locked
Print documents (*.rtf, *.pdf, etc) using the printto verb from inside a Windows Service RRS feed

  • Question

  • Hello,

     

    I have a large complex application which runs inside a service.  The service is currently set to use the "Local System" special account, though I'd prefer to eventually use "Local Service" so that I can remain compatible in Vista. 

     

    Part of this application involves printing documents of varied file types, including RTF, PDF and HTML documents.  At the moment I'm attempting to do so in a generic manner by creating a process with System.Diagnostics.Process and pass in the file name and the "printto" verb.  Everything seems to work perfectly when I run it directly as an application, but as soon as I run it inside a service, the launched processes encounter problems that I can't seem to figure out.  Here's the code that creates the process itself.

     

    pNewProcess = new Process();

    pNewProcess.StartInfo.FileName = sDocName;

    pNewProcess.StartInfo.Verb = "printto";

    pNewProcess.StartInfo.CreateNoWindow = true;

    pNewProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

    pNewProcess.StartInfo.Arguments = "\"" + sPrinter + "\"";

    pNewProcess.StartInfo.UseShellExecute = true;

    pNewProcess.StartInfo.WorkingDirectory = sDocPath;

    pNewProcess.Start();

     

    I know that it isn't considered a great idea to do anything that might show a UI from inside a service, but I don't know any other way to provide generic printing of a variety of file types.  The behaviour I encounter is basically the process is created and started but just hangs there doing nothing.  I suspect its encountering an error.

     

    Is there a way to get this working like I need, or do I need to rethink how I'm printing documents?  Unfortunately the printing is a hard requirement, as well as the service, so I need to figure out a way to get all this working together.  Thanks.

     

    Kristofor

    Tuesday, December 18, 2007 9:31 PM

