Почему GetWindowThreadProcessId возвращает 0 при вызове из службы? - PullRequest
3 голосов
/ 17 марта 2010

При использовании следующего класса в консольном приложении и наличии хотя бы одного экземпляра Блокнота, GetWindowThreadProcessId правильно возвращает ненулевой идентификатор потока. Однако, если один и тот же код включен в службу Windows, GetWindowThreadProcessId всегда возвращает 0, и исключений не выдается. Изменение пользователя, под которым запускается служба, таким же, как у пользователя, на котором запущено консольное приложение, не изменило результат. Что заставляет GetWindowThreadProcessId возвращать 0, даже если ему предоставлен действительный hwnd? И почему он работает по-разному в консольном приложении и сервисе? Примечание. Я использую 32-разрядную версию Windows 7 и нацеливаюсь на .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 ]

15 голосов
/ 17 марта 2010

Служба работает в своем собственном сеансе, печально известный сеанс 0 в Vista и Win7. Этот сеанс изолирует сервисы от рабочего стола пользователя, он выполняется в другом сеансе. Специально для предотвращения взаимодействия с пользователем службы, которая обычно работает с очень привилегированной учетной записью (например, LocalSystem). Дыра в безопасности.

Соответственно, служба не может видеть дескрипторы окна, принадлежащие другому сеансу.

Не знаю, зачем вы это делаете, но обычно вам нужна вспомогательная программа, которая представляет пользовательский интерфейс и взаимодействует со службой через механизм IPC, например именованные каналы, сокеты, удаленное взаимодействие .NET или WCF. Если вы используете именованный канал, перед именем канала добавьте "Global\", чтобы все сеансы могли его видеть.

1 голос
/ 17 марта 2010

Вы также можете включить опцию «Разрешить сервису взаимодействовать с рабочим столом» и посмотреть, работает ли он. В противном случае я бы согласился с комментарием onbugz выше.

0 голосов
/ 17 марта 2010

Служба Windows не имеет пользовательского интерфейса, поэтому у нее нет окна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...