How to determine if a Windows kernel event object is automatic - reset or manual - reset?

Windows allows you to create (called) Event Objects .

An event (synchronization primitive on Windows) can be of the type auto-reset (in this case you could say it is a kind of semaphore ) or it can be of the type manual-reset, in which case it remains set as long as someone won't dump it.

Now, from the docs for CreateEvent , OpenEvent , SetEvent , etc., it seems that there is no way to determine when the event was created, whether it is auto-reset or maual-reset.

I am in a situation where one process creates a named Event, and the second process will have to work on this event (it receives the transmitted name, then opens the event and, in the end, signals about it). Since the event should always be a manually reset event for everything that makes sense, I would like to add a check in the second process to make sure that this event is manually reset. Is there any way to check this?

(And yes, this is more enjoyable in my situation, as it would be a mistake if any code generated an auto-reset event and then passed it to this process. And all the better if I can detect them.)

+4
source share
2 answers

There is no documentary way to do this, but in fact it is not difficult if you go to earth without documents. (For your purposes, this should be good, since it does not affect the functionality of your program.)

The first thing you need to do is find out if the given handle is an event or not. For this you use NtQueryObject. The function is registered here: http://msdn.microsoft.com/en-us/library/bb432383(v=vs.85).aspx . It comes with the usual conditions for its own APIs, which may disappear or change without notice. A partial example:

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

This will give you the PUBLIC_OBJECT_TYPE_INFORMATION structure. The TypeName field will be an "Event" if the object is actually an event.

Then you call NtQueryEvent to get the type of event. All of this is completely undocumented.

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

Now just look at the EventType field in the information and you're done. "NotificationEvent" means manual reset and "SynchronizationEvent" means auto reset.

If you are interested in how I understood this second part, I did not. Information here: http://undocumented.ntinternals.net/ . Please use responsibly!

+4
source

Call WaitForSingleObject( handle, 0 ) immediately after returning the original WaitForSingleObject . If the return value is WAIT_TIMEOUT , then you know that this is an auto-reset event, if it WAIT_OBJECT_0 , and this will be a manual reset event.

This relies on the descriptor being set between two calls, so there is a potential race condition when it does not detect an auto-reset event, but it should work most of the time. How pleasant it is, hopefully enough?

+1
source

All Articles