2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: message.c,v 1.78 2004/12/25 22:59:10 navaraf Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
24 * FILE: subsys/win32k/ntuser/message.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
30 /* INCLUDES ******************************************************************/
42 } DOSENDMESSAGE
, *PDOSENDMESSAGE
;
44 /* FUNCTIONS *****************************************************************/
47 IntInitMessageImpl(VOID
)
49 return STATUS_SUCCESS
;
53 IntCleanupMessageImpl(VOID
)
55 return STATUS_SUCCESS
;
58 #define MMS_SIZE_WPARAM -1
59 #define MMS_SIZE_WPARAMWCHAR -2
60 #define MMS_SIZE_LPARAMSZ -3
61 #define MMS_SIZE_SPECIAL -4
62 #define MMS_FLAG_READ 0x01
63 #define MMS_FLAG_WRITE 0x02
64 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
65 typedef struct tagMSGMEMORY
70 } MSGMEMORY
, *PMSGMEMORY
;
72 static MSGMEMORY MsgMemory
[] =
74 { WM_CREATE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
75 { WM_DDE_ACK
, sizeof(KMDDELPARAM
), MMS_FLAG_READ
},
76 { WM_DDE_EXECUTE
, MMS_SIZE_WPARAM
, MMS_FLAG_READ
},
77 { WM_GETMINMAXINFO
, sizeof(MINMAXINFO
), MMS_FLAG_READWRITE
},
78 { WM_GETTEXT
, MMS_SIZE_WPARAMWCHAR
, MMS_FLAG_WRITE
},
79 { WM_NCCALCSIZE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
80 { WM_NCCREATE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
81 { WM_SETTEXT
, MMS_SIZE_LPARAMSZ
, MMS_FLAG_READ
},
82 { WM_STYLECHANGED
, sizeof(STYLESTRUCT
), MMS_FLAG_READ
},
83 { WM_STYLECHANGING
, sizeof(STYLESTRUCT
), MMS_FLAG_READWRITE
},
84 { WM_COPYDATA
, MMS_SIZE_SPECIAL
, MMS_FLAG_READ
},
85 { WM_WINDOWPOSCHANGED
, sizeof(WINDOWPOS
), MMS_FLAG_READ
},
86 { WM_WINDOWPOSCHANGING
, sizeof(WINDOWPOS
), MMS_FLAG_READWRITE
},
89 static PMSGMEMORY FASTCALL
90 FindMsgMemory(UINT Msg
)
92 PMSGMEMORY MsgMemoryEntry
;
94 /* See if this message type is present in the table */
95 for (MsgMemoryEntry
= MsgMemory
;
96 MsgMemoryEntry
< MsgMemory
+ sizeof(MsgMemory
) / sizeof(MSGMEMORY
);
99 if (Msg
== MsgMemoryEntry
->Message
)
101 return MsgMemoryEntry
;
109 MsgMemorySize(PMSGMEMORY MsgMemoryEntry
, WPARAM wParam
, LPARAM lParam
)
112 PUNICODE_STRING WindowName
;
113 PUNICODE_STRING ClassName
;
116 if (MMS_SIZE_WPARAM
== MsgMemoryEntry
->Size
)
118 return (UINT
) wParam
;
120 else if (MMS_SIZE_WPARAMWCHAR
== MsgMemoryEntry
->Size
)
122 return (UINT
) (wParam
* sizeof(WCHAR
));
124 else if (MMS_SIZE_LPARAMSZ
== MsgMemoryEntry
->Size
)
126 return (UINT
) ((wcslen((PWSTR
) lParam
) + 1) * sizeof(WCHAR
));
128 else if (MMS_SIZE_SPECIAL
== MsgMemoryEntry
->Size
)
130 switch(MsgMemoryEntry
->Message
)
134 Cs
= (CREATESTRUCTW
*) lParam
;
135 WindowName
= (PUNICODE_STRING
) Cs
->lpszName
;
136 ClassName
= (PUNICODE_STRING
) Cs
->lpszClass
;
137 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
138 if (IS_ATOM(ClassName
->Buffer
))
140 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
144 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
150 return wParam
? sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) : sizeof(RECT
);
154 return sizeof(COPYDATASTRUCT
) + ((PCOPYDATASTRUCT
)lParam
)->cbData
;
164 return MsgMemoryEntry
->Size
;
168 static FASTCALL NTSTATUS
169 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
171 NCCALCSIZE_PARAMS
*UnpackedNcCalcsize
;
172 NCCALCSIZE_PARAMS
*PackedNcCalcsize
;
173 CREATESTRUCTW
*UnpackedCs
;
174 CREATESTRUCTW
*PackedCs
;
175 PUNICODE_STRING WindowName
;
176 PUNICODE_STRING ClassName
;
180 *lParamPacked
= lParam
;
181 if (WM_NCCALCSIZE
== Msg
&& wParam
)
183 UnpackedNcCalcsize
= (NCCALCSIZE_PARAMS
*) lParam
;
184 if (UnpackedNcCalcsize
->lppos
!= (PWINDOWPOS
) (UnpackedNcCalcsize
+ 1))
186 PackedNcCalcsize
= ExAllocatePoolWithTag(PagedPool
,
187 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
189 if (NULL
== PackedNcCalcsize
)
191 DPRINT1("Not enough memory to pack lParam\n");
192 return STATUS_NO_MEMORY
;
194 RtlCopyMemory(PackedNcCalcsize
, UnpackedNcCalcsize
, sizeof(NCCALCSIZE_PARAMS
));
195 PackedNcCalcsize
->lppos
= (PWINDOWPOS
) (PackedNcCalcsize
+ 1);
196 RtlCopyMemory(PackedNcCalcsize
->lppos
, UnpackedNcCalcsize
->lppos
, sizeof(WINDOWPOS
));
197 *lParamPacked
= (LPARAM
) PackedNcCalcsize
;
200 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
202 UnpackedCs
= (CREATESTRUCTW
*) lParam
;
203 WindowName
= (PUNICODE_STRING
) UnpackedCs
->lpszName
;
204 ClassName
= (PUNICODE_STRING
) UnpackedCs
->lpszClass
;
205 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
206 if (IS_ATOM(ClassName
->Buffer
))
208 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
212 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
214 PackedCs
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
215 if (NULL
== PackedCs
)
217 DPRINT1("Not enough memory to pack lParam\n");
218 return STATUS_NO_MEMORY
;
220 RtlCopyMemory(PackedCs
, UnpackedCs
, sizeof(CREATESTRUCTW
));
221 CsData
= (PCHAR
) (PackedCs
+ 1);
222 PackedCs
->lpszName
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
223 RtlCopyMemory(CsData
, WindowName
->Buffer
, WindowName
->Length
);
224 CsData
+= WindowName
->Length
;
225 *((WCHAR
*) CsData
) = L
'\0';
226 CsData
+= sizeof(WCHAR
);
227 PackedCs
->lpszClass
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
228 if (IS_ATOM(ClassName
->Buffer
))
230 *((WCHAR
*) CsData
) = L
'A';
231 CsData
+= sizeof(WCHAR
);
232 *((ATOM
*) CsData
) = (ATOM
)(DWORD_PTR
) ClassName
->Buffer
;
233 CsData
+= sizeof(ATOM
);
237 *((WCHAR
*) CsData
) = L
'S';
238 CsData
+= sizeof(WCHAR
);
239 RtlCopyMemory(CsData
, ClassName
->Buffer
, ClassName
->Length
);
240 CsData
+= ClassName
->Length
;
241 *((WCHAR
*) CsData
) = L
'\0';
242 CsData
+= sizeof(WCHAR
);
244 ASSERT(CsData
== (PCHAR
) PackedCs
+ Size
);
245 *lParamPacked
= (LPARAM
) PackedCs
;
248 return STATUS_SUCCESS
;
251 static FASTCALL NTSTATUS
252 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
254 NCCALCSIZE_PARAMS
*UnpackedParams
;
255 NCCALCSIZE_PARAMS
*PackedParams
;
256 PWINDOWPOS UnpackedWindowPos
;
258 if (lParamPacked
== lParam
)
260 return STATUS_SUCCESS
;
263 if (WM_NCCALCSIZE
== Msg
&& wParam
)
265 PackedParams
= (NCCALCSIZE_PARAMS
*) lParamPacked
;
266 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
267 UnpackedWindowPos
= UnpackedParams
->lppos
;
268 RtlCopyMemory(UnpackedParams
, PackedParams
, sizeof(NCCALCSIZE_PARAMS
));
269 UnpackedParams
->lppos
= UnpackedWindowPos
;
270 RtlCopyMemory(UnpackedWindowPos
, PackedParams
+ 1, sizeof(WINDOWPOS
));
271 ExFreePool((PVOID
) lParamPacked
);
273 return STATUS_SUCCESS
;
275 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
277 ExFreePool((PVOID
) lParamPacked
);
279 return STATUS_SUCCESS
;
284 return STATUS_INVALID_PARAMETER
;
289 NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo
)
292 NTUSERDISPATCHMESSAGEINFO MsgInfo
;
293 PWINDOW_OBJECT WindowObject
;
294 LRESULT Result
= TRUE
;
296 Status
= MmCopyFromCaller(&MsgInfo
, UnsafeMsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
297 if (! NT_SUCCESS(Status
))
299 SetLastNtError(Status
);
303 /* Process timer messages. */
304 if (WM_TIMER
== MsgInfo
.Msg
.message
&& 0 != MsgInfo
.Msg
.lParam
)
306 LARGE_INTEGER LargeTickCount
;
307 /* FIXME: Call hooks. */
309 /* FIXME: Check for continuing validity of timer. */
311 MsgInfo
.HandledByKernel
= FALSE
;
312 KeQueryTickCount(&LargeTickCount
);
313 MsgInfo
.Proc
= (WNDPROC
) MsgInfo
.Msg
.lParam
;
314 MsgInfo
.Msg
.lParam
= (LPARAM
)LargeTickCount
.u
.LowPart
;
316 else if (NULL
== MsgInfo
.Msg
.hwnd
)
318 MsgInfo
.HandledByKernel
= TRUE
;
323 /* Get the window object. */
324 WindowObject
= IntGetWindowObject(MsgInfo
.Msg
.hwnd
);
325 if (NULL
== WindowObject
)
327 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
328 MsgInfo
.HandledByKernel
= TRUE
;
333 if (WindowObject
->OwnerThread
!= PsGetCurrentThread())
335 IntReleaseWindowObject(WindowObject
);
336 DPRINT1("Window doesn't belong to the calling thread!\n");
337 MsgInfo
.HandledByKernel
= TRUE
;
342 /* FIXME: Call hook procedures. */
344 MsgInfo
.HandledByKernel
= FALSE
;
346 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcW
& 0xFFFF0000))
348 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcA
& 0xFFFF0000))
350 /* Both Unicode and Ansi winprocs are real, use whatever
352 MsgInfo
.Proc
= (MsgInfo
.Ansi
? WindowObject
->WndProcA
353 : WindowObject
->WndProcW
);
357 /* Real Unicode winproc */
358 MsgInfo
.Ansi
= FALSE
;
359 MsgInfo
.Proc
= WindowObject
->WndProcW
;
364 /* Must have real Ansi winproc */
366 MsgInfo
.Proc
= WindowObject
->WndProcA
;
369 IntReleaseWindowObject(WindowObject
);
372 Status
= MmCopyToCaller(UnsafeMsgInfo
, &MsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
373 if (! NT_SUCCESS(Status
))
375 SetLastNtError(Status
);
384 NtUserTranslateMessage(LPMSG lpMsg
,
390 Status
= MmCopyFromCaller(&SafeMsg
, lpMsg
, sizeof(MSG
));
391 if(!NT_SUCCESS(Status
))
393 SetLastNtError(Status
);
397 return IntTranslateKbdMessage(&SafeMsg
, dwhkl
);
402 IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
404 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
413 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
418 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
425 case WM_LBUTTONDBLCLK
:
426 case WM_MBUTTONDBLCLK
:
427 case WM_RBUTTONDBLCLK
:
428 case WM_XBUTTONDBLCLK
:
431 PSYSTEM_CURSORINFO CurInfo
;
433 if(!IntGetWindowStationObject(InputWindowStation
))
437 CurInfo
= IntGetSysCursorInfo(InputWindowStation
);
438 wParam
= (WPARAM
)(CurInfo
->ButtonsDown
);
439 ObDereferenceObject(InputWindowStation
);
441 IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
442 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
445 case WM_NCLBUTTONDOWN
:
446 case WM_NCMBUTTONDOWN
:
447 case WM_NCRBUTTONDOWN
:
448 case WM_NCXBUTTONDOWN
:
449 case WM_NCLBUTTONDBLCLK
:
450 case WM_NCMBUTTONDBLCLK
:
451 case WM_NCRBUTTONDBLCLK
:
452 case WM_NCXBUTTONDBLCLK
:
454 IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
455 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
462 IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, PWINDOW_OBJECT MsgWindow
,
467 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
469 /* eat the message, search again! */
473 Result
= IntSendMessage(MsgWindow
->Self
, WM_MOUSEACTIVATE
, (WPARAM
)NtUserGetParent(MsgWindow
->Self
), (LPARAM
)MAKELONG(*HitTest
, Msg
->message
));
476 case MA_NOACTIVATEANDEAT
:
480 case MA_ACTIVATEANDEAT
:
481 IntMouseActivateWindow(MsgWindow
);
485 IntMouseActivateWindow(MsgWindow
);
493 IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, USHORT
*HitTest
, BOOL Remove
)
495 PWINDOW_OBJECT Window
;
497 if(!(Window
= IntGetWindowObject(Msg
->hwnd
)))
499 /* let's just eat the message?! */
503 if(ThreadQueue
== Window
->MessageQueue
&&
504 ThreadQueue
->CaptureWindow
!= Window
->Self
)
506 /* only send WM_NCHITTEST messages if we're not capturing the window! */
507 *HitTest
= IntSendMessage(Window
->Self
, WM_NCHITTEST
, 0,
508 MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
));
510 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
512 PWINDOW_OBJECT DesktopWindow
;
513 HWND hDesktop
= IntGetDesktopWindow();
515 if((DesktopWindow
= IntGetWindowObject(hDesktop
)))
519 WinPosWindowFromPoint(DesktopWindow
, Window
->MessageQueue
, &Msg
->pt
, &Wnd
);
524 /* post the message to the other window */
525 Msg
->hwnd
= Wnd
->Self
;
526 if(!(Wnd
->Status
& WINDOWSTATUS_DESTROYING
))
528 MsqPostMessage(Wnd
->MessageQueue
, Msg
, FALSE
,
529 Msg
->message
== WM_MOUSEMOVE
? QS_MOUSEMOVE
:
533 /* eat the message */
534 IntReleaseWindowObject(Wnd
);
535 IntReleaseWindowObject(Window
);
536 IntReleaseWindowObject(DesktopWindow
);
539 IntReleaseWindowObject(Wnd
);
542 IntReleaseWindowObject(DesktopWindow
);
551 if(IS_BTN_MESSAGE(Msg
->message
, DOWN
))
553 /* generate double click messages, if necessary */
554 if ((((*HitTest
) != HTCLIENT
) ||
555 (IntGetClassLong(Window
, GCL_STYLE
, FALSE
) & CS_DBLCLKS
)) &&
556 MsqIsDblClk(Msg
, Remove
))
558 Msg
->message
+= WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
;
562 if(Msg
->message
!= WM_MOUSEWHEEL
)
565 if ((*HitTest
) != HTCLIENT
)
567 Msg
->message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
568 if((Msg
->message
== WM_NCRBUTTONUP
) &&
569 (((*HitTest
) == HTCAPTION
) || ((*HitTest
) == HTSYSMENU
)))
571 Msg
->message
= WM_CONTEXTMENU
;
572 Msg
->wParam
= (WPARAM
)Window
->Self
;
576 Msg
->wParam
= *HitTest
;
578 Msg
->lParam
= MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
);
580 else if(ThreadQueue
->MoveSize
== NULL
&&
581 ThreadQueue
->MenuOwner
== NULL
)
583 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
584 Msg
->lParam
= MAKELONG(
585 Msg
->pt
.x
- (WORD
)Window
->ClientRect
.left
,
586 Msg
->pt
.y
- (WORD
)Window
->ClientRect
.top
);
590 IntReleaseWindowObject(Window
);
596 * Internal version of PeekMessage() doing all the work
599 IntPeekMessage(PUSER_MESSAGE Msg
,
605 LARGE_INTEGER LargeTickCount
;
606 PUSER_MESSAGE_QUEUE ThreadQueue
;
607 PUSER_MESSAGE Message
;
608 BOOL Present
, RemoveMessages
;
610 /* The queues and order in which they are checked are documented in the MSDN
611 article on GetMessage() */
613 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
615 /* Inspect RemoveMsg flags */
616 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
617 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
623 KeQueryTickCount(&LargeTickCount
);
624 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
626 /* Dispatch sent messages here. */
627 while (MsqDispatchOneSentMessage(ThreadQueue
));
629 /* Now look for a quit message. */
631 if (ThreadQueue
->QuitPosted
)
633 /* According to the PSDK, WM_QUIT messages are always returned, regardless
634 of the filter specified */
635 Msg
->Msg
.hwnd
= NULL
;
636 Msg
->Msg
.message
= WM_QUIT
;
637 Msg
->Msg
.wParam
= ThreadQueue
->QuitExitCode
;
639 Msg
->FreeLParam
= FALSE
;
642 ThreadQueue
->QuitPosted
= FALSE
;
647 /* Now check for normal messages. */
648 Present
= MsqFindMessage(ThreadQueue
,
657 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
660 MsqDestroyMessage(Message
);
665 /* Check for hardware events. */
666 Present
= MsqFindMessage(ThreadQueue
,
675 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
678 MsqDestroyMessage(Message
);
683 /* Check for sent messages again. */
684 while (MsqDispatchOneSentMessage(ThreadQueue
));
686 /* Check for paint messages. */
687 if (IntGetPaintMessage(Wnd
, MsgFilterMin
, MsgFilterMax
, PsGetWin32Thread(), &Msg
->Msg
, RemoveMessages
))
689 Msg
->FreeLParam
= FALSE
;
693 /* FIXME - get WM_(SYS)TIMER messages */
701 PWINDOW_OBJECT MsgWindow
= NULL
;;
703 if(Msg
->Msg
.hwnd
&& (MsgWindow
= IntGetWindowObject(Msg
->Msg
.hwnd
)) &&
704 Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
)
708 if(IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, TRUE
))
709 /* FIXME - check message filter again, if the message doesn't match anymore,
712 IntReleaseWindowObject(MsgWindow
);
713 /* eat the message, search again */
716 if(ThreadQueue
->CaptureWindow
== NULL
)
718 IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
719 if((Msg
->Msg
.message
!= WM_MOUSEMOVE
&& Msg
->Msg
.message
!= WM_NCMOUSEMOVE
) &&
720 IS_BTN_MESSAGE(Msg
->Msg
.message
, DOWN
) &&
721 IntActivateWindowMouse(ThreadQueue
, &Msg
->Msg
, MsgWindow
, &HitTest
))
723 IntReleaseWindowObject(MsgWindow
);
724 /* eat the message, search again */
731 IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
736 IntReleaseWindowObject(MsgWindow
);
743 if((Msg
->Msg
.hwnd
&& Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
) &&
744 IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, FALSE
))
745 /* FIXME - check message filter again, if the message doesn't match anymore,
748 /* eat the message, search again */
759 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
767 NTUSERGETMESSAGEINFO Info
;
768 PWINDOW_OBJECT Window
;
769 PMSGMEMORY MsgMemoryEntry
;
777 Window
= IntGetWindowObject(Wnd
);
784 IntReleaseWindowObject(Window
);
788 if (MsgFilterMax
< MsgFilterMin
)
794 Present
= IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
798 /* See if this message type is present in the table */
799 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
800 if (NULL
== MsgMemoryEntry
)
802 /* Not present, no copying needed */
807 /* Determine required size */
808 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
810 /* Allocate required amount of user-mode memory */
811 Info
.LParamSize
= Size
;
813 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
814 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
815 if (! NT_SUCCESS(Status
))
817 SetLastNtError(Status
);
820 /* Transfer lParam data to user-mode mem */
821 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
822 if (! NT_SUCCESS(Status
))
824 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
825 &Info
.LParamSize
, MEM_DECOMMIT
);
826 SetLastNtError(Status
);
829 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
831 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
833 ExFreePool((void *) Msg
.Msg
.lParam
);
835 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
836 if (! NT_SUCCESS(Status
))
838 SetLastNtError(Status
);
847 IntWaitMessage(HWND Wnd
,
851 PUSER_MESSAGE_QUEUE ThreadQueue
;
855 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
859 if (IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
864 /* Nothing found. Wait for new messages. */
865 Status
= MsqWaitForNewMessages(ThreadQueue
);
867 while (STATUS_WAIT_0
<= Status
&& Status
<= STATUS_WAIT_63
);
869 SetLastNtError(Status
);
875 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
880 * FUNCTION: Get a message from the calling thread's message queue.
882 * UnsafeMsg - Pointer to the structure which receives the returned message.
883 * Wnd - Window whose messages are to be retrieved.
884 * MsgFilterMin - Integer value of the lowest message value to be
886 * MsgFilterMax - Integer value of the highest message value to be
891 NTUSERGETMESSAGEINFO Info
;
893 PWINDOW_OBJECT Window
;
894 PMSGMEMORY MsgMemoryEntry
;
902 Window
= IntGetWindowObject(Wnd
);
906 IntReleaseWindowObject(Window
);
908 if (MsgFilterMax
< MsgFilterMin
)
916 GotMessage
= IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
920 /* See if this message type is present in the table */
921 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
922 if (NULL
== MsgMemoryEntry
)
924 /* Not present, no copying needed */
929 /* Determine required size */
930 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
932 /* Allocate required amount of user-mode memory */
933 Info
.LParamSize
= Size
;
935 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
936 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
938 if (! NT_SUCCESS(Status
))
940 SetLastNtError(Status
);
943 /* Transfer lParam data to user-mode mem */
944 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
945 if (! NT_SUCCESS(Status
))
947 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
948 &Info
.LParamSize
, MEM_DECOMMIT
);
949 SetLastNtError(Status
);
952 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
954 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
956 ExFreePool((void *) Msg
.Msg
.lParam
);
958 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
959 if (! NT_SUCCESS(Status
))
961 SetLastNtError(Status
);
965 else if (! IntWaitMessage(Wnd
, MsgFilterMin
, MsgFilterMax
))
970 while (! GotMessage
);
972 return WM_QUIT
!= Info
.Msg
.message
;
991 static NTSTATUS FASTCALL
992 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
, PMSGMEMORY MsgMemoryEntry
)
999 *KernelModeMsg
= *UserModeMsg
;
1001 /* See if this message type is present in the table */
1002 if (NULL
== MsgMemoryEntry
)
1004 /* Not present, no copying needed */
1005 return STATUS_SUCCESS
;
1008 /* Determine required size */
1009 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1013 /* Allocate kernel mem */
1014 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
1015 if (NULL
== KernelMem
)
1017 DPRINT1("Not enough memory to copy message to kernel mem\n");
1018 return STATUS_NO_MEMORY
;
1020 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
1022 /* Copy data if required */
1023 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
1025 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
1026 if (! NT_SUCCESS(Status
))
1028 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1029 ExFreePool(KernelMem
);
1035 /* Make sure we don't pass any secrets to usermode */
1036 RtlZeroMemory(KernelMem
, Size
);
1041 KernelModeMsg
->lParam
= 0;
1044 return STATUS_SUCCESS
;
1047 static NTSTATUS FASTCALL
1048 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
1051 PMSGMEMORY MsgMemoryEntry
;
1054 /* See if this message type is present in the table */
1055 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
1056 if (NULL
== MsgMemoryEntry
)
1058 /* Not present, no copying needed */
1059 return STATUS_SUCCESS
;
1062 /* Determine required size */
1063 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1067 /* Copy data if required */
1068 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
1070 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
1071 if (! NT_SUCCESS(Status
))
1073 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1074 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1079 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1082 return STATUS_SUCCESS
;
1086 NtUserPostMessage(HWND Wnd
,
1091 PWINDOW_OBJECT Window
;
1092 MSG UserModeMsg
, KernelModeMsg
;
1093 LARGE_INTEGER LargeTickCount
;
1095 PMSGMEMORY MsgMemoryEntry
;
1099 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue
, wParam
);
1101 else if (Wnd
== HWND_BROADCAST
)
1104 PWINDOW_OBJECT DesktopWindow
;
1107 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
1108 List
= IntWinListChildren(DesktopWindow
);
1109 IntReleaseWindowObject(DesktopWindow
);
1112 for (i
= 0; List
[i
]; i
++)
1113 NtUserPostMessage(List
[i
], Msg
, wParam
, lParam
);
1119 PSYSTEM_CURSORINFO CurInfo
;
1120 Window
= IntGetWindowObject(Wnd
);
1123 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1126 if(Window
->Status
& WINDOWSTATUS_DESTROYING
)
1128 IntReleaseWindowObject(Window
);
1129 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd
);
1130 /* FIXME - last error code? */
1134 UserModeMsg
.hwnd
= Wnd
;
1135 UserModeMsg
.message
= Msg
;
1136 UserModeMsg
.wParam
= wParam
;
1137 UserModeMsg
.lParam
= lParam
;
1138 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1139 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1140 if (! NT_SUCCESS(Status
))
1142 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1145 CurInfo
= IntGetSysCursorInfo(PsGetWin32Thread()->Desktop
->WindowStation
);
1146 KernelModeMsg
.pt
.x
= CurInfo
->x
;
1147 KernelModeMsg
.pt
.y
= CurInfo
->y
;
1148 KeQueryTickCount(&LargeTickCount
);
1149 KernelModeMsg
.time
= LargeTickCount
.u
.LowPart
;
1150 MsqPostMessage(Window
->MessageQueue
, &KernelModeMsg
,
1151 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
,
1153 IntReleaseWindowObject(Window
);
1160 NtUserPostThreadMessage(DWORD idThread
,
1165 MSG UserModeMsg
, KernelModeMsg
;
1169 PMSGMEMORY MsgMemoryEntry
;
1171 Status
= PsLookupThreadByThreadId((void *)idThread
,&peThread
);
1173 if( Status
== STATUS_SUCCESS
) {
1174 pThread
= peThread
->Tcb
.Win32Thread
;
1175 if( !pThread
|| !pThread
->MessageQueue
)
1177 ObDereferenceObject( peThread
);
1181 UserModeMsg
.hwnd
= NULL
;
1182 UserModeMsg
.message
= Msg
;
1183 UserModeMsg
.wParam
= wParam
;
1184 UserModeMsg
.lParam
= lParam
;
1185 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1186 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1187 if (! NT_SUCCESS(Status
))
1189 ObDereferenceObject( peThread
);
1190 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1193 MsqPostMessage(pThread
->MessageQueue
, &KernelModeMsg
,
1194 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
,
1196 ObDereferenceObject( peThread
);
1199 SetLastNtError( Status
);
1205 NtUserQuerySendMessage(DWORD Unknown0
)
1213 IntSendMessage(HWND hWnd
,
1218 ULONG_PTR Result
= 0;
1219 if(IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1221 return (LRESULT
)Result
;
1226 static LRESULT FASTCALL
1227 IntSendMessageTimeoutSingle(HWND hWnd
,
1237 PWINDOW_OBJECT Window
;
1238 PMSGMEMORY MsgMemoryEntry
;
1239 INT lParamBufferSize
;
1240 LPARAM lParamPacked
;
1241 PW32THREAD Win32Thread
;
1243 /* FIXME: Call hooks. */
1244 Window
= IntGetWindowObject(hWnd
);
1247 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1251 Win32Thread
= PsGetWin32Thread();
1253 if (NULL
!= Win32Thread
&&
1254 Window
->MessageQueue
== Win32Thread
->MessageQueue
)
1256 if (Win32Thread
->IsExiting
)
1258 /* Never send messages to exiting threads */
1259 IntReleaseWindowObject(Window
);
1263 /* See if this message type is present in the table */
1264 MsgMemoryEntry
= FindMsgMemory(Msg
);
1265 if (NULL
== MsgMemoryEntry
)
1267 lParamBufferSize
= -1;
1271 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1274 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
)))
1276 IntReleaseWindowObject(Window
);
1277 DPRINT1("Failed to pack message parameters\n");
1280 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
1282 Result
= (ULONG_PTR
)IntCallWindowProc(Window
->WndProcW
, FALSE
, hWnd
, Msg
, wParam
,
1283 lParamPacked
,lParamBufferSize
);
1287 Result
= (ULONG_PTR
)IntCallWindowProc(Window
->WndProcA
, TRUE
, hWnd
, Msg
, wParam
,
1288 lParamPacked
,lParamBufferSize
);
1296 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
)))
1298 IntReleaseWindowObject(Window
);
1299 DPRINT1("Failed to unpack message parameters\n");
1303 IntReleaseWindowObject(Window
);
1307 if(uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->MessageQueue
))
1309 IntReleaseWindowObject(Window
);
1310 /* FIXME - Set a LastError? */
1314 if(Window
->Status
& WINDOWSTATUS_DESTROYING
)
1316 IntReleaseWindowObject(Window
);
1317 /* FIXME - last error? */
1318 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd
);
1322 Status
= MsqSendMessage(Window
->MessageQueue
, hWnd
, Msg
, wParam
, lParam
,
1323 uTimeout
, (uFlags
& SMTO_BLOCK
), uResult
);
1324 IntReleaseWindowObject(Window
);
1325 if (STATUS_TIMEOUT
== Status
)
1327 /* MSDN says GetLastError() should return 0 after timeout */
1328 SetLastWin32Error(0);
1331 else if (! NT_SUCCESS(Status
))
1333 SetLastNtError(Status
);
1341 IntSendMessageTimeout(HWND hWnd
,
1349 PWINDOW_OBJECT DesktopWindow
;
1353 if (HWND_BROADCAST
!= hWnd
)
1355 return IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1358 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
1359 if (NULL
== DesktopWindow
)
1361 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1364 Children
= IntWinListChildren(DesktopWindow
);
1365 IntReleaseWindowObject(DesktopWindow
);
1366 if (NULL
== Children
)
1371 for (Child
= Children
; NULL
!= *Child
; Child
++)
1373 IntSendMessageTimeoutSingle(*Child
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1376 ExFreePool(Children
);
1378 return (LRESULT
) TRUE
;
1382 /* This function posts a message if the destination's message queue belongs to
1383 another thread, otherwise it sends the message. It does not support broadcast
1386 IntPostOrSendMessage(HWND hWnd
,
1392 PWINDOW_OBJECT Window
;
1394 if(hWnd
== HWND_BROADCAST
)
1399 Window
= IntGetWindowObject(hWnd
);
1402 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1406 if(Window
->MessageQueue
!= PsGetWin32Thread()->MessageQueue
)
1408 Result
= NtUserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1412 if(!IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1418 IntReleaseWindowObject(Window
);
1420 return (LRESULT
)Result
;
1424 IntDoSendMessage(HWND Wnd
,
1429 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1431 LRESULT Result
= TRUE
;
1433 PWINDOW_OBJECT Window
;
1434 NTUSERSENDMESSAGEINFO Info
;
1437 PMSGMEMORY MsgMemoryEntry
;
1439 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1441 /* FIXME: Call hooks. */
1442 if (HWND_BROADCAST
!= Wnd
)
1444 Window
= IntGetWindowObject(Wnd
);
1447 /* Tell usermode to not touch this one */
1448 Info
.HandledByKernel
= TRUE
;
1449 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1450 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1455 /* FIXME: Check for an exiting window. */
1457 /* See if the current thread can handle the message */
1458 if (HWND_BROADCAST
!= Wnd
&& NULL
!= PsGetWin32Thread() &&
1459 Window
->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1461 /* Gather the information usermode needs to call the window proc directly */
1462 Info
.HandledByKernel
= FALSE
;
1463 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
1465 if (0xFFFF0000 != ((DWORD
) Window
->WndProcA
& 0xFFFF0000))
1467 /* Both Unicode and Ansi winprocs are real, see what usermode prefers */
1468 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
),
1470 if (! NT_SUCCESS(Status
))
1472 Info
.Ansi
= ! Window
->Unicode
;
1474 Info
.Proc
= (Info
.Ansi
? Window
->WndProcA
: Window
->WndProcW
);
1478 /* Real Unicode winproc */
1480 Info
.Proc
= Window
->WndProcW
;
1485 /* Must have real Ansi winproc */
1487 Info
.Proc
= Window
->WndProcA
;
1489 IntReleaseWindowObject(Window
);
1493 /* Must be handled by other thread */
1494 if (HWND_BROADCAST
!= Wnd
)
1496 IntReleaseWindowObject(Window
);
1498 Info
.HandledByKernel
= TRUE
;
1499 UserModeMsg
.hwnd
= Wnd
;
1500 UserModeMsg
.message
= Msg
;
1501 UserModeMsg
.wParam
= wParam
;
1502 UserModeMsg
.lParam
= lParam
;
1503 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1504 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1505 if (! NT_SUCCESS(Status
))
1507 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1508 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1509 return (dsm
? 0 : -1);
1513 Result
= IntSendMessage(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1514 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
);
1518 Result
= IntSendMessageTimeout(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1519 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1520 dsm
->uFlags
, dsm
->uTimeout
, &dsm
->Result
);
1522 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1523 if (! NT_SUCCESS(Status
))
1525 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1526 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1527 return(dsm
? 0 : -1);
1531 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1532 if (! NT_SUCCESS(Status
))
1534 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1537 return (LRESULT
)Result
;
1541 NtUserSendMessageTimeout(HWND hWnd
,
1548 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1553 dsm
.uFlags
= uFlags
;
1554 dsm
.uTimeout
= uTimeout
;
1555 Result
= IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
1556 if(uResult
!= NULL
&& Result
!= 0)
1560 Status
= MmCopyToCaller(uResult
, &dsm
.Result
, sizeof(ULONG_PTR
));
1561 if(!NT_SUCCESS(Status
))
1563 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1571 NtUserSendMessage(HWND Wnd
,
1575 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1577 return IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
);
1581 NtUserSendMessageCallback(HWND hWnd
,
1585 SENDASYNCPROC lpCallBack
,
1594 NtUserSendNotifyMessage(HWND hWnd
,
1605 NtUserWaitMessage(VOID
)
1608 return IntWaitMessage(NULL
, 0, 0);
1612 NtUserGetQueueStatus(BOOL ClearChanges
)
1614 PUSER_MESSAGE_QUEUE Queue
;
1617 Queue
= PsGetWin32Thread()->MessageQueue
;
1619 IntLockMessageQueue(Queue
);
1621 Result
= MAKELONG(Queue
->QueueBits
, Queue
->ChangedBits
);
1624 Queue
->ChangedBits
= 0;
1627 IntUnLockMessageQueue(Queue
);
1633 IntInitMessagePumpHook()
1635 PsGetCurrentThread()->Tcb
.Win32Thread
->MessagePumpHookValue
++;
1640 IntUninitMessagePumpHook()
1642 if (PsGetCurrentThread()->Tcb
.Win32Thread
->MessagePumpHookValue
<= 0)
1646 PsGetCurrentThread()->Tcb
.Win32Thread
->MessagePumpHookValue
--;