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



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

Event (Windows中的同步原语)可以是类型为auto-reset的(在这种情况下,你可以说它是一种信号量),也可以是类型为manual-reset的,在这种情况下,它保持设置,直到有人重置它。

现在,从文档CreateEvent, OpenEvent, SetEvent等,似乎没有办法确定,一旦事件已经创建,是否自动复位或手动复位。

我在这种情况下,一个进程创建了一个命名的事件,第二个进程将不得不对这个事件进行操作(它获得了名称,然后将打开事件并最终发出信号)。由于事件应该始终是手动重置事件,因此我希望在第二个过程中添加一个检查,以确保它手动重置事件。有什么办法检查这个吗?

(是的,它在我的情况下更有好处,因为如果任何代码将创建一个自动重置事件,然后将其传递给此进程,无论如何都会是一个bug。)但是bug是会发生的,如果我能检测到它们就更好了。

没有文档规定的方法来做到这一点,但如果您冒险进入文档规定的领域,实际上并不难。(对于您的目的,这应该是好的,因为它不会真正影响您的程序的功能。)

你需要做的第一件事是弄清楚给你的句柄是否是一个事件。为此使用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 );

现在,只需检查info中的EventType字段,就完成了。"NotificationEvent"为手动复位,"SynchronizationEvent"为自动复位。

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

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

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

相关内容

  • 没有找到相关文章

最新更新