【问题标题】:Cannot start desktop application from Windows service on Windows 7无法在 Windows 7 上从 Windows 服务启动桌面应用程序
【发布时间】:2010-10-01 10:41:16
【问题描述】:

嗨,

我在 Windows 7 上以具有管理员权限的用户身份登录了 C# WCF windows 服务。 我正在尝试在服务启动后启动桌面应用程序。我发现的所有讨论都是关于 windows 站和桌面...我创建了一个单独的线程,设置线程站和桌面并尝试启动桌面应用程序。 当我使用 asp.net 开发服务器从 VS2010 启动它时,代码可以工作,但如果它是从服务启动的,则没有错误但进程没有启动。我尝试以不同的用户身份启动进程并尝试调用 CreateProcessWithLogonW(将 startInfo.lpDesktop 设置为“winsta0\default”;之前)。在这两种情况下,我都返回了 processId,但看不到桌面应用程序。 谁能帮我看看哪里出错了?

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);
        }
    }

}

【问题讨论】:

  • 任何带有完整源代码示例的最终解决方案?

标签: c# windows wcf service


【解决方案1】:

交互式 Windows 服务在 Windows Vista 中进行了以安全为中心的改造。服务现在在隔离的“会话 0”中运行,不能轻易地将窗口注入交互式用户会话。上面的代码将在 Session 0 中创建 GUI 元素,这些元素不会显示在任何用户的桌面上,即使选中了“允许服务与桌面交互”。

有关 Windows 服务限制的更多详细信息,请参见 this technical document from Microsoft

【讨论】:

    【解决方案2】:

    【讨论】:

    • Thx,我已经读过,尝试检查服务中的“允许服务与桌面交互”复选框,更改运行服务的用户...,对于特定用户,该复选框不是无论如何都允许,我尝试在注册表中手动设置它但没有结果...
    • 我更多地指的是这个声明:“重要的服务不能直接与 Windows Vista 中的用户交互。因此,标题为使用交互服务的部分中提到的技术不应在新代码中使用。” - 似乎不再可能让服务直接从 Windows Vista 开始与用户交互(这意味着,我猜是 Vista、7 和 Server 2008!)。它在调试器中工作,因为调试器不是真正的服务!
    • 嗯,是的,我害怕那部分。这意味着必须尝试不同的设计。非常感谢。
    【解决方案3】:

    应用程序在 Windows Vista 之后的不同会话中打开。因此,您看不到应用程序打开并且您无法与应用程序通信。这可能会有所帮助

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

    阿西姆

    【讨论】:

      【解决方案4】:

      我现在正在处理这个问题,我知道 UltraVNC 会这样做,所以我会查看代码。目前我还不能 100% 确定答案,等我知道后我会更新这篇文章。

      要点是您执行 CreateProcessAsUser,然后该进程可能必须执行 OpenInputDesktop,然后执行 SetThreadDesktop,但就像我无法让它工作一样。

      【讨论】:

        猜你喜欢
        • 2011-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-19
        • 2022-01-13
        • 2011-07-01
        • 2011-12-08
        相关资源
        最近更新 更多