.net – How to start a process from windows service into currently logged in user’s session

netwindows-services

I need to start a program from Windows Service. That program is a user UI application. Moreover that application should be started under specific user account.

The problem is that a Window Services run in session #0, but a logged in user sessions are 1,2 etc.

So the question is: how to start a process from a window service in such a way that it run in currently logged in user's session?

I'd emphasis on that the question is not about how to start a process under specific account (it's obvious – Process.Start(new ProcessStartInfo("..") { UserName=..,Password=..})). Even if I install my windows to run under current user account the service will run in session #0 anyway.
Setting "Allow service to interact with desktop" doesn't help.

My windows service is .net-based.

UPDATE:
first of all, .NET has nothing to do here, it's actually pure Win32 thing.
Here's what I'm doing. The following code is in my windows service (C# using win32 function via P/Inkove, I skipped import signatures, they're all here – http://www.pinvoke.net/default.aspx/advapi32/CreateProcessWithLogonW.html):

    var startupInfo = new StartupInfo()
        {
            lpDesktop = "WinSta0\\Default",
            cb = Marshal.SizeOf(typeof(StartupInfo)),
        };
    var processInfo = new ProcessInformation();
    string command = @"c:\windows\Notepad.exe";
    string user = "Administrator";
    string password = "password";
    string currentDirectory = System.IO.Directory.GetCurrentDirectory();
    try
    {
        bool bRes = CreateProcessWithLogonW(user, null, password, 0,
            command, command, 0,
            Convert.ToUInt32(0),
            currentDirectory, ref startupInfo, out processInfo);
        if (!bRes)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    }
    catch (Exception ex)
    {
        writeToEventLog(ex);
        return;
    }
    WaitForSingleObject(processInfo.hProcess, Convert.ToUInt32(0xFFFFFFF));
    UInt32 exitCode = Convert.ToUInt32(123456);
    GetExitCodeProcess(processInfo.hProcess, ref exitCode);
    writeToEventLog("Notepad has been started by WatchdogService. Exitcode: " + exitCode);

    CloseHandle(processInfo.hProcess);
    CloseHandle(processInfo.hThread);

The code goes to the line "Notepad has been started by WatchdogService. Exitcode: " + exitCode. Exitcode is 3221225794.
And there's no any new notepad started.
Where am I wrong?

Best Answer

The problem with Shrike's answer is that it does not work with a user connected over RDP.
Here is my solution, which properly determines the current user's session before creating the process. It has been tested to work on XP and 7.

https://github.com/murrayju/CreateProcessAsUser

Everything you need is wrapped up into a single .NET class with a static method:

public static bool StartProcessAsCurrentUser(string appPath, string cmdLine, string workDir, bool visible)