diff --git a/reactos/dll/win32/kernel32/misc/stubs.c b/reactos/dll/win32/kernel32/misc/stubs.c index c611d72c987..3349611c531 100644 --- a/reactos/dll/win32/kernel32/misc/stubs.c +++ b/reactos/dll/win32/kernel32/misc/stubs.c @@ -620,24 +620,6 @@ MapUserPhysicalPagesScatter( return 0; } -/* - * @unimplemented - */ -BOOL -STDCALL -QueueUserWorkItem( - LPTHREAD_START_ROUTINE Function, - PVOID Context, - ULONG Flags - ) -{ - STUB; - return 0; -} - - - - /* * @unimplemented */ diff --git a/reactos/dll/win32/kernel32/thread/thread.c b/reactos/dll/win32/kernel32/thread/thread.c index 3c68a8b263c..916091f3030 100644 --- a/reactos/dll/win32/kernel32/thread/thread.c +++ b/reactos/dll/win32/kernel32/thread/thread.c @@ -873,4 +873,79 @@ SleepEx(DWORD dwMilliseconds, return 0; } + +typedef struct _QUEUE_USER_WORKITEM_CONTEXT +{ + LPTHREAD_START_ROUTINE Function; + PVOID Context; +} QUEUE_USER_WORKITEM_CONTEXT, *PQUEUE_USER_WORKITEM_CONTEXT; + +static VOID +NTAPI +InternalWorkItemTrampoline(PVOID Context) +{ + QUEUE_USER_WORKITEM_CONTEXT Info; + + ASSERT(Context != NULL); + + /* Save the context to the stack */ + Info = *(volatile QUEUE_USER_WORKITEM_CONTEXT *)Context; + + /* Free the context before calling the callback. This avoids + a memory leak in case the thread dies... */ + RtlFreeHeap(RtlGetProcessHeap(), + 0, + Context); + + /* Call the real callback */ + Info.Function(Info.Context); +} + + +/* + * @implemented + */ +BOOL +STDCALL +QueueUserWorkItem( + LPTHREAD_START_ROUTINE Function, + PVOID Context, + ULONG Flags + ) +{ + PQUEUE_USER_WORKITEM_CONTEXT WorkItemContext; + NTSTATUS Status; + + /* Save the context for the trampoline function */ + WorkItemContext = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + sizeof(*WorkItemContext)); + if (WorkItemContext == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + WorkItemContext->Function = Function; + WorkItemContext->Context = Context; + + /* NOTE: Don't use Function directly since the callback signature + differs. This might cause problems on certain platforms... */ + Status = RtlQueueWorkItem(InternalWorkItemTrampoline, + WorkItemContext, + Flags); + if (!NT_SUCCESS(Status)) + { + /* Free the allocated context in case of failure */ + RtlFreeHeap(RtlGetProcessHeap(), + 0, + WorkItemContext); + + SetLastErrorByStatus(Status); + return FALSE; + } + + return TRUE; +} + /* EOF */