5

Windowsでは、(名前付きの)イベントオブジェクトを作成できます。

イベント(Windowsの同期プリミティブ)は、自動リセットタイプ(この場合はセマフォの一種と言えます)にすることも、手動リセットタイプにすることもできます。この場合、誰かがリセットするまで設定されたままになります。

さて、CreateEvent、OpenEvent、SetEventなどのドキュメントから、イベント作成れる、それが自動リセットか手動リセットかを判断する方法はないようです。

私は、1つのプロセスが名前付きイベントを作成し、2番目のプロセスがこのイベントを操作する必要がある状況にあります(名前が渡され、イベントを開いて最終的に通知します)。イベントは、すべてが意味をなすために常に手動リセットイベントである必要があるため、手動リセットイベントであることを確認するために、2番目のプロセスにチェックを追加したいと思います。これを確認する方法はありますか?

(はい、私の状況ではもっと便利です。コードが自動リセットイベントを作成し、それをこのプロセスに渡すと、とにかくバグになるからです。しかし、バグは発生します。私はそれらを検出することができます。)

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 );

ここで、info の EventType フィールドを調べるだけで完了です。「NotificationEvent」は手動リセットを意味し、「SynchronizationEvent」は自動リセットを意味します。

私がその 2 番目の部分をどのように考え出したか疑問に思っているなら、私は知りませんでした。情報はhttp://undocumented.ntinternals.net/から得られます。責任を持って使用してください!

于 2013-01-11T16:54:27.347 に答える
1

イニシャルが戻っWaitForSingleObject( handle, 0 )たらすぐに電話してください。WaitForSingleObject戻り値がの場合、WAIT_TIMEOUTそれが自動リセットイベントであることがわかります。戻り値の場合、WAIT_OBJECT_0それは手動リセットイベントです。

これは、2つの呼び出しの間に設定されているハンドルに依存しているため、自動リセットイベントを検出しない潜在的な競合状態がありますが、ほとんどの場合は機能するはずです。持っていて良かったので、うまくいけばそれで十分ですか?

于 2013-01-11T16:11:15.803 に答える