views:

90

answers:

5

I'm running a process from inside a windows service using

ProcessStartInfo processStartInfo = new ....
Process.Start(processStartInfo);

The problem is, if I run service under local system account, it runs alright, but it doesn't show the programs' window. I've tried to put user credentials in service properties, but then 'Allow service to interact with desktop' checkbox becomes disable.

I really need to run the app calling it from service, and I really need to see the app's window.

Help me please.

UPD. Well, you use overloaded version of Process.Start what takes username, password and domain - it will pull the program to the desktop. But now it starts the app under one credentials but shows that on a different user's desktop. How come?

UPD2: I have an idea! I can use psexec.exe from Sysinternals Suite. But the problem is I need to start that thing silently "as administrator". And I don't know how. I mean even if you're already have admin rights, sometimes you have to manually say "run as administrator", confirm UAC and only after that you're ready to go. I don't know how silently run something without bringing UAC thing....

UPD3: Dear Lord. I've got that thing! Finally.

Ok. In the beginning the problem was indeed in session 0 isolation thing. So I needed to build a middle app that can be started from the service and then, that app in its turn suppose to start my application through RPC and bring it to a desktop. Instead of building middle layer app I decided to use psexec tool (anyway it works exactly the way I need - through RPC). And when I tried to use that tool under LOCAL SYSTEM account it didn't work for some reason. And then I realized - the reason is damn EULA popup dialog that MS put in every single pstool, and it was impossible to click the button to confirm dialog under local system account. So the solution is to create a key in the registry HKU.DEFAULT\Software\Sysinternals\PsExec with DWORD value EulaAccepted = 1

Hooray, now it works! BUT! Now I need to bring the program to the currently logged user's screen. To do that I'm gonna need the session id!

So the question is: How to get currently logged user's session id? And what happens if there's no one logged yet? What session id that would be?

UPD4: That's it! I got that one!

[DllImport("Kernel32.dll", EntryPoint = "WTSGetActiveConsoleSessionId")] public static extern int WTSGetActiveConsoleSessionId();

Thank you guys!

A: 

If you are trying this on anything newer than WindowsXP this will not work. This is because of a new feature introduced in Vista / Windows 7 called Session 0 isolation. http://msdn.microsoft.com/en-us/library/bb756986.aspx You will not be able to get a app launched by a service to show up on the users desktop.

Flesrouy
+1  A: 

One solution would be to have a third process act as an intermediary, and tell it to launch apps via RPC/Named pipes.

Processes:

  • Windows service
  • Intermediary application
  • The app you want to run

The shim creates a communication endpoint (named pipe, WCF endpoint) and listens on it. When it gets a message to go ahead, it launches the app you want to run.

Then, when the Windows service wants to launch an app, it finds and opens the endpoint (named pipe, WCF endpoint), and sends the message to launch the app. Then the intermediary application takes care of the process launching business, and doesn't have any of the limitations that the Windows service has.

Make this intermediary process start with logon, and you're good to go.

This is similar to how the Microsoft test agent/controller work when you need to run tests that interact with the desktop.

Merlyn Morgan-Graham
Ahhhh... Is there any easier solution? I'm trying to start an app with psexec.exe from SysInternals suite. You can provide the session id to it and it will bring the app to the desktop of that user which uses that session.But the problem is that it needs to be started as admin. For example if you even try to run something like that: PsExec.exe -u mydomain\user -p pass123 -i -s 1 "c:\windows\system32\calc.exe"Even if user has administrator rights, that script would work unless you manually say "run as administrator". How can I run something silently as admin without bringing UAC thing?
Ike
A: 

This can be done without an intermediate process, but it requires more than 500 lines of code to do. Basically, you want to launch your second process as the current logged on user. For Vista/7, this user will have their own winlogon process, while for XP, they will have an explorer process. You need to get the primary token, environment block, security attributes, and thread security attributes of that running process then call the Windows API function CreateProcessAsUser with all that information, making sure you select the correct window station as well (usually "WinSta0\Default"). This is all doable, but you might have a better time with the other suggestion of a second process and IPC.

Matthew Ferreira
I tried that, still doesn't bring the window. Damn that 0 isolation stuff...
Ike
A: 

You can get the active console session id using WTSGetActiveConsoleSessionId (from the terminal services API). You can only use it for WinXP/Win2K3 or higher, but that should be fine, as you can hard code 0 for the session id on Win2K or earlier. Here is the PInvoke signature for it:

[DllImport("Kernel32.dll", SetLastError = true)]
[return:MarshalAs(UnmanagedType.U4)]
public static extern int WTSGetActiveConsoleSessionId ( );

As far as launching a process in the user's session, you can refer to the answer I gave here. It basically involves callling four API's; WTSGEtConsoleSessionId, WTSQueryUserToken, DuplicateTokenEx, then CreateProcessAsUser, and it will work on any machine running WinXP/Win2K3 or higher.

Javert93
-1: this answer is already in the question.
John Saunders
Sorry, I realized that I misunderstood the actual question and updated my post to provide a better answer.
Javert93