开发者

Why does GetWindowThreadProcessId return 0 when called from a service?

When using the following class in a console application, and having at least one instance of Notepad running, GetWindowThreadProcessId correctly returns a non-zero thread id. However, if the same code is included in a Windows Service, GetWindowThreadProcessId always returns 0 and no exceptions are thrown. Changing the user the service launches under to be the same as the one running the console application didn't alter the result. What causes GetWindowThreadProcessId to return 0 even if it is provided with a valid hwnd? And why does it function differently in the console application and the service? Note: I am running Windows 7 32-bit and targeting .NET 3.5.

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

    public void AttachToNotepad()
    {
        var processesT开发者_如何学编程oAttachTo = Process.GetProcessesByName("Notepad")

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

            ....
        }
    }
}

Console Code:

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

        testClass.AttachToNotepad();
    }
}

Service Code:

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()
    {
        ...
    }
}


A service runs in its own session, the infamous session 0 in Vista and Win7. That session isolates services from the user desktop, it runs in another session. Specifically to prevent a service that usually runs with a very privileged account (like LocalSystem) from interacting with the user. A security hole.

Accordingly, a service cannot see the window handles owned by another session.

Not sure why you are doing this but you typically need a helper program that presents a user interface and communicates with the service through an IPC mechanism like named pipes, sockets, .NET remoting or WCF. If you use a named pipe, prefix the pipe name with "Global\" so all sessions can see it.


You could also enable the option "Allow service to interact with desktop" and see if that works. Otherwise I would have to agree with onbugz comment above.


A Windows Service has no UI, so it has no window.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