Cannot start desktop application from Windows serv

2019-04-29 09:47发布

问题:

HI,

I have C# WCF windows service on Windows 7 logged on as user with admin rights. I am trying to start desktop application after service start. All discussions I found are about windows stations and desktops... I created a separate thread, set thread station and desktop and tried to start desktop application. Code works when I start it from VS2010 using asp.net development server but if it was started from service there are no errors but process was not started. I've tried to start process as different user and tried call of CreateProcessWithLogonW (with setting startInfo.lpDesktop to "winsta0\default"; previously). In both cases I have processId returned but cannot see desktop application. Can somebody help me to see where is a mistake?

public class ExternalProcess
{
    const int READ_CONTROL = 0x20000;
    const int WRITE_DAC = 0x40000;
    const int DESKTOP_WRITEOBJECTS = 0x80;
    const int DESKTOP_READOBJECTS = 0x1;

    private Process extProcess;
    private string sFilePath = "";

    [DllImport("user32.dll")]
    private static extern bool SetThreadDesktop(IntPtr hDesktop);
    [DllImport("user32.dll")]
    static extern IntPtr OpenDesktop(string lpszDesktop, uint dwFlags,bool fInherit, uint dwDesiredAccess);
    [DllImport("user32.dll")]
    private static extern IntPtr GetProcessWindowStation();
    [DllImport("user32.dll")]
    private static extern IntPtr OpenWindowStation(string lpszWinSta, bool fInherit, ACCESS_MASK dwDesiredAccess);
    [DllImport("user32.dll")]
    private static extern IntPtr SetProcessWindowStation(IntPtr hWinsta);

    public bool StartProcess(string filePath)
    {
        sFilePath = filePath;
        Thread t = new Thread(new ThreadStart(Thread_StartProcess));
        t.Start();

        return true;
    }

    private void Thread_StartProcess()
    {
        IntPtr hwinstaSave;
        IntPtr hwinsta, hwinsta2;
        IntPtr hdesk;

        hwinstaSave = GetProcessWindowStation();
            System.Console.WriteLine("GetProcessWindowStation Lasterror= " + Marshal.GetLastWin32Error().ToString());
            System.Console.WriteLine("GetProcessWindowStation hwinstaSave= " + hwinstaSave.ToString());
        //hwinsta = OpenWindowStation("winsta0", false, ACCESS_MASK.GENERIC_EXECUTE | ACCESS_MASK.DESKTOP_CREATEWINDOW | ACCESS_MASK.DESKTOP_CREATEMENU | ACCESS_MASK.DESKTOP_SWITCHDESKTOP | ACCESS_MASK.DESKTOP_WRITEOBJECTS);
        hwinsta = OpenWindowStation("winsta0", false, ACCESS_MASK.WINSTA_ALL_ACCESS); // when call from windows service OpenWindowStation returns 0
            System.Console.WriteLine("OpenWindowStation lasterror = " + Marshal.GetLastWin32Error().ToString());
            System.Console.WriteLine("OpenWindowStation hwinsta= " + hwinsta.ToString());
        hwinsta2 = SetProcessWindowStation(hwinsta);
            System.Console.WriteLine("SetProcessWindowStation lasterror = " + Marshal.GetLastWin32Error().ToString());
            System.Console.WriteLine("SetProcessWindowStation hwinsta2= " + hwinsta2.ToString());
        hdesk = OpenDesktop("default", 0, true, READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS);
            System.Console.WriteLine("OpenDesktop lasterror = " + Marshal.GetLastWin32Error().ToString());
            System.Console.WriteLine("OpenDesktop hdesk= " + hdesk.ToString());
        bool Success = SetThreadDesktop(hdesk);
            System.Console.WriteLine("SetThreadDesktop lasterror = " + Marshal.GetLastWin32Error().ToString());
            System.Console.WriteLine("SetThreadDesktop Success= " + Success.ToString());

        try
        {
            extProcess = new Process();

            extProcess.StartInfo.FileName = sFilePath;
            extProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

            if (extProcess.Start())
                System.Console.WriteLine("Process started ");
            else
                System.Console.WriteLine("Not started!");
        }
        catch (Win32Exception e)
        {
            System.Console.WriteLine("Start {0} failed. Error: " + e.Message);
        }
    }

}

回答1:

Interactive Windows Services received a security-centric makeover in Windows Vista. Services now run in the isolated "Session 0" and can not easily inject windows into interactive user sessions. Your code above will create GUI elements in Session 0, which are not shown on any user's desktop, even with the "Allow service to interact with desktop" checked.

More details on the Windows Services restrictions are in this technical document from Microsoft.



回答2:

Perhapse this helps: http://msdn.microsoft.com/en-us/library/ms683502%28VS.85%29.aspx

hth

Mario



回答3:

The application opens up in different session since windows Vista. Hence you do not see the application open and you are unable to communicate to the application. This may help

Possible to launch a process in a user's session from a service?

Asim



回答4:

I'm in the middle of this right now, I know UltraVNC does this so I would look at the code. I'm not 100% sure of the answer at this moment, when I figure it out i'll update this post.

The gist is that you do a CreateProcessAsUser, the process then might have to do OpenInputDesktop then a SetThreadDesktop, but like I can't get it to work yet.