2015-09-22 2 views
1

У меня есть программа (работает как фоновый процесс), в которой я установил крючок для захвата событий EVENT_SYSTEM_FOREGROUND (т. Е. Когда пользователь переключается между окнами). Обратный вызов, который зарегистрирован для крючка, в основном регистрирует, какое приложение (процесс exe filename) пользователь переключил с и который они переключили на.Win32 C++ OpenProceess должен возвращать значение null, если пользователь вышел из приложения, но не так ли?

Я хочу добавить код, чтобы проверить, включено ли приложение, которое они переключали из (если мы не предполагаем, что они его закрыли, и это то, что внесло на передний план новое окно). Я проверяю на это существование, пытаясь создать дескриптор предыдущего PID, используя OpenProcess

//Check prev pid still exists - if not, assume the previous app has been closed 
    HANDLE hPrevProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,false,g_prevPid); 
    if (hPrevProc==NULL){ 
     prevProcStillRunning=false; 
    } 
    else{ 
     CloseHandle(hPrevProc); 
    } 

Предположения с указанным кодом:
g_prevPid заселен с PID - Я проверил это
prevProcStillRunning инициализирован to true

Проблема с приведенным выше кодом заключается в том, что по какой-либо причине, даже когда пользователь вышел из приложения (например, notepad.exe). В течение 10 секунд после их выхода этот тест все равно проходит (т.е. - hPrevProc получает инициализацию). Несмотря на то, что в диспетчере задач я вижу, что процесс Notepad.exe распался (и да, у меня только один экземпляр его открыт), так или иначе, строка OpenProcess все равно может получить дескриптор этого PID. Я предполагаю, что как-то PID на самом деле все еще существует, но может быть в состоянии, когда его завершение. Я обнаружил, что если этот код вызывается еще несколько раз, в конце концов он вернет null.

Я хотел бы найти лучший способ проверить, является ли hPrevProc еще активным. Я попытался проверить это, используя функцию GetExitCodeProcess, но это, похоже, просто дает мне PID, и я даже не уверен, что это правильный подход в любом случае.

Любая помощь приветствуется.

+0

Точный момент времени, когда последний дескриптор объекта ядра закрыт и, следовательно, приводит к сбою OpenProcess(), весьма непредсказуем , Типичное зараженное вредоносным ПО, которое программисты, добровольно устанавливающие на своем компьютере, может сохранить его дольше, чем ожидалось. –

+0

Процессы зомби имеют идентификатор, даже если они завершены. Используйте 'WaitForSingleObject' с таймаутом 0, чтобы узнать, завершился ли процесс. –

ответ

1

Возможно, какой-то процесс (возможно, ваш?) По-прежнему содержит действительный дескриптор этого процесса. Пока CloseHandle не был вызван на все ручки, система поддерживает внутреннюю запись, которая позволяет получить доступ к своим данным процесса. Это важно, потому что, как вы говорите, должно быть возможно вызвать GetExitCodeProcess в закрытом процессе, также кто-то может ожидать, что он остановится с WaitForSingleObject.

Также будьте осторожны с PID, их можно использовать повторно, поэтому теоретически вы можете вызвать OpenProcess на какой-либо другой недавно открытый процесс.

Что касается проверки, если данный процесс не является зомби, вы можете попробовать перечислить окна верхнего уровня с помощью EnumWindows и проверить, связан ли какой-либо из них с данным PID (для получения PID окна используйте GetWindowThreadProcessID).

1

Процесс существует в системе после того, как он завершается, по крайней мере, пока есть открытая ручка.

Единственный надежный способ знать, является ли процесс все еще активен в:

  • убедитесь, что процесс не может выйти с кодом STILL_ACTIVE (259)
  • пытаются открыть процесс (OpenProcess) - > если вы не можете, завершается
  • читать код процесса выхода (GetExitCodeProcess) -> если это не STILL_ACTIVE, процесс завершается.

Вы код мог бы стать:

//Check prev pid still exists - if not, assume the previous app has been closed 
HANDLE hPrevProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,false,g_prevPid); 
if (hPrevProc==NULL){ 
    prevProcStillRunning=false; 
} 
else{ 
    DWORD cr; 
    if ((GetExitCodeProcess(hPrevProc, &cr) == 0) || (cr != STILL_ACTIVE)) { 
     prevProcStillRunning=false; 
    } 
    CloseHandle(hPrevProc); 
} 

Во всяком случае, закрытие приложения с графическим интерфейсом включает в себя различные этапы:

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

событие будет отправлено как только основное окно будет закрыто, что может произойти некоторое время до того, как приложение фактически остановится. Хорошим примером для этого является Firefox. Если вы закроете окно и сразу же попытаетесь запустить новый процесс, вы получите сообщение об ошибке, потому что даже если пользовательский интерфейс ушел, процесс не прекращается. Хуже всего то, что вы можете найти приложения, которые просто заходят в фон при закрытии пользовательского интерфейса и позволяют пользователю снова открывать интерфейс после действия над значком в области состояния панели задач (Shell_NotifyIcon и его обратном вызове). Это распространено для служб другого приложения, работающих в фоновом режиме (сетевые серверы, брандмауэры и т. Д.). В этом случае пользовательский интерфейс не работает, но процесс не завершится.

TL/DR: время между нарушением пользовательского интерфейса и завершением процесса, имеющим его значение, является переменной и зависит от загрузки системы и фоновой активности процесса после закрытия пользовательского интерфейса. Вы можете попытаться использовать задержку для этого, но я ничего не могу гарантировать об этом ...

+0

Спасибо за это предложение Серж, я попробовал код, который вы выложили выше, но опять же, если тест в выражении «if» запускается, когда новое окно попадает в фокус, оно получит «STILL_ACTIVE» - снова проверено через 1 секунду, и это вернет другое значение, указывающее, что процесс больше не существует. – Tommy

+0

@ Томми: Боюсь, я не могу сделать здесь намного лучше. См. Мое редактирование для объяснения - не для решения :-( –

Смежные вопросы