为什么GetWindowThreadProcessId从服务调用时返回0?

时间:2010-03-17 09:46:01

标签: c# winapi pinvoke

在控制台应用程序中使用以下类,并且至少有一个Notepad实例正在运行时,GetWindowThreadProcessId会正确返回非零线程ID。但是,如果Windows服务中包含相同的代码,GetWindowThreadProcessId始终返回0并且不会抛出任何异常。将服务启动的用户更改为与运行控制台应用程序的用户相同,不会改变结果。导致GetWindowThreadProcessId返回0的原因是什么,即使它提供了有效的hwnd?为什么它在控制台应用程序和服务中的功能不同?注意:我正在运行Windows 7 32位并以.NET 3.5为目标。

public class TestClass
{
    [DllImport("user32.dll")]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

    public void AttachToNotepad()
    {
        var processesToAttachTo = Process.GetProcessesByName("Notepad")

        foreach (var process in processesToAttachTo)
        {
            var threadID = GetWindowThreadProcessId(process.MainWindowHandle, 
                IntPtr.Zero);

            ....
        }
    }
}

控制台代码:

class Program
{
    static void Main(string[] args)
    {
        var testClass = new TestClass();

        testClass.AttachToNotepad();
    }
}

服务代码:

public class TestService : ServiceBase
{
    private TestClass testClass = new TestClass();

    static void Main()
    {
        ServiceBase.Run(new TestService());
    }

    protected override void OnStart(string[] args)
    {
        testClass.AttachToNotepad();

        base.OnStart(args);
    }

    protected override void OnStop()
    {
        ...
    }
}

3 个答案:

答案 0 :(得分:15)

服务在自己的会话中运行,Vista和Win7中臭名昭着的会话0。该会话将服务与用户桌面隔离,它在另一个会话中运行。特别是为了防止通常使用特权帐户(如LocalSystem)运行的服务与用户进行交互。安全漏洞。

因此,服务无法看到另一个会话所拥有的窗口句柄。

不确定为什么要这样做,但是您通常需要一个帮助程序,它提供用户界面并通过IPC机制(如命名管道,套接字,.NET远程处理或WCF)与服务进行通信。如果使用命名管道,请在管道名称前加"Global\",以便所有会话都能看到它。

答案 1 :(得分:1)

您还可以启用“允许服务与桌面交互”选项,看看是否有效。否则我将不得不同意上面的onbugz评论。

答案 2 :(得分:0)

Windows服务没有用户界面,因此没有窗口。