如何判断Windows内核事件对象是自动重置还是手动重置?

Windows允许创build(命名) 事件对象 。

一个事件(Windows中的同步原语)可以是自动重置types(在这种情况下,你可以说它是一种信号量 ),或者它可以是手动重置types,在这种情况下,它保持设置,直到有人重置它。

现在,从CreateEvent , OpenEvent , SetEvent等文档看来,一旦创build事件,似乎无法确定是自动重置还是重置。

我处于这种情况,一个进程创build一个命名的事件,第二个进程将不得不对这个事件进行操作(它通过名字,然后打开事件并最终发出信号)。 由于事件应该始终是一个手动重置事件的整个事情是有道理的,我希望在第二个过程中添加一个检查,以确保它一个手动重置事件。 有没有办法检查这个?

(是的,在我的情况下更好,因为如果任何代码会创build一个自动重置事件,然后将其传递给这个进程,它将会是一个错误,但是错误会发生,我可以检测到他们)

没有记录的方法来做到这一点,但如果你冒险进入无证的土地其实并不难。 (为了您的目的,这应该没问题,因为它不会真的影响您的程序功能。)

你需要做的第一件事是弄清楚给你的句柄是不是一个事件。 你用这个NtQueryObject。 该功能记录在这里: http : //msdn.microsoft.com/en-us/library/bb432383(v=vs.85).aspx 。 它附带了本地API的通常要求,它可能会在没有通知的情况下消失或更改。 部分例子:

#include <winternl.h> typedef NTSTATUS (NTAPI * PFN_NtQueryObject)( HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength ); HMODULE ntdll = GetmoduleeHandle( L"ntdll.dll" ); auto NtQueryObject = (PFN_NtQueryObject)GetProcAddress( ntdll, "NtQueryObject" ); NTSTATUS result = NtQueryObject( eventHandle, ObjectTypeInformation, buffer, length, &length ); 

这会给你一个PUBLIC_OBJECT_TYPE_INFORMATION结构。 如果对象实际上是一个事件,TypeName字段将是“事件”。

接下来,调用NtQueryEvent来获取事件的类型。 所有这些完全没有记录。

 typedef enum _EVENT_INFORMATION_CLASS { EventBasicInformation } EVENT_INFORMATION_CLASS, *PEVENT_INFORMATION_CLASS; typedef enum _EVENT_TYPE { NotificationEvent, SynchronizationEvent } EVENT_TYPE, *PEVENT_TYPE; typedef struct _EVENT_BASIC_INFORMATION { EVENT_TYPE EventType; LONG EventState; } EVENT_BASIC_INFORMATION, *PEVENT_BASIC_INFORMATION; typedef NTSTATUS (NTAPI * PFN_NtQueryEvent)( HANDLE EventHandle, EVENT_INFORMATION_CLASS EventInformationClass, PVOID EventInformation, ULONG EventInformationLength, PULONG ReturnLength ); auto NtQueryEvent = (PFN_NtQueryEvent)GetProcAddress( ntdll, "NtQueryEvent" ); EVENT_BASIC_INFORMATION info; ULONG length = sizeof( info ); NTSTATUS result = NtQueryEvent( eventHandle, EventBasicInformation, &info, length, &length ); 

现在,只需检查信息中的EventType字段,就完成了。 “NotificationEvent”表示手动重置,“SynchronizationEvent”表示自动重置。

如果你想知道我是如何计算出第二部分的话,我没有。 信息来自这里: http : //undocumented.ntinternals.net/ 。 请使用负责任!

在初始WaitForSingleObject返回后立即调用WaitForSingleObject( handle, 0 ) 。 如果返回值是WAIT_TIMEOUT那么你知道这是一个自动重置事件,如果它是WAIT_OBJECT_0将被返回,这是一个手动重置事件。

这依赖于两个调用之间的句柄,所以有一个潜在的竞争条件,它不会检测到自动重置事件,但它应该大部分时间工作。 因为这是一个很好的,希望这是足够的?