5

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

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

现在,从CreateEventOpenEventSetEvent等的文档看来,一旦创建了事件,似乎无法确定它是自动重置还是手动重置。

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

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

4

2 回答 2

6

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

你需要做的第一件事是弄清楚给你的句柄是否是一个事件。为此,您使用 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/ 。请负责任地使用!

于 2013-01-11T16:54:27.347 回答
1

在您的姓名返回WaitForSingleObject( handle, 0 )后立即致电。WaitForSingleObject如果返回值是WAIT_TIMEOUT那么你知道它是一个自动重置事件,如果它WAIT_OBJECT_0会被返回并且它是一个手动重置事件。

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

于 2013-01-11T16:11:15.803 回答