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.
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 ******************************************************************/
43 } DOSENDMESSAGE
, *PDOSENDMESSAGE
;
45 /* FUNCTIONS *****************************************************************/
48 IntInitMessageImpl(VOID
)
50 return STATUS_SUCCESS
;
54 IntCleanupMessageImpl(VOID
)
56 return STATUS_SUCCESS
;
59 #define MMS_SIZE_WPARAM -1
60 #define MMS_SIZE_WPARAMWCHAR -2
61 #define MMS_SIZE_LPARAMSZ -3
62 #define MMS_SIZE_SPECIAL -4
63 #define MMS_FLAG_READ 0x01
64 #define MMS_FLAG_WRITE 0x02
65 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
66 typedef struct tagMSGMEMORY
71 } MSGMEMORY
, *PMSGMEMORY
;
73 static MSGMEMORY MsgMemory
[] =
75 { WM_CREATE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
76 { WM_DDE_ACK
, sizeof(KMDDELPARAM
), MMS_FLAG_READ
},
77 { WM_DDE_EXECUTE
, MMS_SIZE_WPARAM
, MMS_FLAG_READ
},
78 { WM_GETMINMAXINFO
, sizeof(MINMAXINFO
), MMS_FLAG_READWRITE
},
79 { WM_GETTEXT
, MMS_SIZE_WPARAMWCHAR
, MMS_FLAG_WRITE
},
80 { WM_NCCALCSIZE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
81 { WM_NCCREATE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
82 { WM_SETTEXT
, MMS_SIZE_LPARAMSZ
, MMS_FLAG_READ
},
83 { WM_STYLECHANGED
, sizeof(STYLESTRUCT
), MMS_FLAG_READ
},
84 { WM_STYLECHANGING
, sizeof(STYLESTRUCT
), MMS_FLAG_READWRITE
},
85 { WM_COPYDATA
, MMS_SIZE_SPECIAL
, MMS_FLAG_READ
},
86 { WM_WINDOWPOSCHANGED
, sizeof(WINDOWPOS
), MMS_FLAG_READ
},
87 { WM_WINDOWPOSCHANGING
, sizeof(WINDOWPOS
), MMS_FLAG_READWRITE
},
90 static PMSGMEMORY FASTCALL
91 FindMsgMemory(UINT Msg
)
93 PMSGMEMORY MsgMemoryEntry
;
95 /* See if this message type is present in the table */
96 for (MsgMemoryEntry
= MsgMemory
;
97 MsgMemoryEntry
< MsgMemory
+ sizeof(MsgMemory
) / sizeof(MSGMEMORY
);
100 if (Msg
== MsgMemoryEntry
->Message
)
102 return MsgMemoryEntry
;
110 MsgMemorySize(PMSGMEMORY MsgMemoryEntry
, WPARAM wParam
, LPARAM lParam
)
113 PUNICODE_STRING WindowName
;
114 PUNICODE_STRING ClassName
;
118 if (MMS_SIZE_WPARAM
== MsgMemoryEntry
->Size
)
120 return (UINT
) wParam
;
122 else if (MMS_SIZE_WPARAMWCHAR
== MsgMemoryEntry
->Size
)
124 return (UINT
) (wParam
* sizeof(WCHAR
));
126 else if (MMS_SIZE_LPARAMSZ
== MsgMemoryEntry
->Size
)
128 return (UINT
) ((wcslen((PWSTR
) lParam
) + 1) * sizeof(WCHAR
));
130 else if (MMS_SIZE_SPECIAL
== MsgMemoryEntry
->Size
)
132 switch(MsgMemoryEntry
->Message
)
136 Cs
= (CREATESTRUCTW
*) lParam
;
137 WindowName
= (PUNICODE_STRING
) Cs
->lpszName
;
138 ClassName
= (PUNICODE_STRING
) Cs
->lpszClass
;
139 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
140 if (IS_ATOM(ClassName
->Buffer
))
142 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
146 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
152 return wParam
? sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) : sizeof(RECT
);
156 return sizeof(COPYDATASTRUCT
) + ((PCOPYDATASTRUCT
)lParam
)->cbData
;
166 return MsgMemoryEntry
->Size
;
175 static FASTCALL NTSTATUS
176 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
178 NCCALCSIZE_PARAMS
*UnpackedNcCalcsize
;
179 NCCALCSIZE_PARAMS
*PackedNcCalcsize
;
180 CREATESTRUCTW
*UnpackedCs
;
181 CREATESTRUCTW
*PackedCs
;
182 PUNICODE_STRING WindowName
;
183 PUNICODE_STRING ClassName
;
187 *lParamPacked
= lParam
;
188 if (WM_NCCALCSIZE
== Msg
&& wParam
)
190 UnpackedNcCalcsize
= (NCCALCSIZE_PARAMS
*) lParam
;
191 if (UnpackedNcCalcsize
->lppos
!= (PWINDOWPOS
) (UnpackedNcCalcsize
+ 1))
193 PackedNcCalcsize
= ExAllocatePoolWithTag(PagedPool
,
194 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
196 if (NULL
== PackedNcCalcsize
)
198 DPRINT1("Not enough memory to pack lParam\n");
199 return STATUS_NO_MEMORY
;
201 RtlCopyMemory(PackedNcCalcsize
, UnpackedNcCalcsize
, sizeof(NCCALCSIZE_PARAMS
));
202 PackedNcCalcsize
->lppos
= (PWINDOWPOS
) (PackedNcCalcsize
+ 1);
203 RtlCopyMemory(PackedNcCalcsize
->lppos
, UnpackedNcCalcsize
->lppos
, sizeof(WINDOWPOS
));
204 *lParamPacked
= (LPARAM
) PackedNcCalcsize
;
207 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
209 UnpackedCs
= (CREATESTRUCTW
*) lParam
;
210 WindowName
= (PUNICODE_STRING
) UnpackedCs
->lpszName
;
211 ClassName
= (PUNICODE_STRING
) UnpackedCs
->lpszClass
;
212 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
213 if (IS_ATOM(ClassName
->Buffer
))
215 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
219 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
221 PackedCs
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
222 if (NULL
== PackedCs
)
224 DPRINT1("Not enough memory to pack lParam\n");
225 return STATUS_NO_MEMORY
;
227 RtlCopyMemory(PackedCs
, UnpackedCs
, sizeof(CREATESTRUCTW
));
228 CsData
= (PCHAR
) (PackedCs
+ 1);
229 PackedCs
->lpszName
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
230 RtlCopyMemory(CsData
, WindowName
->Buffer
, WindowName
->Length
);
231 CsData
+= WindowName
->Length
;
232 *((WCHAR
*) CsData
) = L
'\0';
233 CsData
+= sizeof(WCHAR
);
234 PackedCs
->lpszClass
= (LPCWSTR
) (CsData
- (PCHAR
) PackedCs
);
235 if (IS_ATOM(ClassName
->Buffer
))
237 *((WCHAR
*) CsData
) = L
'A';
238 CsData
+= sizeof(WCHAR
);
239 *((ATOM
*) CsData
) = (ATOM
)(DWORD_PTR
) ClassName
->Buffer
;
240 CsData
+= sizeof(ATOM
);
244 *((WCHAR
*) CsData
) = L
'S';
245 CsData
+= sizeof(WCHAR
);
246 RtlCopyMemory(CsData
, ClassName
->Buffer
, ClassName
->Length
);
247 CsData
+= ClassName
->Length
;
248 *((WCHAR
*) CsData
) = L
'\0';
249 CsData
+= sizeof(WCHAR
);
251 ASSERT(CsData
== (PCHAR
) PackedCs
+ Size
);
252 *lParamPacked
= (LPARAM
) PackedCs
;
255 return STATUS_SUCCESS
;
258 static FASTCALL NTSTATUS
259 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
261 NCCALCSIZE_PARAMS
*UnpackedParams
;
262 NCCALCSIZE_PARAMS
*PackedParams
;
263 PWINDOWPOS UnpackedWindowPos
;
265 if (lParamPacked
== lParam
)
267 return STATUS_SUCCESS
;
270 if (WM_NCCALCSIZE
== Msg
&& wParam
)
272 PackedParams
= (NCCALCSIZE_PARAMS
*) lParamPacked
;
273 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
274 UnpackedWindowPos
= UnpackedParams
->lppos
;
275 RtlCopyMemory(UnpackedParams
, PackedParams
, sizeof(NCCALCSIZE_PARAMS
));
276 UnpackedParams
->lppos
= UnpackedWindowPos
;
277 RtlCopyMemory(UnpackedWindowPos
, PackedParams
+ 1, sizeof(WINDOWPOS
));
278 ExFreePool((PVOID
) lParamPacked
);
280 return STATUS_SUCCESS
;
282 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
284 ExFreePool((PVOID
) lParamPacked
);
286 return STATUS_SUCCESS
;
291 return STATUS_INVALID_PARAMETER
;
296 NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo
)
299 NTUSERDISPATCHMESSAGEINFO MsgInfo
;
300 PWINDOW_OBJECT WindowObject
;
301 LRESULT Result
= TRUE
;
303 Status
= MmCopyFromCaller(&MsgInfo
, UnsafeMsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
304 if (! NT_SUCCESS(Status
))
306 SetLastNtError(Status
);
310 /* Process timer messages. */
311 if (WM_TIMER
== MsgInfo
.Msg
.message
&& 0 != MsgInfo
.Msg
.lParam
)
313 LARGE_INTEGER LargeTickCount
;
314 /* FIXME: Call hooks. */
316 /* FIXME: Check for continuing validity of timer. */
318 MsgInfo
.HandledByKernel
= FALSE
;
319 KeQueryTickCount(&LargeTickCount
);
320 MsgInfo
.Proc
= (WNDPROC
) MsgInfo
.Msg
.lParam
;
321 MsgInfo
.Msg
.lParam
= (LPARAM
)LargeTickCount
.u
.LowPart
;
323 else if (NULL
== MsgInfo
.Msg
.hwnd
)
325 MsgInfo
.HandledByKernel
= TRUE
;
330 /* Get the window object. */
331 WindowObject
= IntGetWindowObject(MsgInfo
.Msg
.hwnd
);
332 if (NULL
== WindowObject
)
334 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
335 MsgInfo
.HandledByKernel
= TRUE
;
340 if (WindowObject
->OwnerThread
!= PsGetCurrentThread())
342 IntReleaseWindowObject(WindowObject
);
343 DPRINT1("Window doesn't belong to the calling thread!\n");
344 MsgInfo
.HandledByKernel
= TRUE
;
349 /* FIXME: Call hook procedures. */
351 MsgInfo
.HandledByKernel
= FALSE
;
353 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcW
& 0xFFFF0000))
355 if (0xFFFF0000 != ((DWORD
) WindowObject
->WndProcA
& 0xFFFF0000))
357 /* Both Unicode and Ansi winprocs are real, use whatever
359 MsgInfo
.Proc
= (MsgInfo
.Ansi
? WindowObject
->WndProcA
360 : WindowObject
->WndProcW
);
364 /* Real Unicode winproc */
365 MsgInfo
.Ansi
= FALSE
;
366 MsgInfo
.Proc
= WindowObject
->WndProcW
;
371 /* Must have real Ansi winproc */
373 MsgInfo
.Proc
= WindowObject
->WndProcA
;
376 IntReleaseWindowObject(WindowObject
);
379 Status
= MmCopyToCaller(UnsafeMsgInfo
, &MsgInfo
, sizeof(NTUSERDISPATCHMESSAGEINFO
));
380 if (! NT_SUCCESS(Status
))
382 SetLastNtError(Status
);
391 NtUserTranslateMessage(LPMSG lpMsg
,
397 Status
= MmCopyFromCaller(&SafeMsg
, lpMsg
, sizeof(MSG
));
398 if(!NT_SUCCESS(Status
))
400 SetLastNtError(Status
);
404 return IntTranslateKbdMessage(&SafeMsg
, dwhkl
);
409 IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
411 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
420 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
425 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
432 case WM_LBUTTONDBLCLK
:
433 case WM_MBUTTONDBLCLK
:
434 case WM_RBUTTONDBLCLK
:
435 case WM_XBUTTONDBLCLK
:
438 PSYSTEM_CURSORINFO CurInfo
;
440 if(!IntGetWindowStationObject(InputWindowStation
))
444 CurInfo
= IntGetSysCursorInfo(InputWindowStation
);
445 wParam
= (WPARAM
)(CurInfo
->ButtonsDown
);
446 ObDereferenceObject(InputWindowStation
);
448 IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
449 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
452 case WM_NCLBUTTONDOWN
:
453 case WM_NCMBUTTONDOWN
:
454 case WM_NCRBUTTONDOWN
:
455 case WM_NCXBUTTONDOWN
:
456 case WM_NCLBUTTONDBLCLK
:
457 case WM_NCMBUTTONDBLCLK
:
458 case WM_NCRBUTTONDBLCLK
:
459 case WM_NCXBUTTONDBLCLK
:
461 IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
462 IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
469 IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, PWINDOW_OBJECT MsgWindow
,
474 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
476 /* eat the message, search again! */
480 Result
= IntSendMessage(MsgWindow
->Self
, WM_MOUSEACTIVATE
, (WPARAM
)NtUserGetParent(MsgWindow
->Self
), (LPARAM
)MAKELONG(*HitTest
, Msg
->message
));
483 case MA_NOACTIVATEANDEAT
:
487 case MA_ACTIVATEANDEAT
:
488 IntMouseActivateWindow(MsgWindow
);
492 IntMouseActivateWindow(MsgWindow
);
500 IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
, USHORT
*HitTest
, BOOL Remove
)
502 PWINDOW_OBJECT Window
;
504 if(!(Window
= IntGetWindowObject(Msg
->hwnd
)))
506 /* let's just eat the message?! */
510 if(ThreadQueue
== Window
->MessageQueue
&&
511 ThreadQueue
->CaptureWindow
!= Window
->Self
)
513 /* only send WM_NCHITTEST messages if we're not capturing the window! */
514 *HitTest
= IntSendMessage(Window
->Self
, WM_NCHITTEST
, 0,
515 MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
));
517 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
519 PWINDOW_OBJECT DesktopWindow
;
520 HWND hDesktop
= IntGetDesktopWindow();
522 if((DesktopWindow
= IntGetWindowObject(hDesktop
)))
526 WinPosWindowFromPoint(DesktopWindow
, Window
->MessageQueue
, &Msg
->pt
, &Wnd
);
531 /* post the message to the other window */
532 Msg
->hwnd
= Wnd
->Self
;
533 if(!(Wnd
->Status
& WINDOWSTATUS_DESTROYING
))
535 MsqPostMessage(Wnd
->MessageQueue
, Msg
, FALSE
,
536 Msg
->message
== WM_MOUSEMOVE
? QS_MOUSEMOVE
:
540 /* eat the message */
541 IntReleaseWindowObject(Wnd
);
542 IntReleaseWindowObject(Window
);
543 IntReleaseWindowObject(DesktopWindow
);
546 IntReleaseWindowObject(Wnd
);
549 IntReleaseWindowObject(DesktopWindow
);
558 if(IS_BTN_MESSAGE(Msg
->message
, DOWN
))
560 /* generate double click messages, if necessary */
561 if ((((*HitTest
) != HTCLIENT
) ||
562 (IntGetClassLong(Window
, GCL_STYLE
, FALSE
) & CS_DBLCLKS
)) &&
563 MsqIsDblClk(Msg
, Remove
))
565 Msg
->message
+= WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
;
569 if(Msg
->message
!= WM_MOUSEWHEEL
)
572 if ((*HitTest
) != HTCLIENT
)
574 Msg
->message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
575 if((Msg
->message
== WM_NCRBUTTONUP
) &&
576 (((*HitTest
) == HTCAPTION
) || ((*HitTest
) == HTSYSMENU
)))
578 Msg
->message
= WM_CONTEXTMENU
;
579 Msg
->wParam
= (WPARAM
)Window
->Self
;
583 Msg
->wParam
= *HitTest
;
585 Msg
->lParam
= MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
);
587 else if(ThreadQueue
->MoveSize
== NULL
&&
588 ThreadQueue
->MenuOwner
== NULL
)
590 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
591 Msg
->lParam
= MAKELONG(
592 Msg
->pt
.x
- (WORD
)Window
->ClientRect
.left
,
593 Msg
->pt
.y
- (WORD
)Window
->ClientRect
.top
);
597 IntReleaseWindowObject(Window
);
603 * Internal version of PeekMessage() doing all the work
606 IntPeekMessage(PUSER_MESSAGE Msg
,
612 LARGE_INTEGER LargeTickCount
;
613 PUSER_MESSAGE_QUEUE ThreadQueue
;
614 PUSER_MESSAGE Message
;
615 BOOL Present
, RemoveMessages
;
617 /* The queues and order in which they are checked are documented in the MSDN
618 article on GetMessage() */
620 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
622 /* Inspect RemoveMsg flags */
623 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
624 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
630 KeQueryTickCount(&LargeTickCount
);
631 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
633 /* Dispatch sent messages here. */
634 while (MsqDispatchOneSentMessage(ThreadQueue
));
636 /* Now look for a quit message. */
638 if (ThreadQueue
->QuitPosted
)
640 /* According to the PSDK, WM_QUIT messages are always returned, regardless
641 of the filter specified */
642 Msg
->Msg
.hwnd
= NULL
;
643 Msg
->Msg
.message
= WM_QUIT
;
644 Msg
->Msg
.wParam
= ThreadQueue
->QuitExitCode
;
646 Msg
->FreeLParam
= FALSE
;
649 ThreadQueue
->QuitPosted
= FALSE
;
654 /* Now check for normal messages. */
655 Present
= MsqFindMessage(ThreadQueue
,
664 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
667 MsqDestroyMessage(Message
);
672 /* Check for hardware events. */
673 Present
= MsqFindMessage(ThreadQueue
,
682 RtlCopyMemory(Msg
, Message
, sizeof(USER_MESSAGE
));
685 MsqDestroyMessage(Message
);
690 /* Check for sent messages again. */
691 while (MsqDispatchOneSentMessage(ThreadQueue
));
693 /* Check for paint messages. */
694 if (IntGetPaintMessage(Wnd
, MsgFilterMin
, MsgFilterMax
, PsGetWin32Thread(), &Msg
->Msg
, RemoveMessages
))
696 Msg
->FreeLParam
= FALSE
;
700 /* Check for WM_(SYS)TIMER messages */
701 Present
= MsqGetTimerMessage(ThreadQueue
, Wnd
, MsgFilterMin
, MsgFilterMax
,
702 &Msg
->Msg
, RemoveMessages
);
705 Msg
->FreeLParam
= FALSE
;
715 PWINDOW_OBJECT MsgWindow
= NULL
;;
717 if(Msg
->Msg
.hwnd
&& (MsgWindow
= IntGetWindowObject(Msg
->Msg
.hwnd
)) &&
718 Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
)
722 if(IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, TRUE
))
723 /* FIXME - check message filter again, if the message doesn't match anymore,
726 IntReleaseWindowObject(MsgWindow
);
727 /* eat the message, search again */
730 if(ThreadQueue
->CaptureWindow
== NULL
)
732 IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
733 if((Msg
->Msg
.message
!= WM_MOUSEMOVE
&& Msg
->Msg
.message
!= WM_NCMOUSEMOVE
) &&
734 IS_BTN_MESSAGE(Msg
->Msg
.message
, DOWN
) &&
735 IntActivateWindowMouse(ThreadQueue
, &Msg
->Msg
, MsgWindow
, &HitTest
))
737 IntReleaseWindowObject(MsgWindow
);
738 /* eat the message, search again */
745 IntSendHitTestMessages(ThreadQueue
, &Msg
->Msg
);
750 IntReleaseWindowObject(MsgWindow
);
757 if((Msg
->Msg
.hwnd
&& Msg
->Msg
.message
>= WM_MOUSEFIRST
&& Msg
->Msg
.message
<= WM_MOUSELAST
) &&
758 IntTranslateMouseMessage(ThreadQueue
, &Msg
->Msg
, &HitTest
, FALSE
))
759 /* FIXME - check message filter again, if the message doesn't match anymore,
762 /* eat the message, search again */
773 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
781 NTUSERGETMESSAGEINFO Info
;
782 PWINDOW_OBJECT Window
;
783 PMSGMEMORY MsgMemoryEntry
;
791 Window
= IntGetWindowObject(Wnd
);
798 IntReleaseWindowObject(Window
);
802 if (MsgFilterMax
< MsgFilterMin
)
808 Present
= IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
);
812 /* See if this message type is present in the table */
813 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
814 if (NULL
== MsgMemoryEntry
)
816 /* Not present, no copying needed */
821 /* Determine required size */
822 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
824 /* Allocate required amount of user-mode memory */
825 Info
.LParamSize
= Size
;
827 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
828 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
829 if (! NT_SUCCESS(Status
))
831 SetLastNtError(Status
);
834 /* Transfer lParam data to user-mode mem */
835 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
836 if (! NT_SUCCESS(Status
))
838 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
839 &Info
.LParamSize
, MEM_DECOMMIT
);
840 SetLastNtError(Status
);
843 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
845 if (RemoveMsg
&& Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
847 ExFreePool((void *) Msg
.Msg
.lParam
);
849 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
850 if (! NT_SUCCESS(Status
))
852 SetLastNtError(Status
);
861 IntWaitMessage(HWND Wnd
,
865 PUSER_MESSAGE_QUEUE ThreadQueue
;
869 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
873 if (IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_NOREMOVE
))
878 /* Nothing found. Wait for new messages. */
879 Status
= MsqWaitForNewMessages(ThreadQueue
, Wnd
, MsgFilterMin
, MsgFilterMax
);
881 while ((STATUS_WAIT_0
<= Status
&& Status
<= STATUS_WAIT_63
) || STATUS_TIMEOUT
== Status
);
883 SetLastNtError(Status
);
889 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
894 * FUNCTION: Get a message from the calling thread's message queue.
896 * UnsafeMsg - Pointer to the structure which receives the returned message.
897 * Wnd - Window whose messages are to be retrieved.
898 * MsgFilterMin - Integer value of the lowest message value to be
900 * MsgFilterMax - Integer value of the highest message value to be
905 NTUSERGETMESSAGEINFO Info
;
907 PWINDOW_OBJECT Window
;
908 PMSGMEMORY MsgMemoryEntry
;
916 Window
= IntGetWindowObject(Wnd
);
920 IntReleaseWindowObject(Window
);
922 if (MsgFilterMax
< MsgFilterMin
)
930 GotMessage
= IntPeekMessage(&Msg
, Wnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
);
934 /* See if this message type is present in the table */
935 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
936 if (NULL
== MsgMemoryEntry
)
938 /* Not present, no copying needed */
943 /* Determine required size */
944 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
,
946 /* Allocate required amount of user-mode memory */
947 Info
.LParamSize
= Size
;
949 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem
, 0,
950 &Info
.LParamSize
, MEM_COMMIT
, PAGE_READWRITE
);
952 if (! NT_SUCCESS(Status
))
954 SetLastNtError(Status
);
957 /* Transfer lParam data to user-mode mem */
958 Status
= MmCopyToCaller(UserMem
, (PVOID
) Info
.Msg
.lParam
, Size
);
959 if (! NT_SUCCESS(Status
))
961 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID
*) &UserMem
,
962 &Info
.LParamSize
, MEM_DECOMMIT
);
963 SetLastNtError(Status
);
966 Info
.Msg
.lParam
= (LPARAM
) UserMem
;
968 if (Msg
.FreeLParam
&& 0 != Msg
.Msg
.lParam
)
970 ExFreePool((void *) Msg
.Msg
.lParam
);
972 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
973 if (! NT_SUCCESS(Status
))
975 SetLastNtError(Status
);
979 else if (! IntWaitMessage(Wnd
, MsgFilterMin
, MsgFilterMax
))
984 while (! GotMessage
);
986 return WM_QUIT
!= Info
.Msg
.message
;
1005 static NTSTATUS FASTCALL
1006 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
, PMSGMEMORY MsgMemoryEntry
)
1013 *KernelModeMsg
= *UserModeMsg
;
1015 /* See if this message type is present in the table */
1016 if (NULL
== MsgMemoryEntry
)
1018 /* Not present, no copying needed */
1019 return STATUS_SUCCESS
;
1022 /* Determine required size */
1023 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1027 /* Allocate kernel mem */
1028 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
1029 if (NULL
== KernelMem
)
1031 DPRINT1("Not enough memory to copy message to kernel mem\n");
1032 return STATUS_NO_MEMORY
;
1034 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
1036 /* Copy data if required */
1037 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
1039 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
1040 if (! NT_SUCCESS(Status
))
1042 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1043 ExFreePool(KernelMem
);
1049 /* Make sure we don't pass any secrets to usermode */
1050 RtlZeroMemory(KernelMem
, Size
);
1055 KernelModeMsg
->lParam
= 0;
1058 return STATUS_SUCCESS
;
1061 static NTSTATUS FASTCALL
1062 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
1065 PMSGMEMORY MsgMemoryEntry
;
1068 /* See if this message type is present in the table */
1069 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
1070 if (NULL
== MsgMemoryEntry
)
1072 /* Not present, no copying needed */
1073 return STATUS_SUCCESS
;
1076 /* Determine required size */
1077 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1081 /* Copy data if required */
1082 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
1084 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
1085 if (! NT_SUCCESS(Status
))
1087 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1088 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1093 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1096 return STATUS_SUCCESS
;
1100 NtUserPostMessage(HWND Wnd
,
1105 PWINDOW_OBJECT Window
;
1106 MSG UserModeMsg
, KernelModeMsg
;
1107 LARGE_INTEGER LargeTickCount
;
1109 PMSGMEMORY MsgMemoryEntry
;
1113 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue
, wParam
);
1115 else if (Wnd
== HWND_BROADCAST
)
1118 PWINDOW_OBJECT DesktopWindow
;
1121 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
1122 List
= IntWinListChildren(DesktopWindow
);
1123 IntReleaseWindowObject(DesktopWindow
);
1126 for (i
= 0; List
[i
]; i
++)
1127 NtUserPostMessage(List
[i
], Msg
, wParam
, lParam
);
1133 Window
= IntGetWindowObject(Wnd
);
1136 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1139 if(Window
->Status
& WINDOWSTATUS_DESTROYING
)
1141 IntReleaseWindowObject(Window
);
1142 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd
);
1143 /* FIXME - last error code? */
1147 UserModeMsg
.hwnd
= Wnd
;
1148 UserModeMsg
.message
= Msg
;
1149 UserModeMsg
.wParam
= wParam
;
1150 UserModeMsg
.lParam
= lParam
;
1151 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1152 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1153 if (! NT_SUCCESS(Status
))
1155 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1158 IntGetCursorLocation(PsGetWin32Thread()->Desktop
->WindowStation
,
1160 KeQueryTickCount(&LargeTickCount
);
1161 KernelModeMsg
.time
= LargeTickCount
.u
.LowPart
;
1162 MsqPostMessage(Window
->MessageQueue
, &KernelModeMsg
,
1163 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
,
1165 IntReleaseWindowObject(Window
);
1172 NtUserPostThreadMessage(DWORD idThread
,
1177 MSG UserModeMsg
, KernelModeMsg
;
1181 PMSGMEMORY MsgMemoryEntry
;
1183 Status
= PsLookupThreadByThreadId((HANDLE
)idThread
,&peThread
);
1185 if( Status
== STATUS_SUCCESS
) {
1186 pThread
= peThread
->Tcb
.Win32Thread
;
1187 if( !pThread
|| !pThread
->MessageQueue
)
1189 ObDereferenceObject( peThread
);
1193 UserModeMsg
.hwnd
= NULL
;
1194 UserModeMsg
.message
= Msg
;
1195 UserModeMsg
.wParam
= wParam
;
1196 UserModeMsg
.lParam
= lParam
;
1197 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1198 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1199 if (! NT_SUCCESS(Status
))
1201 ObDereferenceObject( peThread
);
1202 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1205 MsqPostMessage(pThread
->MessageQueue
, &KernelModeMsg
,
1206 NULL
!= MsgMemoryEntry
&& 0 != KernelModeMsg
.lParam
,
1208 ObDereferenceObject( peThread
);
1211 SetLastNtError( Status
);
1217 NtUserQuerySendMessage(DWORD Unknown0
)
1225 IntSendMessage(HWND hWnd
,
1230 ULONG_PTR Result
= 0;
1231 if(IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1233 return (LRESULT
)Result
;
1238 static LRESULT FASTCALL
1239 IntSendMessageTimeoutSingle(HWND hWnd
,
1249 PWINDOW_OBJECT Window
;
1250 PMSGMEMORY MsgMemoryEntry
;
1251 INT lParamBufferSize
;
1252 LPARAM lParamPacked
;
1253 PW32THREAD Win32Thread
;
1255 /* FIXME: Call hooks. */
1256 Window
= IntGetWindowObject(hWnd
);
1259 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1263 Win32Thread
= PsGetWin32Thread();
1265 if (NULL
!= Win32Thread
&&
1266 Window
->MessageQueue
== Win32Thread
->MessageQueue
)
1268 if (Win32Thread
->IsExiting
)
1270 /* Never send messages to exiting threads */
1271 IntReleaseWindowObject(Window
);
1275 /* See if this message type is present in the table */
1276 MsgMemoryEntry
= FindMsgMemory(Msg
);
1277 if (NULL
== MsgMemoryEntry
)
1279 lParamBufferSize
= -1;
1283 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1286 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
)))
1288 IntReleaseWindowObject(Window
);
1289 DPRINT1("Failed to pack message parameters\n");
1292 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
1294 Result
= (ULONG_PTR
)IntCallWindowProc(Window
->WndProcW
, FALSE
, hWnd
, Msg
, wParam
,
1295 lParamPacked
,lParamBufferSize
);
1299 Result
= (ULONG_PTR
)IntCallWindowProc(Window
->WndProcA
, TRUE
, hWnd
, Msg
, wParam
,
1300 lParamPacked
,lParamBufferSize
);
1308 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
)))
1310 IntReleaseWindowObject(Window
);
1311 DPRINT1("Failed to unpack message parameters\n");
1315 IntReleaseWindowObject(Window
);
1319 if(uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->MessageQueue
))
1321 IntReleaseWindowObject(Window
);
1322 /* FIXME - Set a LastError? */
1326 if(Window
->Status
& WINDOWSTATUS_DESTROYING
)
1328 IntReleaseWindowObject(Window
);
1329 /* FIXME - last error? */
1330 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd
);
1334 Status
= MsqSendMessage(Window
->MessageQueue
, hWnd
, Msg
, wParam
, lParam
,
1335 uTimeout
, (uFlags
& SMTO_BLOCK
), uResult
);
1336 IntReleaseWindowObject(Window
);
1337 if (STATUS_TIMEOUT
== Status
)
1339 /* MSDN says GetLastError() should return 0 after timeout */
1340 SetLastWin32Error(0);
1343 else if (! NT_SUCCESS(Status
))
1345 SetLastNtError(Status
);
1353 IntSendMessageTimeout(HWND hWnd
,
1361 PWINDOW_OBJECT DesktopWindow
;
1365 if (HWND_BROADCAST
!= hWnd
)
1367 return IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1370 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
1371 if (NULL
== DesktopWindow
)
1373 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1376 Children
= IntWinListChildren(DesktopWindow
);
1377 IntReleaseWindowObject(DesktopWindow
);
1378 if (NULL
== Children
)
1383 for (Child
= Children
; NULL
!= *Child
; Child
++)
1385 IntSendMessageTimeoutSingle(*Child
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1388 ExFreePool(Children
);
1390 return (LRESULT
) TRUE
;
1394 /* This function posts a message if the destination's message queue belongs to
1395 another thread, otherwise it sends the message. It does not support broadcast
1398 IntPostOrSendMessage(HWND hWnd
,
1404 PWINDOW_OBJECT Window
;
1406 if(hWnd
== HWND_BROADCAST
)
1411 Window
= IntGetWindowObject(hWnd
);
1414 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1418 if(Window
->MessageQueue
!= PsGetWin32Thread()->MessageQueue
)
1420 Result
= NtUserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1424 if(!IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1430 IntReleaseWindowObject(Window
);
1432 return (LRESULT
)Result
;
1436 IntDoSendMessage(HWND Wnd
,
1441 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1443 LRESULT Result
= TRUE
;
1445 PWINDOW_OBJECT Window
;
1446 NTUSERSENDMESSAGEINFO Info
;
1449 PMSGMEMORY MsgMemoryEntry
;
1451 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1453 /* FIXME: Call hooks. */
1454 if (HWND_BROADCAST
!= Wnd
)
1456 Window
= IntGetWindowObject(Wnd
);
1459 /* Tell usermode to not touch this one */
1460 Info
.HandledByKernel
= TRUE
;
1461 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1462 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1467 /* FIXME: Check for an exiting window. */
1469 /* See if the current thread can handle the message */
1470 if (HWND_BROADCAST
!= Wnd
&& NULL
!= PsGetWin32Thread() &&
1471 Window
->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1473 /* Gather the information usermode needs to call the window proc directly */
1474 Info
.HandledByKernel
= FALSE
;
1475 if (0xFFFF0000 != ((DWORD
) Window
->WndProcW
& 0xFFFF0000))
1477 if (0xFFFF0000 != ((DWORD
) Window
->WndProcA
& 0xFFFF0000))
1479 /* Both Unicode and Ansi winprocs are real, see what usermode prefers */
1480 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
),
1482 if (! NT_SUCCESS(Status
))
1484 Info
.Ansi
= ! Window
->Unicode
;
1486 Info
.Proc
= (Info
.Ansi
? Window
->WndProcA
: Window
->WndProcW
);
1490 /* Real Unicode winproc */
1492 Info
.Proc
= Window
->WndProcW
;
1497 /* Must have real Ansi winproc */
1499 Info
.Proc
= Window
->WndProcA
;
1501 IntReleaseWindowObject(Window
);
1505 /* Must be handled by other thread */
1506 if (HWND_BROADCAST
!= Wnd
)
1508 IntReleaseWindowObject(Window
);
1510 Info
.HandledByKernel
= TRUE
;
1511 UserModeMsg
.hwnd
= Wnd
;
1512 UserModeMsg
.message
= Msg
;
1513 UserModeMsg
.wParam
= wParam
;
1514 UserModeMsg
.lParam
= lParam
;
1515 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1516 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1517 if (! NT_SUCCESS(Status
))
1519 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1520 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1521 return (dsm
? 0 : -1);
1525 Result
= IntSendMessage(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1526 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
);
1530 Result
= IntSendMessageTimeout(KernelModeMsg
.hwnd
, KernelModeMsg
.message
,
1531 KernelModeMsg
.wParam
, KernelModeMsg
.lParam
,
1532 dsm
->uFlags
, dsm
->uTimeout
, &dsm
->Result
);
1534 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1535 if (! NT_SUCCESS(Status
))
1537 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1538 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1539 return(dsm
? 0 : -1);
1543 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1544 if (! NT_SUCCESS(Status
))
1546 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1549 return (LRESULT
)Result
;
1553 NtUserSendMessageTimeout(HWND hWnd
,
1560 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1565 dsm
.uFlags
= uFlags
;
1566 dsm
.uTimeout
= uTimeout
;
1567 Result
= IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
1568 if(uResult
!= NULL
&& Result
!= 0)
1572 Status
= MmCopyToCaller(uResult
, &dsm
.Result
, sizeof(ULONG_PTR
));
1573 if(!NT_SUCCESS(Status
))
1575 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1583 NtUserSendMessage(HWND Wnd
,
1587 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1589 return IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
);
1593 NtUserSendMessageCallback(HWND hWnd
,
1597 SENDASYNCPROC lpCallBack
,
1606 NtUserSendNotifyMessage(HWND hWnd
,
1617 NtUserWaitMessage(VOID
)
1620 return IntWaitMessage(NULL
, 0, 0);
1624 NtUserGetQueueStatus(BOOL ClearChanges
)
1626 PUSER_MESSAGE_QUEUE Queue
;
1629 Queue
= PsGetWin32Thread()->MessageQueue
;
1631 IntLockMessageQueue(Queue
);
1633 Result
= MAKELONG(Queue
->QueueBits
, Queue
->ChangedBits
);
1636 Queue
->ChangedBits
= 0;
1639 IntUnLockMessageQueue(Queue
);
1645 IntInitMessagePumpHook()
1647 PsGetCurrentThread()->Tcb
.Win32Thread
->MessagePumpHookValue
++;
1652 IntUninitMessagePumpHook()
1654 if (PsGetCurrentThread()->Tcb
.Win32Thread
->MessagePumpHookValue
<= 0)
1658 PsGetCurrentThread()->Tcb
.Win32Thread
->MessagePumpHookValue
--;