iLemming
iLemming

Reputation: 36274

How to get Currently logged user's session ID?

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.

Update 1:

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, and shows that on a different user's desktop. How come?

Update 2:

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", which I don't know how to do it.

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...

Update 3:

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

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.exe 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?

Update 4:

That's it! I got that one!

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

Upvotes: 6

Views: 20314

Answers (4)

Javert93
Javert93

Reputation: 644

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 calling four API's; WTSGEtConsoleSessionId, WTSQueryUserToken, DuplicateTokenEx, then CreateProcessAsUser, and it will work on any machine running WinXP/Win2K3 or higher.

Upvotes: 5

user203570
user203570

Reputation:

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.

Upvotes: 2

Merlyn Morgan-Graham
Merlyn Morgan-Graham

Reputation: 59151

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.

Upvotes: 3

Flesrouy
Flesrouy

Reputation: 684

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.

Upvotes: 1

Related Questions