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

时间:2013-01-11 15:52:58

标签: windows winapi autoresetevent manualresetevent windows-kernel

Windows允许创建(命名)Event objects

一个事件(Windows中的同步原语)可以是自动重置类型(在这种情况下是could say it's kind of a semaphore),也可以是手动重置类型,在这种情况下,它会一直保持设置,直到有人重置它为止。

现在,从docs CreateEventOpenEventSetEvent等{{3}}开始,一旦事件创建,似乎无法确定,无论是自动重置还是重置。

我处于这种情况,其中一个进程创建一个命名的事件,第二个进程必须对此事件进行操作(它将传递名称,然后打开事件并最终发出信号)。由于事件应始终是手动重置事件,因为整个事情都有意义,我本来希望在第二个过程中添加一个检查,以确保 手动重置事件。有没有办法检查这个?

(是的,在我的情况下,它更像是一个很好的东西,因为如果任何代码创建一个自动重置事件然后将它传递给这个过程,它将是一个错误。但是错误发生了,并且如果我能发现它们就越好。)

2 个答案:

答案 0 :(得分:5)

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

您需要做的第一件事是弄清楚给您的句柄是否是一个事件。你使用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 = GetModuleHandle( L"ntdll.dll" );

auto NtQueryObject = (PFN_NtQueryObject)GetProcAddress( ntdll, "NtQueryObject" );

NTSTATUS result = NtQueryObject(
    eventHandle,
    ObjectTypeInformation,
    buffer,
    length,
    &length );

这将为您提供PUBLIC_OBJECT_TYPE_INFORMATION结构。如果对象实际上是一个事件,则TypeName字段将为“Event”。

接下来,调用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/。请负责任地使用!

答案 1 :(得分:1)

在您的初始WaitForSingleObject( handle, 0 )返回后立即致电WaitForSingleObject。如果返回值为WAIT_TIMEOUT,那么您知道它是自动重置事件,如果它是WAIT_OBJECT_0将被返回并且它是手动重置事件。

这确实依赖于在两次调用之间设置的句柄,因此存在潜在的竞争条件,它不会检测到自动重置事件,但它应该在大多数时间工作。因为这是一个很好的,希望这就够了吗?