Здравствуйте. Я пишу драйвер (уже почти написан) и интерфейсную DLL-ку. Управляющая программа будет общаться с драйвером посредством DLL. Драйвер написан таким образом, что общаться он должен только с одной программой. На управляющую программу я влиять не могу, поэтому делаю так: 1. управляющая программа посылает команду LOGIN (через DeviceIOControl) 2. драйвер запоминает ID-шник этого процесса ?. при получении остальных команд драйвер проверяет ID процесса и игнорирует другие процессы 3. при закрытии приложение посылает команду LOGOFF 4. драйвер сбрасывает ID процесса и готов к работе с другими программами Но если программа закрылась и не послала LOGOFF (например пользователь её убил, или она рухнула ...) драйвер остаётся заблокированным. Возникла такая идея - в драйвере отследить завершение процесса и сбросить запомненный ID. Как отследить завершение процесса ?
Сходил на обед, подумал над задачей... В режиме пользователя я бы передал HANDLE процесса в WaitForSingleObject и ждал бы, пока не сработает Wait. Нашёл в DDK функцию KeWaitForSingleObject, но в качестве объекта она принимает только 'event, mutex, semaphore, thread, or timer' Получается что такой способ не прокатит, или я не прав ?
Попробуй проще - сделай список ID процессов, которые передавали драйверу команду LOGIN и, в дальнейшем, если какой-либо процесс посылает команду дрову - проверять, входит ли он в этот список. В этом случае проблема с завершением процесса отпадает. Или ещё вариант, чуть более сложный. Пусть прога (DLLшка) шифрует передаваемые через DeviceIoControl данные при помощи своего ID. А драйвер - пусть расшифровывает эти данные по ID текущего процесса и проверяет правильность расшифровки по какой-то метке в начале данных, ну в общем идея понятна. А насчёт KeWaitForSingleObject - кто тебе мешает ждать главный поток процесса? Ты же сам написал 'event, mutex, semaphore, thread, or timer'
vasalvit Зачем? Разве нельзя в процессе открыть драйвер и повиснуть на ReadFile/WriteFile, а в драйвере в обработчике обрабатывать закрытие хендла по факту завершения процесса?
По поводу списка ID-шников - не подойдёт. Хочется что бы при завершении процесса драйвер освобождал ресурсы и выгружался. А вот про главный поток процесса - я не подумал Спасибо Буду копать в эту сторону
Да, конечно нужно ждать в отдельном потоке. ИМХО - самый правильный вариант. Два остальных я написал только потому, что сам сначала не заметил, что можно ждать потоки.
KeWaitForSingleObject() без проблем может работать с объектами процессов и потоков (EPROCESS и ETHREAD соответственно), так что если у тебя только один процесс одновременно может открыть твой девайс, тогда это решение предпочтительнее. Если несколько процессов одновременно могут держать хендл твоего девайса, тогда можно слегка модифицировать этот способ: создать по одному системному потоку на управляющий процесс и в каждом ждать на объекте EPROCESS этого процесса. При этом, разумеется, в IRP_MJ_CREATE девайса нужно запихнуть ID процесса в список и создать поток. В любом случае удаление процесса из списка и очистка всех необходимых ресурсов у тебя будет в двух местах - в IRP_MJ_CLOSE и в системном потоке сразу после удачного ожидания (не забудь синхронизацию, например, мутекс). При этом бегать по списку придётся только в случае IRP_MJ_CLOSE, ибо в поток можно передать указатель на LIST_ENTRY в качестве контекста.
А что PsSetCreateProcessNotifyRoutine уже не гламурно ? PsSetCreateProcessNotifyRoutine (ProcessNotify, FALSE); void ProcessNotify (IN HANDLE ParentId, IN HANDLE ProcessId,IN BOOLEAN Create) { if (Create == FALSE && ProcessId == myId) myId = INVALID_HADLE_VALUE; } ?
PsSetCreateProcessNotifyRoutine() - это крайний случай, т.к. их всего может быть установлено 8 штук в системе. Может получится ситуация, когда девятому драйверу не удастся установить нотификатор, что не есть хорошо. Поэтому если есть возможность обойтись без PsSetCreateProcessNotifyRoutine() - лучше использовать эту возможность.
vasalvit скажу тебе секрет: kernel32!WaitForSingleObject -> ntdll!ZwWaitForSingleObject -> nt!NtWaitForSingleObject -> nt!KeWaitForSingleObject так что на всём, на чем может ждать юзермодная функция, может ждать и Ke***. Объект E/KPROCESS Всегда начинается с DISPATCHER_HEADER (по сути тоже самое что и KEVENT, грубо говоря, объект KPROCESS содержит в начале объект KEVENT. только вот тип у него в поле Type не евент, а процесс). Она переходит в сигнальное состояние при завершении процесса. Поэтому никаких проблем. при LOGON: создаешь отдельный поток (PsCreateSystemThread), референсишь себе объект "процесс" (PsLookupProcessByProcessId), ждёшь на нем (KeWaitForSingleObject) без тайм-аута, после этого (значит процесс уже умер) делаешь g_ControlProcessId=0 и ObDereferenceObject(Process) только надо не забыть после завершения KeWaitForSingleObject прочекать, а не приаттачен твой драйвер уже к другому процессу, а то будет грустно. в потоке в локальную переменную придется сохранить ID перед ожиданием и сравнить с глобальным ID после ожидания прежде чем делать LOGOFF
Завершение процесса, который открывает объект устройства драйвера, можно отследить по IRP типа IRP_MJ_CLEANUP. Не зависимо от того, закрылось ли приложение нормально и вызвало CloseHandle или же завершилось аварийно и не закрыло дескриптор устройства, драйвер получит IRP_MJ_CLEANUP.