2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
5 * FILE: subsys/win32k/ntuser/message.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * 06-06-2001 CSH Created
11 /* INCLUDES ******************************************************************/
18 BOOLEAN NTAPI
PsGetProcessExitProcessCalled(PEPROCESS Process
);
20 #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
28 DOSENDMESSAGE
, *PDOSENDMESSAGE
;
30 /* FUNCTIONS *****************************************************************/
33 IntInitMessageImpl(VOID
)
35 return STATUS_SUCCESS
;
39 IntCleanupMessageImpl(VOID
)
41 return STATUS_SUCCESS
;
44 #define MMS_SIZE_WPARAM -1
45 #define MMS_SIZE_WPARAMWCHAR -2
46 #define MMS_SIZE_LPARAMSZ -3
47 #define MMS_SIZE_SPECIAL -4
48 #define MMS_FLAG_READ 0x01
49 #define MMS_FLAG_WRITE 0x02
50 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
51 typedef struct tagMSGMEMORY
57 MSGMEMORY
, *PMSGMEMORY
;
59 static MSGMEMORY MsgMemory
[] =
61 { WM_CREATE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
62 { WM_DDE_ACK
, sizeof(KMDDELPARAM
), MMS_FLAG_READ
},
63 { WM_DDE_EXECUTE
, MMS_SIZE_WPARAM
, MMS_FLAG_READ
},
64 { WM_GETMINMAXINFO
, sizeof(MINMAXINFO
), MMS_FLAG_READWRITE
},
65 { WM_GETTEXT
, MMS_SIZE_WPARAMWCHAR
, MMS_FLAG_WRITE
},
66 { WM_NCCALCSIZE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
67 { WM_NCCREATE
, MMS_SIZE_SPECIAL
, MMS_FLAG_READWRITE
},
68 { WM_SETTEXT
, MMS_SIZE_LPARAMSZ
, MMS_FLAG_READ
},
69 { WM_STYLECHANGED
, sizeof(STYLESTRUCT
), MMS_FLAG_READ
},
70 { WM_STYLECHANGING
, sizeof(STYLESTRUCT
), MMS_FLAG_READWRITE
},
71 { WM_COPYDATA
, MMS_SIZE_SPECIAL
, MMS_FLAG_READ
},
72 { WM_WINDOWPOSCHANGED
, sizeof(WINDOWPOS
), MMS_FLAG_READ
},
73 { WM_WINDOWPOSCHANGING
, sizeof(WINDOWPOS
), MMS_FLAG_READWRITE
},
76 static PMSGMEMORY FASTCALL
77 FindMsgMemory(UINT Msg
)
79 PMSGMEMORY MsgMemoryEntry
;
81 /* See if this message type is present in the table */
82 for (MsgMemoryEntry
= MsgMemory
;
83 MsgMemoryEntry
< MsgMemory
+ sizeof(MsgMemory
) / sizeof(MSGMEMORY
);
86 if (Msg
== MsgMemoryEntry
->Message
)
88 return MsgMemoryEntry
;
96 MsgMemorySize(PMSGMEMORY MsgMemoryEntry
, WPARAM wParam
, LPARAM lParam
)
99 PUNICODE_STRING WindowName
;
100 PUNICODE_STRING ClassName
;
105 if (MMS_SIZE_WPARAM
== MsgMemoryEntry
->Size
)
109 else if (MMS_SIZE_WPARAMWCHAR
== MsgMemoryEntry
->Size
)
111 Size
= (UINT
) (wParam
* sizeof(WCHAR
));
113 else if (MMS_SIZE_LPARAMSZ
== MsgMemoryEntry
->Size
)
115 Size
= (UINT
) ((wcslen((PWSTR
) lParam
) + 1) * sizeof(WCHAR
));
117 else if (MMS_SIZE_SPECIAL
== MsgMemoryEntry
->Size
)
119 switch(MsgMemoryEntry
->Message
)
123 Cs
= (CREATESTRUCTW
*) lParam
;
124 WindowName
= (PUNICODE_STRING
) Cs
->lpszName
;
125 ClassName
= (PUNICODE_STRING
) Cs
->lpszClass
;
126 Size
= sizeof(CREATESTRUCTW
) + WindowName
->Length
+ sizeof(WCHAR
);
127 if (IS_ATOM(ClassName
->Buffer
))
129 Size
+= sizeof(WCHAR
) + sizeof(ATOM
);
133 Size
+= sizeof(WCHAR
) + ClassName
->Length
+ sizeof(WCHAR
);
138 Size
= wParam
? sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
) : sizeof(RECT
);
142 Size
= sizeof(COPYDATASTRUCT
) + ((PCOPYDATASTRUCT
)lParam
)->cbData
;
145 case WM_COPYGLOBALDATA
:
157 Size
= MsgMemoryEntry
->Size
;
160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
162 DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
170 PackParam(LPARAM
*lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, BOOL NonPagedPoolNeeded
)
172 NCCALCSIZE_PARAMS
*UnpackedNcCalcsize
;
173 NCCALCSIZE_PARAMS
*PackedNcCalcsize
;
174 CREATESTRUCTW
*UnpackedCs
;
175 CREATESTRUCTW
*PackedCs
;
176 PLARGE_STRING WindowName
;
177 PUNICODE_STRING ClassName
;
182 *lParamPacked
= lParam
;
184 if (NonPagedPoolNeeded
)
185 PoolType
= NonPagedPool
;
187 PoolType
= PagedPool
;
189 if (WM_NCCALCSIZE
== Msg
&& wParam
)
192 UnpackedNcCalcsize
= (NCCALCSIZE_PARAMS
*) lParam
;
193 PackedNcCalcsize
= ExAllocatePoolWithTag(PoolType
,
194 sizeof(NCCALCSIZE_PARAMS
) + sizeof(WINDOWPOS
),
197 if (NULL
== PackedNcCalcsize
)
199 DPRINT1("Not enough memory to pack lParam\n");
200 return STATUS_NO_MEMORY
;
202 RtlCopyMemory(PackedNcCalcsize
, UnpackedNcCalcsize
, sizeof(NCCALCSIZE_PARAMS
));
203 PackedNcCalcsize
->lppos
= (PWINDOWPOS
) (PackedNcCalcsize
+ 1);
204 RtlCopyMemory(PackedNcCalcsize
->lppos
, UnpackedNcCalcsize
->lppos
, sizeof(WINDOWPOS
));
205 *lParamPacked
= (LPARAM
) PackedNcCalcsize
;
207 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
209 UnpackedCs
= (CREATESTRUCTW
*) lParam
;
210 WindowName
= (PLARGE_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(PoolType
, 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 else if (PoolType
== NonPagedPool
)
257 PMSGMEMORY MsgMemoryEntry
;
260 MsgMemoryEntry
= FindMsgMemory(Msg
);
262 if ((!MsgMemoryEntry
) || (MsgMemoryEntry
->Size
< 0))
264 /* Keep previous behavior */
265 return STATUS_SUCCESS
;
267 PackedData
= ExAllocatePoolWithTag(NonPagedPool
, MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
), TAG_MSG
);
268 RtlCopyMemory(PackedData
, (PVOID
)lParam
, MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
));
269 *lParamPacked
= (LPARAM
)PackedData
;
272 return STATUS_SUCCESS
;
276 UnpackParam(LPARAM lParamPacked
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, BOOL NonPagedPoolUsed
)
278 NCCALCSIZE_PARAMS
*UnpackedParams
;
279 NCCALCSIZE_PARAMS
*PackedParams
;
280 PWINDOWPOS UnpackedWindowPos
;
282 if (lParamPacked
== lParam
)
284 return STATUS_SUCCESS
;
287 if (WM_NCCALCSIZE
== Msg
&& wParam
)
289 PackedParams
= (NCCALCSIZE_PARAMS
*) lParamPacked
;
290 UnpackedParams
= (NCCALCSIZE_PARAMS
*) lParam
;
291 UnpackedWindowPos
= UnpackedParams
->lppos
;
292 RtlCopyMemory(UnpackedParams
, PackedParams
, sizeof(NCCALCSIZE_PARAMS
));
293 UnpackedParams
->lppos
= UnpackedWindowPos
;
294 RtlCopyMemory(UnpackedWindowPos
, PackedParams
+ 1, sizeof(WINDOWPOS
));
295 ExFreePool((PVOID
) lParamPacked
);
297 return STATUS_SUCCESS
;
299 else if (WM_CREATE
== Msg
|| WM_NCCREATE
== Msg
)
301 ExFreePool((PVOID
) lParamPacked
);
303 return STATUS_SUCCESS
;
305 else if (NonPagedPoolUsed
)
307 PMSGMEMORY MsgMemoryEntry
;
308 MsgMemoryEntry
= FindMsgMemory(Msg
);
309 if (MsgMemoryEntry
->Size
< 0)
311 /* Keep previous behavior */
312 return STATUS_INVALID_PARAMETER
;
315 if (MsgMemory
->Flags
== MMS_FLAG_READWRITE
)
317 //RtlCopyMemory((PVOID)lParam, (PVOID)lParamPacked, MsgMemory->Size);
319 ExFreePool((PVOID
) lParamPacked
);
320 return STATUS_SUCCESS
;
325 return STATUS_INVALID_PARAMETER
;
329 // Wakeup any thread/process waiting on idle input.
334 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
335 PUSER_MESSAGE_QUEUE ForegroundQueue
;
336 PTHREADINFO pti
, ptiForeground
= NULL
;
338 ForegroundQueue
= IntGetFocusMessageQueue();
341 ptiForeground
= ForegroundQueue
->Thread
->Tcb
.Win32Thread
;
343 pti
= PsGetCurrentThreadWin32Thread();
345 if ( pti
&& pti
->pDeskInfo
&& pti
== ptiForeground
)
347 if ( pti
->fsHooks
& HOOKID_TO_FLAG(WH_FOREGROUNDIDLE
) ||
348 pti
->pDeskInfo
->fsHooks
& HOOKID_TO_FLAG(WH_FOREGROUNDIDLE
) )
350 co_HOOK_CallHooks(WH_FOREGROUNDIDLE
,HC_ACTION
,0,0);
354 DPRINT("IdlePing ppi 0x%x\n",ppi
);
355 if ( ppi
&& ppi
->InputIdleEvent
)
357 DPRINT("InputIdleEvent\n");
358 KeSetEvent( ppi
->InputIdleEvent
, IO_NO_INCREMENT
, FALSE
);
365 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
367 DPRINT("IdlePong ppi 0x%x\n",ppi
);
368 if ( ppi
&& ppi
->InputIdleEvent
)
370 KeClearEvent(ppi
->InputIdleEvent
);
375 IntCallWndProc( PWND Window
, HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
377 BOOL SameThread
= FALSE
;
380 if (Window
->head
.pti
== ((PTHREADINFO
)PsGetCurrentThreadWin32Thread()))
387 co_HOOK_CallHooks( WH_CALLWNDPROC
, HC_ACTION
, SameThread
, (LPARAM
)&CWP
);
391 IntCallWndProcRet ( PWND Window
, HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*uResult
)
393 BOOL SameThread
= FALSE
;
396 if (Window
->head
.pti
== ((PTHREADINFO
)PsGetCurrentThreadWin32Thread()))
401 CWPR
.wParam
= wParam
;
402 CWPR
.lParam
= lParam
;
403 CWPR
.lResult
= *uResult
;
404 co_HOOK_CallHooks( WH_CALLWNDPROCRET
, HC_ACTION
, SameThread
, (LPARAM
)&CWPR
);
408 IntDispatchMessage(PMSG pMsg
)
410 LARGE_INTEGER TickCount
;
413 PMSGMEMORY MsgMemoryEntry
;
414 INT lParamBufferSize
;
421 Window
= UserGetWindowObject(pMsg
->hwnd
);
422 if (!Window
) return 0;
425 pti
= PsGetCurrentThreadWin32Thread();
427 if (((pMsg
->message
== WM_SYSTIMER
) ||
428 (pMsg
->message
== WM_TIMER
)) &&
431 if (pMsg
->message
== WM_TIMER
)
433 ObReferenceObject(pti
->pEThread
);
434 if (ValidateTimerCallback(pti
,pMsg
->lParam
))
436 KeQueryTickCount(&TickCount
);
437 Time
= MsqCalculateMessageTime(&TickCount
);
438 retval
= co_IntCallWindowProc((WNDPROC
)pMsg
->lParam
,
446 ObDereferenceObject(pti
->pEThread
);
451 PTIMER pTimer
= FindSystemTimer(pMsg
);
452 if (pTimer
&& pTimer
->pfn
)
454 KeQueryTickCount(&TickCount
);
455 Time
= MsqCalculateMessageTime(&TickCount
);
456 pTimer
->pfn(pMsg
->hwnd
, WM_SYSTIMER
, (UINT
)pMsg
->wParam
, Time
);
462 if ( !Window
) return 0;
464 /* See if this message type is present in the table */
465 MsgMemoryEntry
= FindMsgMemory(pMsg
->message
);
466 if ( !MsgMemoryEntry
)
468 lParamBufferSize
= -1;
472 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, pMsg
->wParam
, pMsg
->lParam
);
475 if (! NT_SUCCESS(PackParam(&lParamPacked
, pMsg
->message
, pMsg
->wParam
, pMsg
->lParam
, FALSE
)))
477 DPRINT1("Failed to pack message parameters\n");
480 ObReferenceObject(pti
->pEThread
);
481 retval
= co_IntCallWindowProc( Window
->lpfnWndProc
,
489 if (! NT_SUCCESS(UnpackParam(lParamPacked
, pMsg
->message
, pMsg
->wParam
, pMsg
->lParam
, FALSE
)))
491 DPRINT1("Failed to unpack message parameters\n");
494 if (pMsg
->message
== WM_PAINT
)
496 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
497 HRGN hrgn
= IntSysCreateRectRgn( 0, 0, 0, 0 );
498 co_UserGetUpdateRgn( Window
, hrgn
, TRUE
);
499 REGION_FreeRgnByHandle( hrgn
);
501 ObDereferenceObject(pti
->pEThread
);
506 co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue
, LPMSG Msg
)
508 if(!Msg
->hwnd
|| ThreadQueue
->CaptureWindow
)
517 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
522 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
529 case WM_LBUTTONDBLCLK
:
530 case WM_MBUTTONDBLCLK
:
531 case WM_RBUTTONDBLCLK
:
532 case WM_XBUTTONDBLCLK
:
535 PSYSTEM_CURSORINFO CurInfo
;
536 CurInfo
= IntGetSysCursorInfo();
538 wParam
= (WPARAM
)(CurInfo
->ButtonsDown
);
540 co_IntSendMessage(Msg
->hwnd
, WM_MOUSEMOVE
, wParam
, Msg
->lParam
);
541 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(HTCLIENT
, Msg
->message
));
544 case WM_NCLBUTTONDOWN
:
545 case WM_NCMBUTTONDOWN
:
546 case WM_NCRBUTTONDOWN
:
547 case WM_NCXBUTTONDOWN
:
548 case WM_NCLBUTTONDBLCLK
:
549 case WM_NCMBUTTONDBLCLK
:
550 case WM_NCRBUTTONDBLCLK
:
551 case WM_NCXBUTTONDBLCLK
:
553 co_IntSendMessage(Msg
->hwnd
, WM_NCMOUSEMOVE
, (WPARAM
)Msg
->wParam
, Msg
->lParam
);
554 co_IntSendMessage(Msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(Msg
->wParam
, Msg
->message
));
561 co_IntActivateWindowMouse( PUSER_MESSAGE_QUEUE ThreadQueue
,
569 ASSERT_REFS_CO(MsgWindow
);
571 if(*HitTest
== (USHORT
)HTTRANSPARENT
)
573 /* eat the message, search again! */
577 Parent
= IntGetParent(MsgWindow
);//fixme: deref retval?
579 /* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
580 Result
= co_IntSendMessage(MsgWindow
->head
.h
,
582 (WPARAM
) (Parent
? Parent
->head
.h
: MsgWindow
->head
.h
),
583 (LPARAM
)MAKELONG(*HitTest
, Msg
->message
)
588 case MA_NOACTIVATEANDEAT
:
592 case MA_ACTIVATEANDEAT
:
593 co_IntMouseActivateWindow(MsgWindow
);
597 co_IntMouseActivateWindow(MsgWindow
);
605 co_IntTranslateMouseMessage( PUSER_MESSAGE_QUEUE ThreadQueue
,
611 USER_REFERENCE_ENTRY Ref
, DesktopRef
;
613 if(!(Window
= UserGetWindowObject(Msg
->hwnd
)))
615 /* let's just eat the message?! */
621 UserRefObjectCo(Window
, &Ref
);
623 if ( ThreadQueue
== Window
->head
.pti
->MessageQueue
&&
624 ThreadQueue
->CaptureWindow
!= Window
->head
.h
)
626 /* only send WM_NCHITTEST messages if we're not capturing the window! */
629 *HitTest
= co_IntSendMessage(Window
->head
.h
, WM_NCHITTEST
, 0,
630 MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
));
632 /* else we are going to see this message again, but then with Remove == TRUE */
634 if (*HitTest
== (USHORT
)HTTRANSPARENT
)
637 HWND hDesktop
= IntGetDesktopWindow();
639 if ((DesktopWindow
= UserGetWindowObject(hDesktop
)))
643 UserRefObjectCo(DesktopWindow
, &DesktopRef
);
645 co_WinPosWindowFromPoint(DesktopWindow
, Window
->head
.pti
->MessageQueue
, &Msg
->pt
, &Wnd
);
650 /* post the message to the other window */
651 Msg
->hwnd
= Wnd
->head
.h
;
652 if(!(Wnd
->state
& WNDS_DESTROYED
))
654 MsqPostMessage(Wnd
->head
.pti
->MessageQueue
, Msg
, FALSE
,
655 Msg
->message
== WM_MOUSEMOVE
? QS_MOUSEMOVE
:
659 /* eat the message */
660 UserDereferenceObject(Wnd
);
661 UserDerefObjectCo(DesktopWindow
);
662 UserDerefObjectCo(Window
);
665 UserDereferenceObject(Wnd
);
668 UserDerefObjectCo(DesktopWindow
);
673 if ( gspv
.bMouseClickLock
&&
674 ((Msg
->message
== WM_LBUTTONUP
) ||
675 (Msg
->message
== WM_LBUTTONDOWN
) ) )
677 if (MsqIsClkLck(Msg
, Remove
))
679 // FIXME: drop the message, hack: use WM_NULL
680 Msg
->message
= WM_NULL
;
684 if (IS_BTN_MESSAGE(Msg
->message
, DOWN
))
686 /* generate double click messages, if necessary */
687 if ((((*HitTest
) != HTCLIENT
) ||
688 (Window
->pcls
->style
& CS_DBLCLKS
)) &&
689 MsqIsDblClk(Msg
, Remove
))
691 Msg
->message
+= WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
;
695 if(Msg
->message
!= WM_MOUSEWHEEL
)
698 if ((*HitTest
) != HTCLIENT
)
700 Msg
->message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
701 if ( (Msg
->message
== WM_NCRBUTTONUP
) &&
702 (((*HitTest
) == HTCAPTION
) || ((*HitTest
) == HTSYSMENU
)) )
704 Msg
->message
= WM_CONTEXTMENU
;
705 Msg
->wParam
= (WPARAM
)Window
->head
.h
;
709 Msg
->wParam
= *HitTest
;
711 Msg
->lParam
= MAKELONG(Msg
->pt
.x
, Msg
->pt
.y
);
713 else if ( ThreadQueue
->MoveSize
== NULL
&&
714 ThreadQueue
->MenuOwner
== NULL
)
716 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
717 Msg
->lParam
= MAKELONG(
718 Msg
->pt
.x
- (WORD
)Window
->rcClient
.left
,
719 Msg
->pt
.y
- (WORD
)Window
->rcClient
.top
);
723 UserDerefObjectCo(Window
);
727 BOOL
ProcessMouseMessage(MSG
* Msg
, BOOLEAN RemoveMessages
)
729 MOUSEHOOKSTRUCT MHook
;
732 PUSER_MESSAGE_QUEUE ThreadQueue
;
733 USER_REFERENCE_ENTRY Ref
;
734 USHORT HitTest
= HTNOWHERE
;
736 pti
= PsGetCurrentThreadWin32Thread();
737 ThreadQueue
= pti
->MessageQueue
;
741 PWND MsgWindow
= NULL
;
743 /* Mouse message process */
746 ( MsgWindow
= UserGetWindowObject(Msg
->hwnd
) ) &&
747 Msg
->message
>= WM_MOUSEFIRST
&&
748 Msg
->message
<= WM_MOUSELAST
)
752 UserRefObjectCo(MsgWindow
, &Ref
);
754 if ( co_IntTranslateMouseMessage( ThreadQueue
,
758 /* FIXME - check message filter again, if the message doesn't match anymore,
761 UserDerefObjectCo(MsgWindow
);
762 /* eat the message, search again */
766 if(ThreadQueue
->CaptureWindow
== NULL
)
768 co_IntSendHitTestMessages(ThreadQueue
, Msg
);
770 if ( ( Msg
->message
!= WM_MOUSEMOVE
&&
771 Msg
->message
!= WM_NCMOUSEMOVE
) &&
772 IS_BTN_MESSAGE(Msg
->message
, DOWN
) &&
773 co_IntActivateWindowMouse(ThreadQueue
, Msg
, MsgWindow
, &HitTest
) )
775 UserDerefObjectCo(MsgWindow
);
776 /* eat the message, search again */
781 UserDerefObjectCo(MsgWindow
);
785 co_IntSendHitTestMessages(ThreadQueue
, Msg
);
792 Msg
->message
>= WM_MOUSEFIRST
&&
793 Msg
->message
<= WM_MOUSELAST
) &&
794 co_IntTranslateMouseMessage( ThreadQueue
,
798 /* FIXME - check message filter again, if the message doesn't match anymore,
801 /* eat the message, search again */
805 pti
->rpdesk
->htEx
= HitTest
; /* Now set the capture hit. */
807 Event
.message
= Msg
->message
;
808 Event
.time
= Msg
->time
;
809 Event
.hwnd
= Msg
->hwnd
;
810 Event
.paramL
= Msg
->pt
.x
;
811 Event
.paramH
= Msg
->pt
.y
;
812 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
816 MHook
.hwnd
= Msg
->hwnd
;
817 MHook
.wHitTestCode
= HitTest
;
818 MHook
.dwExtraInfo
= 0;
819 if (co_HOOK_CallHooks( WH_MOUSE
,
820 RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
825 MHook
.hwnd
= Msg
->hwnd
;
826 MHook
.wHitTestCode
= HitTest
;
827 MHook
.dwExtraInfo
= 0;
828 co_HOOK_CallHooks( WH_CBT
,
832 DPRINT1("MouseMessage WH_CBT Call Hook return!\n");
839 BOOL
ProcessKeyboardMessage(MSG
* Msg
, BOOLEAN RemoveMessages
)
843 Event
.message
= Msg
->message
;
844 Event
.hwnd
= Msg
->hwnd
;
845 Event
.time
= Msg
->time
;
846 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
847 Event
.paramH
= Msg
->lParam
& 0x7FFF;
848 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
849 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
851 if (co_HOOK_CallHooks( WH_KEYBOARD
,
852 RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
856 /* skip this message */
857 co_HOOK_CallHooks( WH_CBT
,
861 DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
867 BOOL
ProcessHardwareMessage(MSG
* Msg
, BOOLEAN RemoveMessages
)
869 if ( IS_MOUSE_MESSAGE(Msg
->message
))
871 if (!ProcessMouseMessage(Msg
, RemoveMessages
))
876 else if ( IS_KBD_MESSAGE(Msg
->message
))
878 if(!ProcessKeyboardMessage(Msg
, RemoveMessages
))
887 * Internal version of PeekMessage() doing all the work
890 co_IntPeekMessage( PMSG Msg
,
897 LARGE_INTEGER LargeTickCount
;
898 PUSER_MESSAGE_QUEUE ThreadQueue
;
901 pti
= PsGetCurrentThreadWin32Thread();
902 ThreadQueue
= pti
->MessageQueue
;
904 RemoveMessages
= RemoveMsg
& PM_REMOVE
;
910 KeQueryTickCount(&LargeTickCount
);
911 ThreadQueue
->LastMsgRead
= LargeTickCount
.u
.LowPart
;
913 /* Dispatch sent messages here. */
914 while (co_MsqDispatchOneSentMessage(ThreadQueue
)) ;
916 /* Now look for a quit message. */
918 if (ThreadQueue
->QuitPosted
)
920 /* According to the PSDK, WM_QUIT messages are always returned, regardless
921 of the filter specified */
923 Msg
->message
= WM_QUIT
;
924 Msg
->wParam
= ThreadQueue
->QuitExitCode
;
928 ThreadQueue
->QuitPosted
= FALSE
;
934 /* Now check for normal messages. */
935 if (MsqPeekMessage( ThreadQueue
,
945 /* Check for hardware events. */
946 if(co_MsqPeekHardwareMessage( ThreadQueue
,
954 if(!ProcessHardwareMessage(Msg
, RemoveMessages
))
960 /* Check for sent messages again. */
961 while (co_MsqDispatchOneSentMessage(ThreadQueue
))
964 /* Check for paint messages. */
965 if( IntGetPaintMessage( Window
,
975 if (PostTimerMessages(Window
))
987 static NTSTATUS FASTCALL
988 CopyMsgToKernelMem(MSG
*KernelModeMsg
, MSG
*UserModeMsg
, PMSGMEMORY MsgMemoryEntry
)
995 *KernelModeMsg
= *UserModeMsg
;
997 /* See if this message type is present in the table */
998 if (NULL
== MsgMemoryEntry
)
1000 /* Not present, no copying needed */
1001 return STATUS_SUCCESS
;
1004 /* Determine required size */
1005 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1009 /* Allocate kernel mem */
1010 KernelMem
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_MSG
);
1011 if (NULL
== KernelMem
)
1013 DPRINT1("Not enough memory to copy message to kernel mem\n");
1014 return STATUS_NO_MEMORY
;
1016 KernelModeMsg
->lParam
= (LPARAM
) KernelMem
;
1018 /* Copy data if required */
1019 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_READ
))
1021 Status
= MmCopyFromCaller(KernelMem
, (PVOID
) UserModeMsg
->lParam
, Size
);
1022 if (! NT_SUCCESS(Status
))
1024 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1025 ExFreePoolWithTag(KernelMem
, TAG_MSG
);
1031 /* Make sure we don't pass any secrets to usermode */
1032 RtlZeroMemory(KernelMem
, Size
);
1037 KernelModeMsg
->lParam
= 0;
1040 return STATUS_SUCCESS
;
1043 static NTSTATUS FASTCALL
1044 CopyMsgToUserMem(MSG
*UserModeMsg
, MSG
*KernelModeMsg
)
1047 PMSGMEMORY MsgMemoryEntry
;
1050 /* See if this message type is present in the table */
1051 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
->message
);
1052 if (NULL
== MsgMemoryEntry
)
1054 /* Not present, no copying needed */
1055 return STATUS_SUCCESS
;
1058 /* Determine required size */
1059 Size
= MsgMemorySize(MsgMemoryEntry
, UserModeMsg
->wParam
, UserModeMsg
->lParam
);
1063 /* Copy data if required */
1064 if (0 != (MsgMemoryEntry
->Flags
& MMS_FLAG_WRITE
))
1066 Status
= MmCopyToCaller((PVOID
) UserModeMsg
->lParam
, (PVOID
) KernelModeMsg
->lParam
, Size
);
1067 if (! NT_SUCCESS(Status
))
1069 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1070 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1075 ExFreePool((PVOID
) KernelModeMsg
->lParam
);
1078 return STATUS_SUCCESS
;
1081 static BOOL FASTCALL
1082 co_IntWaitMessage( PWND Window
,
1087 PUSER_MESSAGE_QUEUE ThreadQueue
;
1088 NTSTATUS Status
= STATUS_SUCCESS
;
1091 pti
= PsGetCurrentThreadWin32Thread();
1092 ThreadQueue
= pti
->MessageQueue
;
1096 if ( co_IntPeekMessage( &Msg
,
1105 /* Nothing found. Wait for new messages. */
1106 Status
= co_MsqWaitForNewMessages( ThreadQueue
,
1111 while ( (STATUS_WAIT_0
<= Status
&& Status
<= STATUS_WAIT_63
) ||
1112 STATUS_TIMEOUT
== Status
);
1114 if (!NT_SUCCESS(Status
))
1116 SetLastNtError(Status
);
1117 DPRINT1("Exit co_IntWaitMessage on error!\n");
1124 co_IntGetPeekMessage( PMSG pMsg
,
1132 BOOL Present
= FALSE
;
1134 if ( hWnd
== HWND_TOPMOST
|| hWnd
== HWND_BROADCAST
)
1137 /* Validate input */
1138 if (hWnd
&& hWnd
!= HWND_BOTTOM
)
1140 if (!(Window
= UserGetWindowObject(hWnd
)))
1150 Window
= (PWND
)hWnd
;
1153 if (MsgFilterMax
< MsgFilterMin
)
1161 Present
= co_IntPeekMessage( pMsg
,
1168 // The WH_GETMESSAGE hook enables an application to monitor messages about to
1169 // be returned by the GetMessage or PeekMessage function.
1171 co_HOOK_CallHooks( WH_GETMESSAGE
, HC_ACTION
, RemoveMsg
& PM_REMOVE
, (LPARAM
)pMsg
);
1174 return (WM_QUIT
!= pMsg
->message
);
1179 if ( !co_IntWaitMessage(Window
, MsgFilterMin
, MsgFilterMax
) )
1184 if (!(RemoveMsg
& PM_NOYIELD
))
1187 // Yield this thread!
1190 UserEnterExclusive();
1191 // Fall through to exit.
1197 while( bGMSG
&& !Present
);
1203 UserPostThreadMessage( DWORD idThread
,
1210 PTHREADINFO pThread
;
1211 LARGE_INTEGER LargeTickCount
;
1214 DPRINT1("UserPostThreadMessage wParam 0x%x lParam 0x%x\n", wParam
,lParam
);
1216 if (FindMsgMemory(Msg
) != 0)
1218 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
1222 Status
= PsLookupThreadByThreadId((HANDLE
)idThread
,&peThread
);
1224 if( Status
== STATUS_SUCCESS
)
1226 pThread
= (PTHREADINFO
)peThread
->Tcb
.Win32Thread
;
1228 !pThread
->MessageQueue
||
1229 (pThread
->TIF_flags
& TIF_INCLEANUP
))
1231 ObDereferenceObject( peThread
);
1235 Message
.hwnd
= NULL
;
1236 Message
.message
= Msg
;
1237 Message
.wParam
= wParam
;
1238 Message
.lParam
= lParam
;
1239 Message
.pt
= gpsi
->ptCursor
;
1241 KeQueryTickCount(&LargeTickCount
);
1242 pThread
->timeLast
= Message
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1243 MsqPostMessage(pThread
->MessageQueue
, &Message
, FALSE
, QS_POSTMESSAGE
);
1244 ObDereferenceObject( peThread
);
1249 SetLastNtError( Status
);
1255 UserPostMessage( HWND Wnd
,
1262 LARGE_INTEGER LargeTickCount
;
1264 if (FindMsgMemory(Msg
) != 0)
1266 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
1272 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1277 if (Wnd
== HWND_BROADCAST
)
1283 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1284 List
= IntWinListChildren(DesktopWindow
);
1288 UserPostMessage(DesktopWindow
->head
.h
, Msg
, wParam
, lParam
);
1289 for (i
= 0; List
[i
]; i
++)
1291 UserPostMessage(List
[i
], Msg
, wParam
, lParam
);
1300 Window
= UserGetWindowObject(Wnd
);
1306 pti
= Window
->head
.pti
;
1307 if ( pti
->TIF_flags
& TIF_INCLEANUP
)
1309 DPRINT1("Attempted to post message to window 0x%x when the thread is in cleanup!\n", Wnd
);
1313 if ( Window
->state
& WNDS_DESTROYED
)
1315 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd
);
1316 /* FIXME - last error code? */
1322 MsqPostQuitMessage(Window
->head
.pti
->MessageQueue
, wParam
);
1327 Message
.message
= Msg
;
1328 Message
.wParam
= wParam
;
1329 Message
.lParam
= lParam
;
1330 Message
.pt
= gpsi
->ptCursor
;
1331 KeQueryTickCount(&LargeTickCount
);
1332 pti
->timeLast
= Message
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1333 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Message
, FALSE
, QS_POSTMESSAGE
);
1341 co_IntSendMessage( HWND hWnd
,
1346 ULONG_PTR Result
= 0;
1347 if(co_IntSendMessageTimeout(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
))
1349 return (LRESULT
)Result
;
1354 static LRESULT FASTCALL
1355 co_IntSendMessageTimeoutSingle( HWND hWnd
,
1361 ULONG_PTR
*uResult
)
1365 PMSGMEMORY MsgMemoryEntry
;
1366 INT lParamBufferSize
;
1367 LPARAM lParamPacked
;
1368 PTHREADINFO Win32Thread
;
1369 ULONG_PTR Result
= 0;
1370 DECLARE_RETURN(LRESULT
);
1371 USER_REFERENCE_ENTRY Ref
;
1373 if (!(Window
= UserGetWindowObject(hWnd
)))
1378 UserRefObjectCo(Window
, &Ref
);
1380 Win32Thread
= PsGetCurrentThreadWin32Thread();
1382 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1384 if ( NULL
!= Win32Thread
&&
1385 Window
->head
.pti
->MessageQueue
== Win32Thread
->MessageQueue
)
1387 if (Win32Thread
->TIF_flags
& TIF_INCLEANUP
)
1389 /* Never send messages to exiting threads */
1393 /* See if this message type is present in the table */
1394 MsgMemoryEntry
= FindMsgMemory(Msg
);
1395 if (NULL
== MsgMemoryEntry
)
1397 lParamBufferSize
= -1;
1401 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1404 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
, FALSE
)))
1406 DPRINT1("Failed to pack message parameters\n");
1410 ObReferenceObject(Win32Thread
->pEThread
);
1411 Result
= (ULONG_PTR
)co_IntCallWindowProc( Window
->lpfnWndProc
,
1423 ObDereferenceObject(Win32Thread
->pEThread
);
1425 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1427 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
, FALSE
)))
1429 DPRINT1("Failed to unpack message parameters\n");
1436 if (uFlags
& SMTO_ABORTIFHUNG
&& MsqIsHung(Window
->head
.pti
->MessageQueue
))
1438 /* FIXME - Set a LastError? */
1442 if (Window
->state
& WNDS_DESTROYED
)
1444 /* FIXME - last error? */
1445 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd
);
1451 Status
= co_MsqSendMessage( Window
->head
.pti
->MessageQueue
,
1457 (uFlags
& SMTO_BLOCK
),
1461 while ((STATUS_TIMEOUT
== Status
) &&
1462 (uFlags
& SMTO_NOTIMEOUTIFNOTHUNG
) &&
1463 !MsqIsHung(Window
->head
.pti
->MessageQueue
));
1465 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1467 if (STATUS_TIMEOUT
== Status
)
1471 Microsoft Windows 2000: If GetLastError returns zero, then the function
1473 XP+ : If the function fails or times out, the return value is zero.
1474 To get extended error information, call GetLastError. If GetLastError
1475 returns ERROR_TIMEOUT, then the function timed out.
1477 SetLastWin32Error(ERROR_TIMEOUT
);
1480 else if (! NT_SUCCESS(Status
))
1482 SetLastNtError(Status
);
1489 if (Window
) UserDerefObjectCo(Window
);
1494 co_IntSendMessageTimeout( HWND hWnd
,
1500 ULONG_PTR
*uResult
)
1506 if (HWND_BROADCAST
!= hWnd
)
1508 return co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1511 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1512 if (NULL
== DesktopWindow
)
1514 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1518 /* Send message to the desktop window too! */
1519 co_IntSendMessageTimeoutSingle(DesktopWindow
->head
.h
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1521 Children
= IntWinListChildren(DesktopWindow
);
1522 if (NULL
== Children
)
1527 for (Child
= Children
; NULL
!= *Child
; Child
++)
1529 co_IntSendMessageTimeoutSingle(*Child
, Msg
, wParam
, lParam
, uFlags
, uTimeout
, uResult
);
1532 ExFreePool(Children
);
1534 return (LRESULT
) TRUE
;
1538 co_IntSendMessageNoWait(HWND hWnd
,
1543 ULONG_PTR Result
= 0;
1544 co_IntSendMessageWithCallBack(hWnd
,
1555 co_IntSendMessageWithCallBack( HWND hWnd
,
1559 SENDASYNCPROC CompletionCallback
,
1560 ULONG_PTR CompletionCallbackContext
,
1565 PMSGMEMORY MsgMemoryEntry
;
1566 INT lParamBufferSize
;
1567 LPARAM lParamPacked
;
1568 PTHREADINFO Win32Thread
;
1569 DECLARE_RETURN(LRESULT
);
1570 USER_REFERENCE_ENTRY Ref
;
1571 PUSER_SENT_MESSAGE Message
;
1573 if (!(Window
= UserGetWindowObject(hWnd
)))
1578 UserRefObjectCo(Window
, &Ref
);
1580 if (Window
->state
& WNDS_DESTROYED
)
1582 /* FIXME - last error? */
1583 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd
);
1587 Win32Thread
= PsGetCurrentThreadWin32Thread();
1589 IntCallWndProc( Window
, hWnd
, Msg
, wParam
, lParam
);
1591 if (Win32Thread
== NULL
)
1597 if (Win32Thread
->TIF_flags
& TIF_INCLEANUP
)
1599 /* Never send messages to exiting threads */
1603 /* See if this message type is present in the table */
1604 MsgMemoryEntry
= FindMsgMemory(Msg
);
1605 if (NULL
== MsgMemoryEntry
)
1607 lParamBufferSize
= -1;
1611 lParamBufferSize
= MsgMemorySize(MsgMemoryEntry
, wParam
, lParam
);
1614 if (! NT_SUCCESS(PackParam(&lParamPacked
, Msg
, wParam
, lParam
, Window
->head
.pti
->MessageQueue
!= Win32Thread
->MessageQueue
)))
1616 DPRINT1("Failed to pack message parameters\n");
1620 /* If this is not a callback and it can be sent now, then send it. */
1621 if ((Window
->head
.pti
->MessageQueue
== Win32Thread
->MessageQueue
) && (CompletionCallback
== NULL
))
1623 ObReferenceObject(Win32Thread
->pEThread
);
1624 Result
= (ULONG_PTR
)co_IntCallWindowProc( Window
->lpfnWndProc
,
1635 ObDereferenceObject(Win32Thread
->pEThread
);
1638 IntCallWndProcRet( Window
, hWnd
, Msg
, wParam
, lParam
, (LRESULT
*)uResult
);
1640 if ((Window
->head
.pti
->MessageQueue
== Win32Thread
->MessageQueue
) && (CompletionCallback
== NULL
))
1642 if (! NT_SUCCESS(UnpackParam(lParamPacked
, Msg
, wParam
, lParam
, FALSE
)))
1644 DPRINT1("Failed to unpack message parameters\n");
1649 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1651 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1652 return STATUS_INSUFFICIENT_RESOURCES
;
1655 Message
->Msg
.hwnd
= hWnd
;
1656 Message
->Msg
.message
= Msg
;
1657 Message
->Msg
.wParam
= wParam
;
1658 Message
->Msg
.lParam
= lParamPacked
;
1659 Message
->CompletionEvent
= NULL
;
1660 Message
->Result
= 0;
1661 Message
->SenderQueue
= NULL
; //Win32Thread->MessageQueue;
1663 IntReferenceMessageQueue(Window
->head
.pti
->MessageQueue
);
1664 Message
->CompletionCallback
= CompletionCallback
;
1665 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
1666 Message
->HookMessage
= MSQ_NORMAL
| MSQ_SENTNOWAIT
;
1667 Message
->HasPackedLParam
= (lParamBufferSize
> 0);
1669 InsertTailList(&Window
->head
.pti
->MessageQueue
->SentMessagesListHead
, &Message
->ListEntry
);
1670 IntDereferenceMessageQueue(Window
->head
.pti
->MessageQueue
);
1675 if (Window
) UserDerefObjectCo(Window
);
1679 /* This function posts a message if the destination's message queue belongs to
1680 another thread, otherwise it sends the message. It does not support broadcast
1683 co_IntPostOrSendMessage( HWND hWnd
,
1692 if ( hWnd
== HWND_BROADCAST
)
1697 if(!(Window
= UserGetWindowObject(hWnd
)))
1702 pti
= PsGetCurrentThreadWin32Thread();
1704 if ( Window
->head
.pti
->MessageQueue
!= pti
->MessageQueue
&&
1705 FindMsgMemory(Msg
) == 0 )
1707 Result
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1711 if ( !co_IntSendMessageTimeoutSingle(hWnd
, Msg
, wParam
, lParam
, SMTO_NORMAL
, 0, &Result
) )
1717 return (LRESULT
)Result
;
1721 co_IntDoSendMessage( HWND hWnd
,
1726 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
1729 LRESULT Result
= TRUE
;
1732 NTUSERSENDMESSAGEINFO Info
;
1735 PMSGMEMORY MsgMemoryEntry
;
1737 RtlZeroMemory(&Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1739 /* FIXME: Call hooks. */
1740 if (HWND_BROADCAST
!= hWnd
)
1742 Window
= UserGetWindowObject(hWnd
);
1745 /* Tell usermode to not touch this one */
1746 Info
.HandledByKernel
= TRUE
;
1747 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1752 /* Check for an exiting window. */
1753 if (Window
&& Window
->state
& WNDS_DESTROYED
)
1755 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1758 /* See if the current thread can handle the message */
1759 pti
= PsGetCurrentThreadWin32Thread();
1761 // This is checked in user mode!!!!!!!
1762 if ( HWND_BROADCAST
!= hWnd
&&
1764 Window
->head
.pti
->MessageQueue
== pti
->MessageQueue
&&
1765 !ISITHOOKED(WH_CALLWNDPROC
) &&
1766 !ISITHOOKED(WH_CALLWNDPROCRET
) &&
1767 ( Msg
< WM_DDE_FIRST
|| Msg
> WM_DDE_LAST
) )
1769 /* Gather the information usermode needs to call the window proc directly */
1770 Info
.HandledByKernel
= FALSE
;
1772 Status
= MmCopyFromCaller(&(Info
.Ansi
), &(UnsafeInfo
->Ansi
), sizeof(BOOL
));
1773 if (! NT_SUCCESS(Status
))
1775 Info
.Ansi
= ! Window
->Unicode
;
1778 Info
.Ansi
= !Window
->Unicode
;
1779 Info
.Proc
= Window
->lpfnWndProc
;
1783 /* Must be handled by other thread */
1784 // if (HWND_BROADCAST != hWnd)
1786 // UserDereferenceObject(Window);
1788 Info
.HandledByKernel
= TRUE
;
1789 UserModeMsg
.hwnd
= hWnd
;
1790 UserModeMsg
.message
= Msg
;
1791 UserModeMsg
.wParam
= wParam
;
1792 UserModeMsg
.lParam
= lParam
;
1793 MsgMemoryEntry
= FindMsgMemory(UserModeMsg
.message
);
1795 Status
= CopyMsgToKernelMem(&KernelModeMsg
, &UserModeMsg
, MsgMemoryEntry
);
1796 if (! NT_SUCCESS(Status
))
1798 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1799 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1800 return (dsm
? 0 : -1);
1805 Result
= co_IntSendMessage( KernelModeMsg
.hwnd
,
1806 KernelModeMsg
.message
,
1807 KernelModeMsg
.wParam
,
1808 KernelModeMsg
.lParam
);
1812 Result
= co_IntSendMessageTimeout( KernelModeMsg
.hwnd
,
1813 KernelModeMsg
.message
,
1814 KernelModeMsg
.wParam
,
1815 KernelModeMsg
.lParam
,
1821 Status
= CopyMsgToUserMem(&UserModeMsg
, &KernelModeMsg
);
1822 if (! NT_SUCCESS(Status
))
1824 MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1825 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1826 return(dsm
? 0 : -1);
1830 Status
= MmCopyToCaller(UnsafeInfo
, &Info
, sizeof(NTUSERSENDMESSAGEINFO
));
1831 if (! NT_SUCCESS(Status
))
1833 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1836 return (LRESULT
)Result
;
1841 UserSendNotifyMessage( HWND hWnd
,
1848 if (FindMsgMemory(Msg
) != 0)
1850 SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY
);
1854 // Basicly the same as IntPostOrSendMessage
1855 if (hWnd
== HWND_BROADCAST
) //Handle Broadcast
1861 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
1862 List
= IntWinListChildren(DesktopWindow
);
1866 UserSendNotifyMessage(DesktopWindow
->head
.h
, Msg
, wParam
, lParam
);
1867 for (i
= 0; List
[i
]; i
++)
1869 UserSendNotifyMessage(List
[i
], Msg
, wParam
, lParam
);
1880 if ( !(Window
= UserGetWindowObject(hWnd
)) ) return FALSE
;
1882 pti
= PsGetCurrentThreadWin32Thread();
1884 if (Window
->head
.pti
->MessageQueue
!= pti
->MessageQueue
)
1885 { // Send message w/o waiting for it.
1886 Result
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1889 { // Handle message and callback.
1890 Result
= co_IntSendMessageTimeoutSingle( hWnd
,
1904 IntGetQueueStatus(DWORD Changes
)
1907 PUSER_MESSAGE_QUEUE Queue
;
1910 pti
= PsGetCurrentThreadWin32Thread();
1911 Queue
= pti
->MessageQueue
;
1913 Changes
&= (QS_ALLINPUT
|QS_ALLPOSTMESSAGE
|QS_SMRESULT
);
1915 Result
= MAKELONG(Queue
->ChangedBits
& Changes
, Queue
->QueueBits
& Changes
);
1919 pti
->pcti
->fsChangeBits
= Queue
->ChangedBits
;
1920 pti
->pcti
->fsChangeBits
&= ~Changes
;
1923 Queue
->ChangedBits
&= ~Changes
;
1929 IntInitMessagePumpHook()
1931 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1935 pti
->pcti
->dwcPumpHook
++;
1942 IntUninitMessagePumpHook()
1944 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1948 if (pti
->pcti
->dwcPumpHook
<= 0)
1952 pti
->pcti
->dwcPumpHook
--;
1958 /** Functions ******************************************************************/
1961 NtUserPostMessage(HWND hWnd
,
1968 UserEnterExclusive();
1970 ret
= UserPostMessage(hWnd
, Msg
, wParam
, lParam
);
1978 NtUserPostThreadMessage(DWORD idThread
,
1985 UserEnterExclusive();
1987 ret
= UserPostThreadMessage( idThread
, Msg
, wParam
, lParam
);
1995 NtUserQuerySendMessage(DWORD Unknown0
)
2003 ////////// API on the way out!
2005 NtUserSendMessageTimeout( HWND hWnd
,
2012 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
2017 DPRINT("Enter NtUserSendMessageTimeout\n");
2019 dsm
.uFlags
= uFlags
;
2020 dsm
.uTimeout
= uTimeout
;
2022 UserEnterExclusive();
2024 Result
= co_IntDoSendMessage(hWnd
, Msg
, wParam
, lParam
, &dsm
, UnsafeInfo
);
2028 if(uResult
!= NULL
&& Result
!= 0)
2032 ProbeForWrite(uResult
, sizeof(ULONG_PTR
), 1);
2033 RtlCopyMemory(uResult
, &dsm
.Result
, sizeof(ULONG_PTR
));
2035 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2037 SetLastWin32Error(ERROR_INVALID_PARAMETER
);;
2047 NtUserSendMessage( HWND Wnd
,
2051 PNTUSERSENDMESSAGEINFO UnsafeInfo
)
2055 UserEnterExclusive();
2057 ret
= co_IntDoSendMessage(Wnd
, Msg
, wParam
, lParam
, NULL
, UnsafeInfo
);
2066 NtUserWaitMessage(VOID
)
2070 UserEnterExclusive();
2072 ret
= co_IntWaitMessage(NULL
, 0, 0);
2081 NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo
,
2086 * FUNCTION: Get a message from the calling thread's message queue.
2088 * UnsafeMsg - Pointer to the structure which receives the returned message.
2089 * Wnd - Window whose messages are to be retrieved.
2090 * MsgFilterMin - Integer value of the lowest message value to be
2092 * MsgFilterMax - Integer value of the highest message value to be
2096 NTUSERGETMESSAGEINFO Info
;
2098 PMSGMEMORY MsgMemoryEntry
;
2104 if ( (MsgFilterMin
|MsgFilterMax
) & ~WM_MAXIMUM
)
2106 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2110 UserEnterExclusive();
2112 RtlZeroMemory(&Msg
, sizeof(MSG
));
2114 GotMessage
= co_IntGetPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
, TRUE
);
2119 /* See if this message type is present in the table */
2120 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
2124 ProbeForWrite(UnsafeInfo
, sizeof(NTUSERGETMESSAGEINFO
), 1);
2125 RtlCopyMemory(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
2127 if (NULL
== MsgMemoryEntry
)
2129 /* Not present, no copying needed */
2130 UnsafeInfo
->LParamSize
= 0;
2134 /* Determine required size */
2135 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
, Info
.Msg
.lParam
);
2137 /* Allocate required amount of user-mode memory */
2138 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
2144 if (! NT_SUCCESS(Status
))
2146 SetLastNtError(Status
);
2147 _SEH2_YIELD(return (BOOL
) -1);
2150 /* Transfer lParam data to user-mode mem */
2151 ProbeForWrite(UserMem
, Size
, 1);
2152 RtlCopyMemory(UserMem
, (PVOID
)Info
.Msg
.lParam
, Size
);
2154 UnsafeInfo
->LParamSize
= Size
;
2155 UnsafeInfo
->Msg
.lParam
= (LPARAM
) UserMem
;
2158 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2160 SetLastNtError(_SEH2_GetExceptionCode());
2164 ZwFreeVirtualMemory(NtCurrentProcess(), &UserMem
, &Size
, MEM_RELEASE
);
2167 _SEH2_YIELD(return (BOOL
) -1);
2176 NtUserGetMessageX(PMSG pMsg
,
2184 if ( (MsgFilterMin
|MsgFilterMax
) & ~WM_MAXIMUM
)
2186 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2190 UserEnterExclusive();
2192 RtlZeroMemory(&Msg
, sizeof(MSG
));
2194 Ret
= co_IntGetPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, PM_REMOVE
, TRUE
);
2202 ProbeForWrite(pMsg
, sizeof(MSG
), 1);
2203 RtlCopyMemory(pMsg
, &Msg
, sizeof(MSG
));
2205 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2207 SetLastNtError(_SEH2_GetExceptionCode());
2217 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo
,
2224 NTUSERGETMESSAGEINFO Info
;
2225 PMSGMEMORY MsgMemoryEntry
;
2226 PVOID UserMem
= NULL
;
2231 if ( RemoveMsg
& PM_BADMSGFLAGS
)
2233 SetLastWin32Error(ERROR_INVALID_FLAGS
);
2237 UserEnterExclusive();
2239 RtlZeroMemory(&Msg
, sizeof(MSG
));
2241 Ret
= co_IntGetPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
, FALSE
);
2248 /* See if this message type is present in the table */
2249 MsgMemoryEntry
= FindMsgMemory(Info
.Msg
.message
);
2253 ProbeForWrite(UnsafeInfo
, sizeof(NTUSERGETMESSAGEINFO
), 1);
2254 RtlCopyMemory(UnsafeInfo
, &Info
, sizeof(NTUSERGETMESSAGEINFO
));
2256 if (NULL
== MsgMemoryEntry
)
2258 /* Not present, no copying needed */
2259 UnsafeInfo
->LParamSize
= 0;
2263 /* Determine required size */
2264 Size
= MsgMemorySize(MsgMemoryEntry
, Info
.Msg
.wParam
, Info
.Msg
.lParam
);
2266 /* Allocate required amount of user-mode memory */
2267 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
2273 if (! NT_SUCCESS(Status
))
2275 SetLastNtError(Status
);
2276 _SEH2_YIELD(return (BOOL
) -1);
2279 /* Transfer lParam data to user-mode mem */
2280 ProbeForWrite(UserMem
, Size
, 1);
2281 RtlCopyMemory(UserMem
, (PVOID
)Info
.Msg
.lParam
, Size
);
2283 UnsafeInfo
->LParamSize
= Size
;
2284 UnsafeInfo
->Msg
.lParam
= (LPARAM
) UserMem
;
2287 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2289 SetLastNtError(_SEH2_GetExceptionCode());
2294 ZwFreeVirtualMemory(NtCurrentProcess(), &UserMem
, &Size
, MEM_RELEASE
);
2304 NtUserPeekMessageX( PMSG pMsg
,
2313 if ( RemoveMsg
& PM_BADMSGFLAGS
)
2315 SetLastWin32Error(ERROR_INVALID_FLAGS
);
2319 UserEnterExclusive();
2321 RtlZeroMemory(&Msg
, sizeof(MSG
));
2323 Ret
= co_IntGetPeekMessage(&Msg
, hWnd
, MsgFilterMin
, MsgFilterMax
, RemoveMsg
, FALSE
);
2331 ProbeForWrite(pMsg
, sizeof(MSG
), 1);
2332 RtlCopyMemory(pMsg
, &Msg
, sizeof(MSG
));
2334 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2336 SetLastNtError(_SEH2_GetExceptionCode());
2346 NtUserCallMsgFilter( LPMSG lpmsg
, INT code
)
2353 ProbeForRead(lpmsg
, sizeof(MSG
), 1);
2354 RtlCopyMemory( &Msg
, lpmsg
, sizeof(MSG
));
2356 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2358 _SEH2_YIELD(return FALSE
);
2362 UserEnterExclusive();
2364 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)&Msg
))
2370 Ret
= co_HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)&Msg
);
2377 ProbeForWrite(lpmsg
, sizeof(MSG
), 1);
2378 RtlCopyMemory(lpmsg
, &Msg
, sizeof(MSG
));
2380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2390 NtUserDispatchMessage(PMSG UnsafeMsgInfo
)
2397 ProbeForRead(UnsafeMsgInfo
, sizeof(MSG
), 1);
2398 RtlCopyMemory(&SafeMsg
, UnsafeMsgInfo
, sizeof(MSG
));
2400 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2402 SetLastNtError(_SEH2_GetExceptionCode());
2403 _SEH2_YIELD(return FALSE
);
2407 UserEnterExclusive();
2409 Res
= IntDispatchMessage(&SafeMsg
);
2417 NtUserTranslateMessage(LPMSG lpMsg
, UINT flags
)
2424 ProbeForRead(lpMsg
, sizeof(MSG
), 1);
2425 RtlCopyMemory(&SafeMsg
, lpMsg
, sizeof(MSG
));
2427 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2429 SetLastNtError(_SEH2_GetExceptionCode());
2430 _SEH2_YIELD(return FALSE
);
2434 UserEnterExclusive();
2436 Ret
= IntTranslateKbdMessage(&SafeMsg
, flags
);
2444 NtUserMessageCall( HWND hWnd
,
2448 ULONG_PTR ResultInfo
,
2449 DWORD dwType
, // fnID?
2452 LRESULT lResult
= 0;
2455 USER_REFERENCE_ENTRY Ref
;
2457 UserEnterExclusive();
2459 /* Validate input */
2460 if (hWnd
&& (hWnd
!= INVALID_HANDLE_VALUE
))
2462 Window
= UserGetWindowObject(hWnd
);
2472 case FNID_DEFWINDOWPROC
:
2473 if (Window
) UserRefObjectCo(Window
, &Ref
);
2474 lResult
= IntDefWindowProc(Window
, Msg
, wParam
, lParam
, Ansi
);
2476 if (Window
) UserDerefObjectCo(Window
);
2478 case FNID_SENDNOTIFYMESSAGE
:
2479 Ret
= UserSendNotifyMessage(hWnd
, Msg
, wParam
, lParam
);
2481 case FNID_BROADCASTSYSTEMMESSAGE
:
2484 DWORD_PTR RetVal
= 0;
2490 ProbeForWrite((PVOID
)ResultInfo
, sizeof(BROADCASTPARM
), 1);
2491 RtlCopyMemory(&parm
, (PVOID
)ResultInfo
, sizeof(BROADCASTPARM
));
2493 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2503 if ( parm
.recipients
& BSM_ALLDESKTOPS
||
2504 parm
.recipients
== BSM_ALLCOMPONENTS
)
2507 else if (parm
.recipients
& BSM_APPLICATIONS
)
2509 if (parm
.flags
& BSF_QUERY
)
2511 if (parm
.flags
& BSF_FORCEIFHUNG
|| parm
.flags
& BSF_NOHANG
)
2513 co_IntSendMessageTimeout( HWND_BROADCAST
,
2521 else if (parm
.flags
& BSF_NOTIMEOUTIFNOTHUNG
)
2523 co_IntSendMessageTimeout( HWND_BROADCAST
,
2527 SMTO_NOTIMEOUTIFNOTHUNG
,
2533 co_IntSendMessageTimeout( HWND_BROADCAST
,
2543 else if (parm
.flags
& BSF_POSTMESSAGE
)
2545 Ret
= UserPostMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2547 else //Everything else,,,, if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2549 Ret
= UserSendNotifyMessage(HWND_BROADCAST
, Msg
, wParam
, lParam
);
2554 case FNID_SENDMESSAGECALLBACK
:
2556 PCALL_BACK_INFO CallBackInfo
= (PCALL_BACK_INFO
)ResultInfo
;
2562 if (!co_IntSendMessageWithCallBack(hWnd
, Msg
, wParam
, lParam
,
2563 CallBackInfo
->CallBack
, CallBackInfo
->Context
, &uResult
))
2565 DPRINT1("Callback failure!\n");
2569 // CallNextHook bypass.
2570 case FNID_CALLWNDPROC
:
2571 case FNID_CALLWNDPROCRET
:
2574 PCLIENTINFO ClientInfo
;
2575 PHOOK NextObj
, Hook
;
2577 pti
= GetW32ThreadInfo();
2579 Hook
= pti
->sphkCurrent
;
2583 NextObj
= Hook
->phkNext
;
2584 ClientInfo
= pti
->pClientInfo
;
2587 ClientInfo
->phkCurrent
= NextObj
;
2589 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2595 if (!ClientInfo
|| !NextObj
) break;
2597 NextObj
->phkNext
= IntGetNextHook(NextObj
);
2599 if ( Hook
->HookId
== WH_CALLWNDPROC
)
2604 CWP
.wParam
= wParam
;
2605 CWP
.lParam
= lParam
;
2606 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook
, NextObj
);
2608 lResult
= co_IntCallHookProc( Hook
->HookId
,
2610 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2621 CWPR
.wParam
= wParam
;
2622 CWPR
.lParam
= lParam
;
2623 CWPR
.lResult
= ClientInfo
->dwHookData
;
2625 lResult
= co_IntCallHookProc( Hook
->HookId
,
2627 ((ClientInfo
->CI_flags
& CI_CURTHPRHOOK
) ? 1 : 0),
2639 case FNID_DEFWINDOWPROC
:
2640 case FNID_CALLWNDPROC
:
2641 case FNID_CALLWNDPROCRET
:
2646 ProbeForWrite((PVOID
)ResultInfo
, sizeof(LRESULT
), 1);
2647 RtlCopyMemory((PVOID
)ResultInfo
, &lResult
, sizeof(LRESULT
));
2649 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2665 #define INFINITE 0xFFFFFFFF
2666 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2670 NtUserWaitForInputIdle( IN HANDLE hProcess
,
2671 IN DWORD dwMilliseconds
,
2675 PPROCESSINFO W32Process
;
2679 LARGE_INTEGER Timeout
;
2681 UserEnterExclusive();
2683 Status
= ObReferenceObjectByHandle(hProcess
,
2684 PROCESS_QUERY_INFORMATION
,
2690 if (!NT_SUCCESS(Status
))
2693 SetLastNtError(Status
);
2697 pti
= PsGetCurrentThreadWin32Thread();
2699 W32Process
= (PPROCESSINFO
)Process
->Win32Process
;
2701 if ( PsGetProcessExitProcessCalled(Process
) ||
2703 pti
->ppi
== W32Process
)
2705 ObDereferenceObject(Process
);
2707 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2711 Handles
[0] = Process
;
2712 Handles
[1] = W32Process
->InputIdleEvent
;
2713 Handles
[2] = pti
->MessageQueue
->NewMessages
; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2717 ObDereferenceObject(Process
);
2719 return STATUS_SUCCESS
; /* no event to wait on */
2722 if (dwMilliseconds
!= INFINITE
)
2723 Timeout
.QuadPart
= (LONGLONG
) dwMilliseconds
* (LONGLONG
) -10000;
2725 DPRINT("WFII: ppi 0x%x\n",W32Process
);
2726 DPRINT("WFII: waiting for %p\n", Handles
[1] );
2730 Status
= KeWaitForMultipleObjects( 3,
2736 dwMilliseconds
== INFINITE
? NULL
: &Timeout
,
2738 UserEnterExclusive();
2740 if (!NT_SUCCESS(Status
))
2742 SetLastNtError(Status
);
2743 Status
= WAIT_FAILED
;
2755 co_IntPeekMessage( &Msg
, 0, 0, 0, PM_REMOVE
| PM_QS_SENDMESSAGE
);
2756 DPRINT1("WFII: WAIT 2\n");
2760 case STATUS_TIMEOUT
:
2761 DPRINT1("WFII: timeout\n");
2766 DPRINT1("WFII: finished\n");
2767 Status
= STATUS_SUCCESS
;
2774 ObDereferenceObject(Process
);