All replies

  • Hi Kritofor,

     

    The code you used is a shell feature, which leverages the CreateProcess API to invoke certain command lines in "printto" registry key. This technology is clearly documented in the link below:

    http://msdn2.microsoft.com/en-us/library/bb776883.aspx

     

    The problem of using this technology under Windows Service is that different account has different view of profile, which includes installed printers list etc.. So the printers installed in the interactive logon session will become invisible to your Windows Service process. This caused your failure.

     

    For example, you may run notepad.exe ->File->Print to see the list of installed printers. Then, you may use sysinternals Psexec tool to run notepad under Local System account like below:

    psexec -s -i -d c:\windows\notepad.exe

     

    From File->Print, you will see different list of installed printers. You may download Psexec tool from the link below:

    http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx

     

    Regarding this issue, the recommended solution is writting a GUI client application which runs in the interactive logon session. Then, the Service can use certain IPC to notify the GUI client to do the print job.

     

    Thanks.

     

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

     

    Thursday, December 20, 2007 2:47 AM
  •  

    Hi Jeffrey,

     

    Thank you for the information, I had surmised something similar was going on.  Unfortunately, I can't rely on a client application running in the interactive session, the application I'm working on needs to be completely automated.  The reason I'm using a service is specifically so that a user is not required to be logged on, otherwise I would just run it as a normal application in the interactive session.

     

    A previous version of this application, written in Delphi 7, accomplished this goal so I know its possible.  Do you know if using impersonation would solve the problem of varying printer install lists?  I thought I was using the impersonation stuff correctly, but perhaps I'm not.  When I run the service, the process shows up in the task manager as Local System even after I start impersonation, but when I use Environment.UserName from inside the code itself, it reports the correct profile names...

     

    Do you have any other suggestions on a way to accomplish what I'm looking to do without relying on user interaction?  I don't mind handling it differently, but the requirement of printing varying file types precludes me attempting to build the document myself and use the PrintDocument stuff.

     

    In a related question, is there some way to check for the existance of a network (or local) printer before I try and use it.  For example, something similar to File.Exists("path").

     

    edit: One last thing to note, I'm attempting to use UNC paths to the printers themselves.  I don't know if that changes anything or not.

     

    Kristofor

    Thursday, December 20, 2007 3:16 PM
  • Hi,

     

    Just to add more information, I ran through the relevant section in debug and my impersonation seems to be working correctly.  I tried what you suggested about running with psexec to check the installed printers and you were correct, the list was different than when I log on interactively, however when I build a similar list from inside my service after impersonating my user account, the list I retrieve is identical to what I would expect.

     

    Based on this information, I have to assume that the printer path being supplied to the printto verb is correct, and its hanging on something else.

     

    Also, I ran a check by giving the service the ability to interact with the desktop and printing RTF's worked as expected in this case, though trying to use Adobe Reader to print a pdf still failed with some unexpected print failure.  I'm not sure if checking that box in the service changes profiles or authorities or anything, but there you go for what its worth.

     

    Kristofor

    Thursday, December 20, 2007 5:27 PM
  • Hi Kristofor ,


    Thanks for your feedback.

     

    Based on your further inforamtion, it seems that you have added the printers under the service account and you can access these printers now. Then, I would suspect the problem is that your service account can not access the printing files on remote shares.

     

    The network share folders are handled by the Windows Lan session manager. And the LAN session is account wide instead of machine wide. So your service account will see different mapping of UNC paths as the interactive account. To workaround this problem, you may invoke "net use" command to re-establish the LAN session in service process or call the Win32 NetUseAdd API directly. I provided some sample code in the link below:

    http://groups.google.co.uk/group/microsoft.public.platformsdk.security/msg/063d7b08b29e5642

     

    Hope this helps.

     

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

     

     

    Friday, December 21, 2007 8:31 AM
  • Hi Jeffrey,

     

    Sorry I was having troubles getting on the forums today... 

     

    Anyway, I'm sorry to say that all the files I'm attempting to print from the service are stored on the local computer in the "C:\Documents and Settings\All Users\Application Data" folder.  I am under the assumption that this folder should be accessible to all user accounts.  Please correct me if I'm wrong.

     

    Thank you for the information, as it might be relevant in the future if I try and access the network, but at the moment I'm trying to just get local things to work.

     

    Regards,

     

    Kristofor Wilson

     

     

    Friday, December 21, 2007 11:54 PM
  • Hi Kristofor,

     

    Sorry, with the current information available and due to the nature of the forum discussion, it is hard to identify the root cause with guess. I think you'd better contact the Microsoft CSS for a case support.

     

    Then, they may help you to find out the root cause. Thanks.

     

    Jeffrey

     

    Monday, December 24, 2007 8:27 AM
  • Thanks for your help Jeffrey,

     

    I'll pursue this directly wiht Microsoft CSS if I need to.

     

    Regards,

     

      Kristofor Wilson

    Monday, December 24, 2007 7:05 PM
  •  Jeffrey Tan - MSFT wrote:

    Hi Kritofor,

     

    The code you used is a shell feature, which leverages the CreateProcess API to invoke certain command lines in "printto" registry key. This technology is clearly documented in the link below:

    http://msdn2.microsoft.com/en-us/library/bb776883.aspx

     

     

     

    Jeffrey, I have a question for you. I's been haunting me for weeks now. What is the File Association for iso (image files)?

     

    Thanks in advance

    Tuesday, December 25, 2007 12:35 AM
  •  Kristofor wrote:

    Thanks for your help Jeffrey,

     

    I'll pursue this directly wiht Microsoft CSS if I need to.

     

    Regards,

     

      Kristofor Wilson

     

    I want to offer a few suggestions that may be helpful provided that your OS is Vista higher than Home Premium.

     

    You run lusrmgr.msc at Command Prompt to get to Local Users and Groups GUI. See if your Service is among the groups. if not you may try to add it. You may also try to add the service to the Users and then the service as a User to the Group Administrator. This may solve all your problems at once. Play with it.

     

    Another avenue is to find your folder that causes you troubles. I understand it is under Users\userName\... etc. Right Click on the folder in question, Properties, Tab Security ==> Edit==> Add. You will get a window. Add Your Service to the users. This folder already has Administrator with full rights and System with full rights already preset as default. Make sure you checked "Full Rights" (for your service) at edit time and say "Apply."

     

    If you do not give a damn about this folder security, the first half of the above is not needed. Just add user Users (a group) to the users in that widnow and give full rights to the users that is to EVERYONE.

     

    I am pretty certain this will be the end of your trouble.

     

    It appears your UAC does not recognize your Service as worthy of getting an access to this folder. Somehow your app running locally not under the service gets an access because perhaps it gets administrator's rights or something. Or if you developed it in VS2005 and the latter has access rights to local folders this will be passed on to your app if it is not yet released.  It is hard for me to explain it clearly. I more or less understand it intuitively.

     

    And yet another avenue is to go to Computer Services GUI, find your service and give it massively full rights via Right click, Properties, etc.

    Tuesday, December 25, 2007 1:06 AM
  • Thanks for your help Jeffrey,

     

    I'll pursue this directly wiht Microsoft CSS if I need to.

     

    Regards,

     

      Kristofor Wilson


    Hi Kristofor,

    I am facing exactly similar problem like yours and have not been able to find a solution yet. Please let me know if you have been able to solve your issue.

    Any help would be highly appreciated.

    -Sumit

    [Please do not forget to mark as answer for a correct reply.]
    Wednesday, July 22, 2009 5:27 AM