Bob Moore
Bob Moore

Reputation: 6894

Launching a .Net winforms application interactively from a service

Environment - VS2008, Vista SP1.

I have written a process management service which can launch applications either in session 0 or the interactive console (usually 1). Please note this is NOT the normal mode of operation, it's for in-house debug purposes only. In the field, these processes will be safely hidden away in session 0. Security concerns do not apply.

Clearly people aren't reading this: security concerns do not apply. We have dozens of existing server apps (NOT services) written like this. We're not about to completely revamp these applications, we just need to be able to get at their inbuilt debug dialogs when running release versions in-house. I already know all about the canonical solution and pipes etc. If it was acceptable to add remote interfaces into all these apps, that's what we'd be doing.

I use the following code to do this:

ZeroMemory (&sui, sizeof(STARTUPINFO));
sui.cb = sizeof (STARTUPINFO);
sui.wShowWindow = pTask->GetWinStartState() ;
sui.dwFlags     = STARTF_USESHOWWINDOW ;
ZeroMemory (&pi,sizeof(pi));

if (bInteractive)
{
   HANDLE  hToken = NULL;
   DWORD dwSessionId = WTSGetActiveConsoleSessionId();
   WTSQueryUserToken (dwSessionId, &hToken);
   sui.lpDesktop = TEXT("winsta0\\default"); 
   LPVOID  pEnv = NULL;
   DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
   HMODULE hModu = LoadLibrary(TEXT("Userenv.dll"));

   if (hModu )
   {
      if (CreateEnvironmentBlock (&pEnv, hToken, FALSE))
         dwCreationFlag |= CREATE_UNICODE_ENVIRONMENT;    
      else
         pEnv = NULL;
   }

   bCreatedOk = CreateProcessAsUser (hToken,
                                     NULL,
                                     (LPTSTR)(pTask->GetExeName()),
                                     NULL,
                                     NULL,
                                     FALSE,
                                     dwCreationFlag,
                                     pEnv,
                                     NULL,
                                     &sui,
                                     &pi);
}
else
{
   bCreatedOk = CreateProcess (NULL, ... blah...);
}

This all works fine and I can run and monitor native processes both in the Vista service session and the console. Great. Cakes and ale for everyone.

So here's the problem. If I try to run a winforms (C#) app interactively like this, it appears to run, shows up in Process Explorer as running in session 1, but on the desktop... nada. No window appears at all. The process runs up and shuts down all fine, but no window ever appears. The exact same winform exe run from explorer also shows up in session 1, but this time appears on the desktop just fine.

Any ideas ?

Upvotes: 1

Views: 1780

Answers (3)

Stephen Martin
Stephen Martin

Reputation: 9645

Despite the evident hysteria there is nothing wrong with launching an application from a service into an interactive session provided it is done with the same privileges as the interactive user or lower. Since you are launching as the interactive user there can be no privilege escalation.

What you are doing does work. I suspect that the issue has something to do with your STARTUPINFO struct. You appear to be creating your sui on the stack but you don't show what you are doing with it. Are you initializing it to all 0s, if not you may be getting some garbage from the stack that is causing the window not to show or to show at some co-ordinates off the screen.

Upvotes: 1

Erik Funkenbusch
Erik Funkenbusch

Reputation: 93424

In a word, "don't".

Services typically run with reduced privileges and NOT as the current user. As such, in Vista+ they're not allowed to interact with the users desktop. On top of all that, services get a null Window Station.

You used to be able to check a box that said something like "Allow to interact with the desktop" but not anymore. It's bad practice.

Your best bet is to create a helper app that runs in the users context and communicates with the service via a named pipe, LRPC or a socket, then have your helper app launch the program for the user. This is the way most anti-virus now works.

Also, read this whitepaper from Microsoft on the subject. Services can't run in anything other than session 0.

NOTE: a little research seems to indicate that you need to duplicate the token using something like this:

DuplicateTokenEx(hTokenNew,MAXIMUM_ALLOWED,NULL,
    SecurityIdentification,TokenPrimary,&hTokenDup);

Upvotes: 0

Johan Buret
Johan Buret

Reputation: 2634

It looks as if you're trying to break Session Isolation. Like Mystere Man said, I don't think it's the right thing to do.

http://support.microsoft.com/?scid=kb%3Ben-us%3B165194&x=5&y=3 might be useful if you really want to do this. In the code sample over there, they seem to initialize more thing than you do.


EDIT If it's for debugging purposes, i-e VS 2008 step-in, just add a wait loop at the beginning, and launch VS with administrator rights. You can attach to your service process without encountering system isolation.

Upvotes: 0

Related Questions