Как определить, когда порожденный процесс готов? (Используя CreateProcess() и FindWindow())

Это должно быть легко: я создаю программу, которая порождает процесс, используя функцию win32 CreateProcess(). Как только этот процесс загружен, я нахожу его окно с помощью FindWindow и отправляю ему сообщения с помощью SendMessage(). Вопрос в том, как я узнаю, что это окно готово принимать сообщения?

Рассмотрим следующее:

HWND wnd;

BOOL Start()
{
  // Spawn the process
  if (! CreateProcess(...))
    return FALSE;

  // Find the process's window (class and name already known)
  wnd = FindWindow(MY_WINDOW_CLASS, MY_WINDOW_NAME);

  // Always returns FALSE because window has not yet been created.
  return (wnd != NULL);
}

Приведенный выше код будет (почти?) всегда терпеть неудачу; окно не может быть создано и найдено так быстро. Если я поставлю ожидание потока, скажем, Sleep(1000), между вызовами CreateProcess и FindWindow, он будет работать нормально. Но это похоже на очень плохой взлом.

Как я могу улучшить это?


person Courtney Christensen    schedule 05.11.2010    source источник


Ответы (4)


(Изменить): Пользователь IInspectable указал на проблемы с WaitForInputIdle() и предложил CBT Hooks.

(...) функция обратного вызова, используемая с SetWindowsHookEx. Система вызывает эту функцию перед активацией, созданием, (...) окном; (... много других вещей).

Кроме того, CBT по какой-то причине является сокращением от компьютерного обучения.

(Старый, будьте осторожны, смотрите комментарии.) Вы ищете WaitForInputIdle(). Цитировать:

Когда родительский процесс создает дочерний процесс, функция CreateProcess возвращает значение, не дожидаясь, пока дочерний процесс завершит свою инициализацию. Прежде чем пытаться взаимодействовать с дочерним процессом, родительский процесс может использовать функцию WaitForInputIdle, чтобы определить, когда инициализация дочернего процесса завершена.

person gimpf    schedule 05.11.2010
comment
Windows API настолько огромен, что никто не может ожидать знания всего. Сегодня узнал кое-что новое, спасибо. - person Mark Ransom; 05.11.2010
comment
Это ошибка, ожидающая своего появления. WaitForInputIdle был изобретен для удовлетворения требований DDE. Использование его для чего-либо еще обречено на неудачу, причем самым тонким образом. Соответствующее чтение: WaitForInputIdle действительно следует называть WaitForProcessStartupComplete и < a href="https://blogs.msdn.microsoft.com/oldnewthing/20100326-00/?p=14483" rel="nofollow noreferrer">WaitForInputIdle ожидает любой поток, который может быть не тем потоком, который вам нужен< /а>. - person IInspectable; 20.12.2015
comment
Спасибо, что обратили мое внимание на эти две статьи из The Old New Thing; история, как всегда, сложнее, чем может показаться сначала, и этот блог — настоящая сокровищница. Однако я не согласен с тем, что WaitForInputIdle() нельзя использовать в этом контексте; метод возвращается, когда все потоки бездействуют одновременно в первый раз (в основном достаточно хорошо для Q), и обработка FindWindow() == null остается необходимой даже при использовании явной синхронизации с использованием именованного события (или аналогичного). К сожалению, я также не знаю лучшего метода, кроме зацикливания в аду. - person gimpf; 21.12.2015
comment
@gimpf: метод возвращается, когда все потоки бездействуют одновременно в первый раз - это не то, о чем говорится в статье в блоге. Функция возвращает значение, как только один поток в целевом процессе достигает точки, в которой он может обрабатывать сообщения. Это может быть поток, отображающий заставку, или фоновый рабочий поток. WaitForInputIdle определенно недостаточно хорош для этого конкретного сценария. Крюк CBT был бы чистым решением заданного вопроса. Нет необходимости в опросе; обратный вызов вызывается при создании окна. - person IInspectable; 02.01.2016
comment
@IInspectable Спасибо за терпеливые исправления. Я перечитал, и да, это любой тред, а не все. Я не знал о крючке CBT, он кажется работоспособным решением без модификации целевого приложения. Я добавляю ссылку на это. - person gimpf; 05.01.2016
comment
Вместо использования SetWindowsHookEx() с хуком WH_CBT вы можете использовать SetWinEventHook() для обработки событий EVENT_OBJECT_CREATE и/или EVENT_OBJECT_SHOW. Даже в документации к хукам предлагается использовать WinEvents вместо хуков. когда возможно. - person Remy Lebeau; 15.07.2016

Вы смотрели WaitForInputIdle?

person Chris    schedule 05.11.2010
comment
У меня есть. Это определенно не то, что вы хотели бы использовать. - person IInspectable; 14.10.2016

Если процесс, который вы запускаете, можно изменить, попросите его отправить сообщение родительскому процессу, когда он будет готов. Вы можете передать HWND родителя в качестве параметра командной строки или использовать FindWindow, если вы можете гарантировать, что родитель будет уникальным.

person Mark Ransom    schedule 05.11.2010

Я предполагаю, что исходный код обоих процессов находится под вашим контролем.

  • Вы можете позволить второму процессу отправить сообщение первому, когда оно будет готово, если второму известны необходимые детали окна сообщений первого процесса.
  • Или вы можете дождаться в первом процессе согласованного именованного объекта синхронизации, такого как событие или мьютекс, установленного вторым процессом.
person Johann Gerell    schedule 05.11.2010