Почему нельзя получить дескриптор главного окна для запущенного процесса? - PullRequest
9 голосов
/ 18 января 2011

У меня есть ситуация, когда я запускаю процесс в своем коде для настройки канала IPC.Процесс, который я запускаю, представляет собой приложение MFC без поддержки CLR.Приложение, из которого я запускаю этот процесс, является модулем C # в приложении WPF (хотя я не думаю, что это является следствием моей проблемы).Это работает с версией приложения, которая поддерживает CLR, и работает на всех компьютерах, кроме цели развертывания, компьютера с сенсорным экраном с Windows 7. Но по какой-то причине, когда я пробую это с этим точным сценарием, объект Process никогда не будетразрешает дескриптор главного окна (Process.MainWindowHandle).Есть ли другой (возможно, даже pinvoke) способ сделать это?Это вещь безопасности?Я тот, кто наблюдает за процессом.Дескриптор главного окна процесса существует.Я не вижу, что может быть не так.

Если это поможет, вот мой код.

        _applicationProcess = new Process();
        _applicationProcess.StartInfo.FileName = _strProcessPath;
        _applicationProcess.StartInfo.Arguments = _strProcessArguments;
        _applicationProcess.Start();

        long nTicks = Environment.TickCount;
        if (_applicationProcess.WaitForInputIdle(1 /*minute(s)*/ * 60000))
        {
            try
            {
                do
                {
                    // Don't let total processing take more than 1 minute(s).
                    if (Environment.TickCount > nTicks + 1 /*minute(s)*/ * 60000)
                        throw new ApplicationException("MFCApplication.Startup failed! The main window handle is zero!");

                    _applicationProcess.Refresh();
                }
                while (_applicationProcess.MainWindowHandle.ToInt32() == 0);

                _applicationHandle = new IntPtr(_applicationProcess.MainWindowHandle.ToInt32());
            }
            catch (Exception ex)
            {
                //Do some stuff...
                throw;
            }
        }
        else
        {
            // Do exception handling.
        }

ApplicationException ударил после минуты попытки получить дескриптор главного окна, отличный от нуля.

Ответы [ 4 ]

6 голосов
/ 19 января 2011

Значение, которое вы получаете из Process.MainWindowHandle, к сожалению, является предположением.Для программы нет функции API, которая позволяла бы ей сообщать Windows «это мое главное окно».Используемое правило задокументировано, это первое окно, созданное процессом при его запуске.Это вызывает проблемы, если это первое окно, скажем, окно входа или заставка.

Мало что вы можете с этим поделать, вам нужно больше узнать о том, как программа ведет себя, чтобы найти, что реально главное окно.Перечисление окон с помощью EnumThreadWindows () может помочь вам найти его, если первое окно было создано в том же потоке, что и главное окно.Более сложный EnumWindows () будет необходим, если это не так.

3 голосов
/ 18 января 2011

Моя привычка - вызывать EnumWindows в цикле в сочетании с GetWindowThreadProcessId, чтобы найти дескриптор окна.

C Code, adapt to your language


DWORD TargetHWND;

//...
    while (EnumWindows(EnumWndProc, (LPARAM)(DWORD)pid)) {
        Sleep(100);
    }


//...

BOOL EnumWndProc(HWND hWnd, LPARAM lParam) {
    DWORD pid = (DWORD)-1;
    GetWindowThreadProcessId(hWnd, &pid);
    if (pid == (DWORD)lParam) {
        TargetHWND = hWnd;
        return FALSE;
    }
    return TRUE;
}
2 голосов
/ 28 апреля 2011

Чтобы получить MainWindowHandle с помощью вашего процесса, убедитесь, что ваше приложение WPF отображается на панели задач, т.е. ShowInTaskbar="True", и установите свойство Application.Current.MainWindow в окне, которое вы хотите установить в качестве основного.window.

Если я выполняю приведенный ниже код в главном окне WPF без установки ShowInTaskbar="True", я всегда получаю 0 как MainWindowHandle, потому что мое окно WPF было полноэкранным и не отображалось на панели задач.

    Application.Current.MainWindow = this;
    var Query = System.Diagnostics.Process.GetProcessesByName("ProcessName");

    if (Query.Any())
    {
        Query.FirstOrDefault().Refresh();
        MessageBox.Show(Query.FirstOrDefault().MainWindowHandle.ToInt32().ToString());
    }
1 голос
/ 18 января 2011

Я не знаю, почему это может отличаться, но после создания процесса попробуйте выполнить:

Process[] allProcesses = Process.GetProcessesByName("YourWindowTitle");

и посмотрите, есть ли у какого-либо из возвращенных процессов MainWindowHandle.

...