diff --git a/reactos/win32ss/include/callback.h b/reactos/win32ss/include/callback.h index b193c277fcb..dbfa6d589b1 100644 --- a/reactos/win32ss/include/callback.h +++ b/reactos/win32ss/include/callback.h @@ -13,7 +13,8 @@ #define USER32_CALLBACK_GETCHARSETINFO (9) #define USER32_CALLBACK_COPYIMAGE (10) #define USER32_CALLBACK_SETWNDICONS (11) -#define USER32_CALLBACK_MAXIMUM (11) +#define USER32_CALLBACK_DELIVERUSERAPC (12) +#define USER32_CALLBACK_MAXIMUM (12) typedef struct _WINDOWPROC_CALLBACK_ARGUMENTS { @@ -138,4 +139,6 @@ NTSTATUS WINAPI User32CallClientLoadLibraryFromKernel(PVOID Arguments, ULONG ArgumentLength); NTSTATUS WINAPI User32CallGetCharsetInfo(PVOID Arguments, ULONG ArgumentLength); +NTSTATUS WINAPI +User32DeliverUserAPC(PVOID Arguments, ULONG ArgumentLength); #endif /* __INCLUDE_USER32_CALLBACK_H */ diff --git a/reactos/win32ss/user/ntuser/callback.c b/reactos/win32ss/user/ntuser/callback.c index a9d6939d2c0..5c1998cda61 100644 --- a/reactos/win32ss/user/ntuser/callback.c +++ b/reactos/win32ss/user/ntuser/callback.c @@ -1100,4 +1100,24 @@ co_IntSetWndIcons(VOID) return TRUE; } +VOID FASTCALL +co_IntDeliverUserAPC(VOID) +{ + NTSTATUS Status; + UserLeaveCo(); + + Status = KeUserModeCallback(USER32_CALLBACK_DELIVERUSERAPC, + 0, + 0, + NULL, + NULL); + + + UserEnterCo(); + + if (!NT_SUCCESS(Status)) + { + ERR("Delivering User APC callback failed!\n"); + } +} /* EOF */ diff --git a/reactos/win32ss/user/ntuser/callback.h b/reactos/win32ss/user/ntuser/callback.h index 0464b48501d..9351e4cdb3e 100644 --- a/reactos/win32ss/user/ntuser/callback.h +++ b/reactos/win32ss/user/ntuser/callback.h @@ -71,3 +71,4 @@ co_IntGetCharsetInfo(LCID Locale, PCHARSETINFO pCs); HANDLE FASTCALL co_IntCopyImage(HANDLE,UINT,INT,INT,UINT); BOOL FASTCALL co_IntSetWndIcons(VOID); +VOID FASTCALL co_IntDeliverUserAPC(VOID); diff --git a/reactos/win32ss/user/ntuser/msgqueue.c b/reactos/win32ss/user/ntuser/msgqueue.c index cf403cfb165..5f1c38dfdd8 100644 --- a/reactos/win32ss/user/ntuser/msgqueue.c +++ b/reactos/win32ss/user/ntuser/msgqueue.c @@ -1132,17 +1132,22 @@ co_MsqSendMessage(PTHREADINFO ptirec, /* We can't access the Message anymore since it could have already been deleted! */ - if(Block) + if (Block) { + PVOID WaitObjects[2]; + + WaitObjects[0] = &CompletionEvent; // Wait 0 + WaitObjects[1] = ptirec->pEThread; // Wait 1 + UserLeaveCo(); /* Don't process messages sent to the thread */ - WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode, - FALSE, (uTimeout ? &Timeout : NULL)); + WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest, + UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL); UserEnterCo(); - if(WaitStatus == STATUS_TIMEOUT) + if (WaitStatus == STATUS_TIMEOUT || WaitStatus == STATUS_USER_APC) { /* Look up if the message has not yet dispatched, if so make sure it can't pass a result and it must not set the completion event anymore */ @@ -1182,7 +1187,27 @@ co_MsqSendMessage(PTHREADINFO ptirec, Entry = Entry->Flink; } - TRACE("MsqSendMessage (blocked) timed out 1\n"); + TRACE("MsqSendMessage (blocked) timed out 1 Status %p\n",WaitStatus); + + } + // Receiving thread passed on and left us hanging with issues still pending. + if ( WaitStatus == STATUS_WAIT_1 ) + { + ERR("Bk Receiving Thread woken up dead!\n"); + Entry = pti->DispatchingMessagesHead.Flink; + while (Entry != &pti->DispatchingMessagesHead) + { + if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry) + == Message) + { + Message->CompletionEvent = NULL; + Message->Result = NULL; + RemoveEntryList(&Message->DispatchingListEntry); + Message->DispatchingListEntry.Flink = NULL; + break; + } + Entry = Entry->Flink; + } } while (co_MsqDispatchOneSentMessage(pti)) ; @@ -1204,7 +1229,7 @@ co_MsqSendMessage(PTHREADINFO ptirec, UserEnterCo(); - if(WaitStatus == STATUS_TIMEOUT) + if (WaitStatus == STATUS_TIMEOUT || WaitStatus == STATUS_USER_APC) { /* Look up if the message has not yet been dispatched, if so make sure it can't pass a result and it must not set the completion event anymore */ @@ -1244,13 +1269,14 @@ co_MsqSendMessage(PTHREADINFO ptirec, Entry = Entry->Flink; } - TRACE("MsqSendMessage timed out 2\n"); + TRACE("MsqSendMessage timed out 2 Status %p\n",WaitStatus); + break; } // Receiving thread passed on and left us hanging with issues still pending. if ( WaitStatus == STATUS_WAIT_2 ) { - ERR("Receiving Thread woken up dead!\n"); + ERR("NB Receiving Thread woken up dead!\n"); Entry = pti->DispatchingMessagesHead.Flink; while (Entry != &pti->DispatchingMessagesHead) { @@ -1272,8 +1298,21 @@ co_MsqSendMessage(PTHREADINFO ptirec, while (NT_SUCCESS(WaitStatus) && WaitStatus == STATUS_WAIT_1); } - if(WaitStatus != STATUS_TIMEOUT) - if (uResult) *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1); + if ( WaitStatus == STATUS_USER_APC ) + { + // The current thread is dying! + TRACE("User APC\n"); + co_IntDeliverUserAPC(); + ERR("User APC Returned\n"); // Should not see this message. + } + + if (WaitStatus != STATUS_TIMEOUT) + { + if (uResult) + { + *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1); + } + } return WaitStatus; } @@ -1972,6 +2011,11 @@ co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter, FALSE, NULL ); UserEnterCo(); + if ( ret == STATUS_USER_APC ) + { + TRACE("MWFNW User APC\n"); + co_IntDeliverUserAPC(); + } return ret; } diff --git a/reactos/win32ss/user/user32/misc/dllmain.c b/reactos/win32ss/user/user32/misc/dllmain.c index 5eac679a2fb..58e3ec07648 100644 --- a/reactos/win32ss/user/user32/misc/dllmain.c +++ b/reactos/win32ss/user/user32/misc/dllmain.c @@ -200,6 +200,7 @@ PVOID apfnDispatch[USER32_CALLBACK_MAXIMUM + 1] = User32CallGetCharsetInfo, User32CallCopyImageFromKernel, User32CallSetWndIconsFromKernel, + User32DeliverUserAPC, }; /* @@ -468,3 +469,10 @@ User32CallSetWndIconsFromKernel(PVOID Arguments, ULONG ArgumentLength) ERR("hIconSmWindows %p hIconWindows %p \n",hIconSmWindows,hIconWindows); return ZwCallbackReturn(Arguments, ArgumentLength, STATUS_SUCCESS); } + +NTSTATUS +WINAPI +User32DeliverUserAPC(PVOID Arguments, ULONG ArgumentLength) +{ + return ZwCallbackReturn(0, 0, STATUS_SUCCESS); +}