Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928/* * PROJECT: ReactOS Win32 Base API * LICENSE: GPL - See COPYING in the top level directory * FILE: dll/win32/kernel32/client/synch.c * PURPOSE: Wrappers for the NT Wait Implementation * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */
/* INCLUDES *****************************************************************/#include <k32.h>
#define NDEBUG#include <debug.h>
#undef InterlockedIncrement#undef InterlockedDecrement#undef InterlockedExchange#undef InterlockedExchangeAdd#undef InterlockedCompareExchange
/* FUNCTIONS *****************************************************************/
/* * @implemented */LONGWINAPIInterlockedIncrement(IN OUT LONG volatile *lpAddend){ return _InterlockedIncrement(lpAddend);}
/* * @implemented */LONGWINAPIInterlockedDecrement(IN OUT LONG volatile *lpAddend){ return _InterlockedDecrement(lpAddend);}
/* * @implemented */LONGWINAPIInterlockedExchange(IN OUT LONG volatile *Target, IN LONG Value){ return _InterlockedExchange(Target, Value);}
/* * @implemented */LONGWINAPIInterlockedExchangeAdd(IN OUT LONG volatile *Addend, IN LONG Value){ return _InterlockedExchangeAdd(Addend, Value);}
/* * @implemented */LONGWINAPIInterlockedCompareExchange(IN OUT LONG volatile *Destination, IN LONG Exchange, IN LONG Comperand){ return _InterlockedCompareExchange(Destination, Exchange, Comperand);}
/* * @implemented */DWORDWINAPIWaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds){ /* Call the extended API */ return WaitForSingleObjectEx(hHandle, dwMilliseconds, FALSE);}
/* * @implemented */DWORDWINAPIWaitForSingleObjectEx(IN HANDLE hHandle, IN DWORD dwMilliseconds, IN BOOL bAlertable){ PLARGE_INTEGER TimePtr; LARGE_INTEGER Time; NTSTATUS Status; RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
/* APCs must execute with the default activation context */ if (bAlertable) { /* Setup the frame */ RtlZeroMemory(&ActCtx, sizeof(ActCtx)); ActCtx.Size = sizeof(ActCtx); ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; RtlActivateActivationContextUnsafeFast(&ActCtx, NULL); }
/* Get real handle */ hHandle = TranslateStdHandle(hHandle);
/* Check for console handle */ if ((IsConsoleHandle(hHandle)) && (VerifyConsoleIoHandle(hHandle))) { /* Get the real wait handle */ hHandle = GetConsoleInputWaitHandle(); }
/* Convert the timeout */ TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds);
/* Start wait loop */ do { /* Do the wait */ Status = NtWaitForSingleObject(hHandle, (BOOLEAN)bAlertable, TimePtr); if (!NT_SUCCESS(Status)) { /* The wait failed */ BaseSetLastNTError(Status); Status = WAIT_FAILED; } } while ((Status == STATUS_ALERTED) && (bAlertable));
/* Cleanup the activation context */ if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
/* Return wait status */ return Status;}
/* * @implemented */DWORDWINAPIWaitForMultipleObjects(IN DWORD nCount, IN CONST HANDLE *lpHandles, IN BOOL bWaitAll, IN DWORD dwMilliseconds){ /* Call the extended API */ return WaitForMultipleObjectsEx(nCount, lpHandles, bWaitAll, dwMilliseconds, FALSE);}
/* * @implemented */DWORDWINAPIWaitForMultipleObjectsEx(IN DWORD nCount, IN CONST HANDLE *lpHandles, IN BOOL bWaitAll, IN DWORD dwMilliseconds, IN BOOL bAlertable){ PLARGE_INTEGER TimePtr; LARGE_INTEGER Time; PHANDLE HandleBuffer; HANDLE Handle[8]; DWORD i; NTSTATUS Status; RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
/* APCs must execute with the default activation context */ if (bAlertable) { /* Setup the frame */ RtlZeroMemory(&ActCtx, sizeof(ActCtx)); ActCtx.Size = sizeof(ActCtx); ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; RtlActivateActivationContextUnsafeFast(&ActCtx, NULL); }
/* Check if we have more handles then we locally optimize */ if (nCount > 8) { /* Allocate a buffer for them */ HandleBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nCount * sizeof(HANDLE)); if (!HandleBuffer) { /* No buffer, fail the wait */ SetLastError(ERROR_NOT_ENOUGH_MEMORY); if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx); return WAIT_FAILED; } } else { /* Otherwise, use our local buffer */ HandleBuffer = Handle; }
/* Copy the handles into our buffer and loop them all */ RtlCopyMemory(HandleBuffer, (LPVOID)lpHandles, nCount * sizeof(HANDLE)); for (i = 0; i < nCount; i++) { /* Check what kind of handle this is */ HandleBuffer[i] = TranslateStdHandle(HandleBuffer[i]);
/* Check for console handle */ if ((IsConsoleHandle(HandleBuffer[i])) && (VerifyConsoleIoHandle(HandleBuffer[i]))) { /* Get the real wait handle */ HandleBuffer[i] = GetConsoleInputWaitHandle(); } }
/* Convert the timeout */ TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds);
/* Start wait loop */ do { /* Do the wait */ Status = NtWaitForMultipleObjects(nCount, HandleBuffer, bWaitAll ? WaitAll : WaitAny, (BOOLEAN)bAlertable, TimePtr); if (!NT_SUCCESS(Status)) { /* Wait failed */ BaseSetLastNTError(Status); Status = WAIT_FAILED; } } while ((Status == STATUS_ALERTED) && (bAlertable));
/* Check if we didn't use our local buffer */ if (HandleBuffer != Handle) { /* Free the allocated one */ RtlFreeHeap(RtlGetProcessHeap(), 0, HandleBuffer); }
/* Cleanup the activation context */ if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
/* Return wait status */ return Status;}
/* * @implemented */DWORDWINAPISignalObjectAndWait(IN HANDLE hObjectToSignal, IN HANDLE hObjectToWaitOn, IN DWORD dwMilliseconds, IN BOOL bAlertable){ PLARGE_INTEGER TimePtr; LARGE_INTEGER Time; NTSTATUS Status; RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
/* APCs must execute with the default activation context */ if (bAlertable) { /* Setup the frame */ RtlZeroMemory(&ActCtx, sizeof(ActCtx)); ActCtx.Size = sizeof(ActCtx); ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; RtlActivateActivationContextUnsafeFast(&ActCtx, NULL); }
/* Get real handle */ hObjectToWaitOn = TranslateStdHandle(hObjectToWaitOn);
/* Check for console handle */ if ((IsConsoleHandle(hObjectToWaitOn)) && (VerifyConsoleIoHandle(hObjectToWaitOn))) { /* Get the real wait handle */ hObjectToWaitOn = GetConsoleInputWaitHandle(); }
/* Convert the timeout */ TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds);
/* Start wait loop */ do { /* Do the wait */ Status = NtSignalAndWaitForSingleObject(hObjectToSignal, hObjectToWaitOn, (BOOLEAN)bAlertable, TimePtr); if (!NT_SUCCESS(Status)) { /* The wait failed */ BaseSetLastNTError(Status); Status = WAIT_FAILED; } } while ((Status == STATUS_ALERTED) && (bAlertable));
/* Cleanup the activation context */ if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
/* Return wait status */ return Status;}
/* * @implemented */HANDLEWINAPICreateWaitableTimerW(IN LPSECURITY_ATTRIBUTES lpTimerAttributes OPTIONAL, IN BOOL bManualReset, IN LPCWSTR lpTimerName OPTIONAL){ CreateNtObjectFromWin32Api(WaitableTimer, Timer, TIMER_ALL_ACCESS, lpTimerAttributes, lpTimerName, bManualReset ? NotificationTimer : SynchronizationTimer);}
/* * @implemented */HANDLEWINAPIOpenWaitableTimerW(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCWSTR lpTimerName){ OpenNtObjectFromWin32Api(Timer, dwDesiredAccess, bInheritHandle, lpTimerName);}
/* * @implemented */BOOLWINAPISetWaitableTimer(IN HANDLE hTimer, IN const LARGE_INTEGER *pDueTime, IN LONG lPeriod, IN PTIMERAPCROUTINE pfnCompletionRoutine OPTIONAL, IN OPTIONAL LPVOID lpArgToCompletionRoutine, IN BOOL fResume){ NTSTATUS Status;
/* Set the timer */ Status = NtSetTimer(hTimer, (PLARGE_INTEGER)pDueTime, (PTIMER_APC_ROUTINE)pfnCompletionRoutine, lpArgToCompletionRoutine, (BOOLEAN)fResume, lPeriod, NULL); if (NT_SUCCESS(Status)) return TRUE;
/* If we got here, then we failed */ BaseSetLastNTError(Status); return FALSE;}
/* * @implemented */BOOLWINAPICancelWaitableTimer(IN HANDLE hTimer){ NTSTATUS Status;
/* Cancel the timer */ Status = NtCancelTimer(hTimer, NULL); if (NT_SUCCESS(Status)) return TRUE;
/* If we got here, then we failed */ BaseSetLastNTError(Status); return FALSE;}
/* * @implemented */HANDLEWINAPIDECLSPEC_HOTPATCHCreateSemaphoreW(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL, IN LONG lInitialCount, IN LONG lMaximumCount, IN LPCWSTR lpName OPTIONAL){ CreateNtObjectFromWin32Api(Semaphore, Semaphore, SEMAPHORE_ALL_ACCESS, lpSemaphoreAttributes, lpName, lInitialCount, lMaximumCount);}
HANDLEWINAPIDECLSPEC_HOTPATCHCreateSemaphoreExW(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL, IN LONG lInitialCount, IN LONG lMaximumCount, IN LPCWSTR lpName OPTIONAL, IN DWORD dwFlags OPTIONAL, IN DWORD dwDesiredAccess OPTIONAL){ CreateNtObjectFromWin32Api(Semaphore, Semaphore, dwDesiredAccess, lpSemaphoreAttributes, lpName, lInitialCount, lMaximumCount);}
HANDLEWINAPIDECLSPEC_HOTPATCHCreateSemaphoreExA(IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes OPTIONAL, IN LONG lInitialCount, IN LONG lMaximumCount, IN LPCSTR lpName OPTIONAL, IN DWORD dwFlags OPTIONAL, IN DWORD dwDesiredAccess OPTIONAL){ ConvertAnsiToUnicodePrologue
if (!lpName) { return CreateSemaphoreExW(lpSemaphoreAttributes, lInitialCount, lMaximumCount, NULL, dwFlags, dwDesiredAccess); }
ConvertAnsiToUnicodeBody(lpName)
if (NT_SUCCESS(Status)) { return CreateSemaphoreExW(lpSemaphoreAttributes, lInitialCount, lMaximumCount, UnicodeCache->Buffer, dwFlags, dwDesiredAccess); }
ConvertAnsiToUnicodeEpilogue}
/* * @implemented */HANDLEWINAPIDECLSPEC_HOTPATCHOpenSemaphoreW(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCWSTR lpName){ OpenNtObjectFromWin32Api(Semaphore, dwDesiredAccess, bInheritHandle, lpName);}
/* * @implemented */BOOLWINAPIDECLSPEC_HOTPATCHReleaseSemaphore(IN HANDLE hSemaphore, IN LONG lReleaseCount, IN LPLONG lpPreviousCount){ NTSTATUS Status;
/* Release the semaphore */ Status = NtReleaseSemaphore(hSemaphore, lReleaseCount, lpPreviousCount); if (NT_SUCCESS(Status)) return TRUE;
/* If we got here, then we failed */ BaseSetLastNTError(Status); return FALSE;}
/* * @implemented */HANDLEWINAPIDECLSPEC_HOTPATCHCreateMutexA(IN LPSECURITY_ATTRIBUTES lpMutexAttributes OPTIONAL, IN BOOL bInitialOwner, IN LPCSTR lpName OPTIONAL){ ConvertWin32AnsiObjectApiToUnicodeApi(Mutex, lpName, lpMutexAttributes, bInitialOwner);}
/* * @implemented */HANDLEWINAPIDECLSPEC_HOTPATCHCreateMutexW(IN LPSECURITY_ATTRIBUTES lpMutexAttributes OPTIONAL, IN BOOL bInitialOwner, IN LPCWSTR lpName OPTIONAL){ CreateNtObjectFromWin32Api(Mutex, Mutant, MUTEX_ALL_ACCESS, lpMutexAttributes, lpName, bInitialOwner);}
/* * @implemented */HANDLEWINAPIDECLSPEC_HOTPATCHOpenMutexW(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCWSTR lpName){ OpenNtObjectFromWin32Api(Mutant, dwDesiredAccess, bInheritHandle, lpName);}
/* * @implemented */BOOLWINAPIDECLSPEC_HOTPATCHReleaseMutex(IN HANDLE hMutex){ NTSTATUS Status;
/* Release the mutant */ Status = NtReleaseMutant(hMutex, NULL); if (NT_SUCCESS(Status)) return TRUE;
/* If we got here, then we failed */ BaseSetLastNTError(Status); return FALSE;}
/* * @implemented */HANDLEWINAPIDECLSPEC_HOTPATCHCreateEventA(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCSTR lpName OPTIONAL){ ConvertWin32AnsiObjectApiToUnicodeApi(Event, lpName, lpEventAttributes, bManualReset, bInitialState);}
/* * @implemented */HANDLEWINAPIDECLSPEC_HOTPATCHCreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL){ CreateNtObjectFromWin32Api(Event, Event, EVENT_ALL_ACCESS, lpEventAttributes, lpName, bManualReset ? NotificationEvent : SynchronizationEvent, bInitialState);}
/* * @implemented */HANDLEWINAPIDECLSPEC_HOTPATCHOpenEventA(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCSTR lpName){ ConvertOpenWin32AnsiObjectApiToUnicodeApi(Event, dwDesiredAccess, bInheritHandle, lpName);}
/* * @implemented */HANDLEWINAPIDECLSPEC_HOTPATCHOpenEventW(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCWSTR lpName){ OpenNtObjectFromWin32Api(Event, dwDesiredAccess, bInheritHandle, lpName);}
/* * @implemented */BOOLWINAPIDECLSPEC_HOTPATCHPulseEvent(IN HANDLE hEvent){ NTSTATUS Status;
/* Pulse the event */ Status = NtPulseEvent(hEvent, NULL); if (NT_SUCCESS(Status)) return TRUE;
/* If we got here, then we failed */ BaseSetLastNTError(Status); return FALSE;}
/* * @implemented */BOOLWINAPIDECLSPEC_HOTPATCHResetEvent(IN HANDLE hEvent){ NTSTATUS Status;
/* Clear the event */ Status = NtResetEvent(hEvent, NULL); if (NT_SUCCESS(Status)) return TRUE;
/* If we got here, then we failed */ BaseSetLastNTError(Status); return FALSE;}
/* * @implemented */BOOLWINAPIDECLSPEC_HOTPATCHSetEvent(IN HANDLE hEvent){ NTSTATUS Status;
/* Set the event */ Status = NtSetEvent(hEvent, NULL); if (NT_SUCCESS(Status)) return TRUE;
/* If we got here, then we failed */ BaseSetLastNTError(Status); return FALSE;}
/* * @implemented */VOIDWINAPIInitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection){ NTSTATUS Status;
/* Initialize the critical section and raise an exception if we failed */ Status = RtlInitializeCriticalSection((PVOID)lpCriticalSection); if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status);}
/* * @implemented */BOOLWINAPIInitializeCriticalSectionAndSpinCount(OUT LPCRITICAL_SECTION lpCriticalSection, IN DWORD dwSpinCount){ NTSTATUS Status;
/* Initialize the critical section */ Status = RtlInitializeCriticalSectionAndSpinCount((PVOID)lpCriticalSection, dwSpinCount); if (!NT_SUCCESS(Status)) { /* Set failure code */ BaseSetLastNTError(Status); return FALSE; }
/* Success */ return TRUE;}
/* * @implemented */VOIDWINAPIDECLSPEC_HOTPATCHSleep(IN DWORD dwMilliseconds){ /* Call the new API */ SleepEx(dwMilliseconds, FALSE);}
/* * @implemented */DWORDWINAPISleepEx(IN DWORD dwMilliseconds, IN BOOL bAlertable){ LARGE_INTEGER Time; PLARGE_INTEGER TimePtr; NTSTATUS errCode; RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
/* APCs must execute with the default activation context */ if (bAlertable) { /* Setup the frame */ RtlZeroMemory(&ActCtx, sizeof(ActCtx)); ActCtx.Size = sizeof(ActCtx); ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; RtlActivateActivationContextUnsafeFast(&ActCtx, NULL); }
/* Convert the timeout */ TimePtr = BaseFormatTimeOut(&Time, dwMilliseconds); if (!TimePtr) { /* Turn an infinite wait into a really long wait */ Time.LowPart = 0; Time.HighPart = 0x80000000; TimePtr = &Time; }
/* Loop the delay while APCs are alerting us */ do { /* Do the delay */ errCode = NtDelayExecution((BOOLEAN)bAlertable, TimePtr); } while ((bAlertable) && (errCode == STATUS_ALERTED));
/* Cleanup the activation context */ if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
/* Return the correct code */ return (errCode == STATUS_USER_APC) ? WAIT_IO_COMPLETION : 0;}
/* * @implemented */BOOLWINAPIRegisterWaitForSingleObject(OUT PHANDLE phNewWaitObject, IN HANDLE hObject, IN WAITORTIMERCALLBACK Callback, IN PVOID Context, IN ULONG dwMilliseconds, IN ULONG dwFlags){ NTSTATUS Status;
/* Get real handle */ hObject = TranslateStdHandle(hObject);
/* Check for console handle */ if ((IsConsoleHandle(hObject)) && (VerifyConsoleIoHandle(hObject))) { /* Get the real wait handle */ hObject = GetConsoleInputWaitHandle(); }
/* Register the wait now */ Status = RtlRegisterWait(phNewWaitObject, hObject, Callback, Context, dwMilliseconds, dwFlags); if (!NT_SUCCESS(Status)) { /* Return failure */ BaseSetLastNTError(Status); return FALSE; }
/* All good */ return TRUE;}
/* * @implemented */HANDLEWINAPIRegisterWaitForSingleObjectEx(IN HANDLE hObject, IN WAITORTIMERCALLBACK Callback, IN PVOID Context, IN ULONG dwMilliseconds, IN ULONG dwFlags){ NTSTATUS Status; HANDLE hNewWaitObject;
/* Get real handle */ hObject = TranslateStdHandle(hObject);
/* Check for console handle */ if ((IsConsoleHandle(hObject)) && (VerifyConsoleIoHandle(hObject))) { /* Get the real wait handle */ hObject = GetConsoleInputWaitHandle(); }
/* Register the wait */ Status = RtlRegisterWait(&hNewWaitObject, hObject, Callback, Context, dwMilliseconds, dwFlags); if (!NT_SUCCESS(Status)) { /* Return failure */ BaseSetLastNTError(Status); return NULL; }
/* Return the object */ return hNewWaitObject;}
/* * @implemented */BOOLWINAPIUnregisterWait(IN HANDLE WaitHandle){ NTSTATUS Status;
/* Check for invalid handle */ if (!WaitHandle) { /* Fail */ SetLastError(ERROR_INVALID_HANDLE); return FALSE; }
/* Deregister the wait and check status */ Status = RtlDeregisterWaitEx(WaitHandle, NULL); if (!(NT_SUCCESS(Status)) || (Status == STATUS_PENDING)) { /* Failure or non-blocking call */ BaseSetLastNTError(Status); return FALSE; }
/* All good */ return TRUE;}
/* * @implemented */BOOLWINAPIUnregisterWaitEx(IN HANDLE WaitHandle, IN HANDLE CompletionEvent){ NTSTATUS Status;
/* Check for invalid handle */ if (!WaitHandle) { /* Fail */ SetLastError(ERROR_INVALID_HANDLE); return FALSE; }
/* Deregister the wait and check status */ Status = RtlDeregisterWaitEx(WaitHandle, CompletionEvent); if (!(NT_SUCCESS(Status)) || ((CompletionEvent != INVALID_HANDLE_VALUE) && (Status == STATUS_PENDING))) { /* Failure or non-blocking call */ BaseSetLastNTError(Status); return FALSE; }
/* All good */ return TRUE;}
/* EOF */