remove user handle table lock, cursor locks, message queue locks, hook lock
[reactos.git] / reactos / subsys / win32k / ntuser / message.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Messages
24 * FILE: subsys/win32k/ntuser/message.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29
30 /* INCLUDES ******************************************************************/
31
32 #include <w32k.h>
33
34 #define NDEBUG
35 #include <debug.h>
36
37 typedef struct
38 {
39 UINT uFlags;
40 UINT uTimeout;
41 ULONG_PTR Result;
42 } DOSENDMESSAGE, *PDOSENDMESSAGE;
43
44 /* FUNCTIONS *****************************************************************/
45
46 NTSTATUS FASTCALL
47 IntInitMessageImpl(VOID)
48 {
49 return STATUS_SUCCESS;
50 }
51
52 NTSTATUS FASTCALL
53 IntCleanupMessageImpl(VOID)
54 {
55 return STATUS_SUCCESS;
56 }
57
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
66 {
67 UINT Message;
68 UINT Size;
69 INT Flags;
70 } MSGMEMORY, *PMSGMEMORY;
71
72 static MSGMEMORY MsgMemory[] =
73 {
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 },
87 };
88
89 static PMSGMEMORY FASTCALL
90 FindMsgMemory(UINT Msg)
91 {
92 PMSGMEMORY MsgMemoryEntry;
93
94 /* See if this message type is present in the table */
95 for (MsgMemoryEntry = MsgMemory;
96 MsgMemoryEntry < MsgMemory + sizeof(MsgMemory) / sizeof(MSGMEMORY);
97 MsgMemoryEntry++)
98 {
99 if (Msg == MsgMemoryEntry->Message)
100 {
101 return MsgMemoryEntry;
102 }
103 }
104
105 return NULL;
106 }
107
108 static UINT FASTCALL
109 MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
110 {
111 CREATESTRUCTW *Cs;
112 PUNICODE_STRING WindowName;
113 PUNICODE_STRING ClassName;
114 UINT Size;
115
116 _SEH_TRY {
117 if (MMS_SIZE_WPARAM == MsgMemoryEntry->Size)
118 {
119 return (UINT) wParam;
120 }
121 else if (MMS_SIZE_WPARAMWCHAR == MsgMemoryEntry->Size)
122 {
123 return (UINT) (wParam * sizeof(WCHAR));
124 }
125 else if (MMS_SIZE_LPARAMSZ == MsgMemoryEntry->Size)
126 {
127 return (UINT) ((wcslen((PWSTR) lParam) + 1) * sizeof(WCHAR));
128 }
129 else if (MMS_SIZE_SPECIAL == MsgMemoryEntry->Size)
130 {
131 switch(MsgMemoryEntry->Message)
132 {
133 case WM_CREATE:
134 case WM_NCCREATE:
135 Cs = (CREATESTRUCTW *) lParam;
136 WindowName = (PUNICODE_STRING) Cs->lpszName;
137 ClassName = (PUNICODE_STRING) Cs->lpszClass;
138 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
139 if (IS_ATOM(ClassName->Buffer))
140 {
141 Size += sizeof(WCHAR) + sizeof(ATOM);
142 }
143 else
144 {
145 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
146 }
147 return Size;
148 break;
149
150 case WM_NCCALCSIZE:
151 return wParam ? sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) : sizeof(RECT);
152 break;
153
154 case WM_COPYDATA:
155 return sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
156
157 default:
158 assert(FALSE);
159 return 0;
160 break;
161 }
162 }
163 else
164 {
165 return MsgMemoryEntry->Size;
166 }
167 } _SEH_HANDLE {
168
169 DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH_GetExceptionCode());
170 } _SEH_END;
171 return 0;
172 }
173
174 static FASTCALL NTSTATUS
175 PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
176 {
177 NCCALCSIZE_PARAMS *UnpackedNcCalcsize;
178 NCCALCSIZE_PARAMS *PackedNcCalcsize;
179 CREATESTRUCTW *UnpackedCs;
180 CREATESTRUCTW *PackedCs;
181 PUNICODE_STRING WindowName;
182 PUNICODE_STRING ClassName;
183 UINT Size;
184 PCHAR CsData;
185
186 *lParamPacked = lParam;
187 if (WM_NCCALCSIZE == Msg && wParam)
188 {
189 UnpackedNcCalcsize = (NCCALCSIZE_PARAMS *) lParam;
190 if (UnpackedNcCalcsize->lppos != (PWINDOWPOS) (UnpackedNcCalcsize + 1))
191 {
192 PackedNcCalcsize = ExAllocatePoolWithTag(PagedPool,
193 sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS),
194 TAG_MSG);
195 if (NULL == PackedNcCalcsize)
196 {
197 DPRINT1("Not enough memory to pack lParam\n");
198 return STATUS_NO_MEMORY;
199 }
200 RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS));
201 PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1);
202 RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS));
203 *lParamPacked = (LPARAM) PackedNcCalcsize;
204 }
205 }
206 else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
207 {
208 UnpackedCs = (CREATESTRUCTW *) lParam;
209 WindowName = (PUNICODE_STRING) UnpackedCs->lpszName;
210 ClassName = (PUNICODE_STRING) UnpackedCs->lpszClass;
211 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
212 if (IS_ATOM(ClassName->Buffer))
213 {
214 Size += sizeof(WCHAR) + sizeof(ATOM);
215 }
216 else
217 {
218 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
219 }
220 PackedCs = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
221 if (NULL == PackedCs)
222 {
223 DPRINT1("Not enough memory to pack lParam\n");
224 return STATUS_NO_MEMORY;
225 }
226 RtlCopyMemory(PackedCs, UnpackedCs, sizeof(CREATESTRUCTW));
227 CsData = (PCHAR) (PackedCs + 1);
228 PackedCs->lpszName = (LPCWSTR) (CsData - (PCHAR) PackedCs);
229 RtlCopyMemory(CsData, WindowName->Buffer, WindowName->Length);
230 CsData += WindowName->Length;
231 *((WCHAR *) CsData) = L'\0';
232 CsData += sizeof(WCHAR);
233 PackedCs->lpszClass = (LPCWSTR) (CsData - (PCHAR) PackedCs);
234 if (IS_ATOM(ClassName->Buffer))
235 {
236 *((WCHAR *) CsData) = L'A';
237 CsData += sizeof(WCHAR);
238 *((ATOM *) CsData) = (ATOM)(DWORD_PTR) ClassName->Buffer;
239 CsData += sizeof(ATOM);
240 }
241 else
242 {
243 *((WCHAR *) CsData) = L'S';
244 CsData += sizeof(WCHAR);
245 RtlCopyMemory(CsData, ClassName->Buffer, ClassName->Length);
246 CsData += ClassName->Length;
247 *((WCHAR *) CsData) = L'\0';
248 CsData += sizeof(WCHAR);
249 }
250 ASSERT(CsData == (PCHAR) PackedCs + Size);
251 *lParamPacked = (LPARAM) PackedCs;
252 }
253
254 return STATUS_SUCCESS;
255 }
256
257 static FASTCALL NTSTATUS
258 UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
259 {
260 NCCALCSIZE_PARAMS *UnpackedParams;
261 NCCALCSIZE_PARAMS *PackedParams;
262 PWINDOWPOS UnpackedWindowPos;
263
264 if (lParamPacked == lParam)
265 {
266 return STATUS_SUCCESS;
267 }
268
269 if (WM_NCCALCSIZE == Msg && wParam)
270 {
271 PackedParams = (NCCALCSIZE_PARAMS *) lParamPacked;
272 UnpackedParams = (NCCALCSIZE_PARAMS *) lParam;
273 UnpackedWindowPos = UnpackedParams->lppos;
274 RtlCopyMemory(UnpackedParams, PackedParams, sizeof(NCCALCSIZE_PARAMS));
275 UnpackedParams->lppos = UnpackedWindowPos;
276 RtlCopyMemory(UnpackedWindowPos, PackedParams + 1, sizeof(WINDOWPOS));
277 ExFreePool((PVOID) lParamPacked);
278
279 return STATUS_SUCCESS;
280 }
281 else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
282 {
283 ExFreePool((PVOID) lParamPacked);
284
285 return STATUS_SUCCESS;
286 }
287
288 ASSERT(FALSE);
289
290 return STATUS_INVALID_PARAMETER;
291 }
292
293 BOOL
294 STDCALL
295 NtUserCallMsgFilter(
296 LPMSG msg,
297 INT code)
298 {
299 DECLARE_RETURN(BOOL);
300
301 DPRINT("Enter NtUserCallMsgFilter\n");
302 UserEnterExclusive();
303
304 if (co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)msg)) RETURN( TRUE);
305 RETURN( co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)msg));
306
307 CLEANUP:
308 DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_);
309 UserLeave();
310 END_CLEANUP;
311 }
312
313 LRESULT STDCALL
314 NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo)
315 {
316 NTSTATUS Status;
317 NTUSERDISPATCHMESSAGEINFO MsgInfo;
318 PWINDOW_OBJECT WindowObject;
319 LRESULT Result = TRUE;
320 DECLARE_RETURN(LRESULT);
321
322 DPRINT("Enter NtUserDispatchMessage\n");
323 UserEnterExclusive();
324
325 Status = MmCopyFromCaller(&MsgInfo, UnsafeMsgInfo, sizeof(NTUSERDISPATCHMESSAGEINFO));
326 if (! NT_SUCCESS(Status))
327 {
328 SetLastNtError(Status);
329 RETURN( 0);
330 }
331
332 /* Process timer messages. */
333 if (WM_TIMER == MsgInfo.Msg.message && 0 != MsgInfo.Msg.lParam)
334 {
335 LARGE_INTEGER LargeTickCount;
336 /* FIXME: Call hooks. */
337
338 /* FIXME: Check for continuing validity of timer. */
339
340 MsgInfo.HandledByKernel = FALSE;
341 KeQueryTickCount(&LargeTickCount);
342 MsgInfo.Proc = (WNDPROC) MsgInfo.Msg.lParam;
343 MsgInfo.Msg.lParam = (LPARAM)LargeTickCount.u.LowPart;
344 }
345 else if (NULL == MsgInfo.Msg.hwnd)
346 {
347 MsgInfo.HandledByKernel = TRUE;
348 Result = 0;
349 }
350 else
351 {
352 /* Get the window object. */
353 WindowObject = IntGetWindowObject(MsgInfo.Msg.hwnd);
354 if (NULL == WindowObject)
355 {
356 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
357 MsgInfo.HandledByKernel = TRUE;
358 Result = 0;
359 }
360 else
361 {
362 if (WindowObject->OwnerThread != PsGetCurrentThread())
363 {
364 IntReleaseWindowObject(WindowObject);
365 DPRINT1("Window doesn't belong to the calling thread!\n");
366 MsgInfo.HandledByKernel = TRUE;
367 Result = 0;
368 }
369 else
370 {
371 /* FIXME: Call hook procedures. */
372
373 MsgInfo.HandledByKernel = FALSE;
374 Result = 0;
375 if (0xFFFF0000 != ((DWORD) WindowObject->WndProcW & 0xFFFF0000))
376 {
377 if (0xFFFF0000 != ((DWORD) WindowObject->WndProcA & 0xFFFF0000))
378 {
379 /* Both Unicode and Ansi winprocs are real, use whatever
380 usermode prefers */
381 MsgInfo.Proc = (MsgInfo.Ansi ? WindowObject->WndProcA
382 : WindowObject->WndProcW);
383 }
384 else
385 {
386 /* Real Unicode winproc */
387 MsgInfo.Ansi = FALSE;
388 MsgInfo.Proc = WindowObject->WndProcW;
389 }
390 }
391 else
392 {
393 /* Must have real Ansi winproc */
394 MsgInfo.Ansi = TRUE;
395 MsgInfo.Proc = WindowObject->WndProcA;
396 }
397 }
398 IntReleaseWindowObject(WindowObject);
399 }
400 }
401 Status = MmCopyToCaller(UnsafeMsgInfo, &MsgInfo, sizeof(NTUSERDISPATCHMESSAGEINFO));
402 if (! NT_SUCCESS(Status))
403 {
404 SetLastNtError(Status);
405 RETURN( 0);
406 }
407
408 RETURN( Result);
409
410 CLEANUP:
411 DPRINT("Leave NtUserDispatchMessage. ret=%i\n", _ret_);
412 UserLeave();
413 END_CLEANUP;
414 }
415
416
417 BOOL STDCALL
418 NtUserTranslateMessage(LPMSG lpMsg,
419 HKL dwhkl)
420 {
421 NTSTATUS Status;
422 MSG SafeMsg;
423 DECLARE_RETURN(BOOL);
424
425 DPRINT("Enter NtUserTranslateMessage\n");
426 UserEnterExclusive();
427
428 Status = MmCopyFromCaller(&SafeMsg, lpMsg, sizeof(MSG));
429 if(!NT_SUCCESS(Status))
430 {
431 SetLastNtError(Status);
432 RETURN( FALSE);
433 }
434
435 RETURN( IntTranslateKbdMessage(&SafeMsg, dwhkl));
436
437 CLEANUP:
438 DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_);
439 UserLeave();
440 END_CLEANUP;
441 }
442
443
444 VOID FASTCALL
445 co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg)
446 {
447 if(!Msg->hwnd || ThreadQueue->CaptureWindow)
448 {
449 return;
450 }
451
452 switch(Msg->message)
453 {
454 case WM_MOUSEMOVE:
455 {
456 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
457 break;
458 }
459 case WM_NCMOUSEMOVE:
460 {
461 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
462 break;
463 }
464 case WM_LBUTTONDOWN:
465 case WM_MBUTTONDOWN:
466 case WM_RBUTTONDOWN:
467 case WM_XBUTTONDOWN:
468 case WM_LBUTTONDBLCLK:
469 case WM_MBUTTONDBLCLK:
470 case WM_RBUTTONDBLCLK:
471 case WM_XBUTTONDBLCLK:
472 {
473 WPARAM wParam;
474 PSYSTEM_CURSORINFO CurInfo;
475
476 if(!IntGetWindowStationObject(InputWindowStation))
477 {
478 break;
479 }
480 CurInfo = IntGetSysCursorInfo(InputWindowStation);
481 wParam = (WPARAM)(CurInfo->ButtonsDown);
482 ObDereferenceObject(InputWindowStation);
483
484 co_IntSendMessage(Msg->hwnd, WM_MOUSEMOVE, wParam, Msg->lParam);
485 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
486 break;
487 }
488 case WM_NCLBUTTONDOWN:
489 case WM_NCMBUTTONDOWN:
490 case WM_NCRBUTTONDOWN:
491 case WM_NCXBUTTONDOWN:
492 case WM_NCLBUTTONDBLCLK:
493 case WM_NCMBUTTONDBLCLK:
494 case WM_NCRBUTTONDBLCLK:
495 case WM_NCXBUTTONDBLCLK:
496 {
497 co_IntSendMessage(Msg->hwnd, WM_NCMOUSEMOVE, (WPARAM)Msg->wParam, Msg->lParam);
498 co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
499 break;
500 }
501 }
502 }
503
504 BOOL FASTCALL
505 co_IntActivateWindowMouse(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, PWINDOW_OBJECT MsgWindow,
506 USHORT *HitTest)
507 {
508 ULONG Result;
509
510 if(*HitTest == (USHORT)HTTRANSPARENT)
511 {
512 /* eat the message, search again! */
513 return TRUE;
514 }
515
516 Result = co_IntSendMessage(MsgWindow->Self, WM_MOUSEACTIVATE, (WPARAM)IntGetParent(MsgWindow), (LPARAM)MAKELONG(*HitTest, Msg->message));
517 switch (Result)
518 {
519 case MA_NOACTIVATEANDEAT:
520 return TRUE;
521 case MA_NOACTIVATE:
522 break;
523 case MA_ACTIVATEANDEAT:
524 co_IntMouseActivateWindow(MsgWindow);
525 return TRUE;
526 default:
527 /* MA_ACTIVATE */
528 co_IntMouseActivateWindow(MsgWindow);
529 break;
530 }
531
532 return FALSE;
533 }
534
535 BOOL FASTCALL
536 co_IntTranslateMouseMessage(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg, USHORT *HitTest, BOOL Remove)
537 {
538 PWINDOW_OBJECT Window;
539
540 if(!(Window = IntGetWindowObject(Msg->hwnd)))
541 {
542 /* let's just eat the message?! */
543 return TRUE;
544 }
545
546 if(ThreadQueue == Window->MessageQueue &&
547 ThreadQueue->CaptureWindow != Window->Self)
548 {
549 /* only send WM_NCHITTEST messages if we're not capturing the window! */
550 *HitTest = co_IntSendMessage(Window->Self, WM_NCHITTEST, 0,
551 MAKELONG(Msg->pt.x, Msg->pt.y));
552
553 if(*HitTest == (USHORT)HTTRANSPARENT)
554 {
555 PWINDOW_OBJECT DesktopWindow;
556 HWND hDesktop = IntGetDesktopWindow();
557
558 if((DesktopWindow = IntGetWindowObject(hDesktop)))
559 {
560 PWINDOW_OBJECT Wnd;
561
562 co_WinPosWindowFromPoint(DesktopWindow, Window->MessageQueue, &Msg->pt, &Wnd);
563 if(Wnd)
564 {
565 if(Wnd != Window)
566 {
567 /* post the message to the other window */
568 Msg->hwnd = Wnd->Self;
569 if(!(Wnd->Status & WINDOWSTATUS_DESTROYING))
570 {
571 MsqPostMessage(Wnd->MessageQueue, Msg, FALSE,
572 Msg->message == WM_MOUSEMOVE ? QS_MOUSEMOVE :
573 QS_MOUSEBUTTON);
574 }
575
576 /* eat the message */
577 IntReleaseWindowObject(Wnd);
578 IntReleaseWindowObject(Window);
579 IntReleaseWindowObject(DesktopWindow);
580 return TRUE;
581 }
582 IntReleaseWindowObject(Wnd);
583 }
584
585 IntReleaseWindowObject(DesktopWindow);
586 }
587 }
588 }
589 else
590 {
591 *HitTest = HTCLIENT;
592 }
593
594 if(IS_BTN_MESSAGE(Msg->message, DOWN))
595 {
596 /* generate double click messages, if necessary */
597 if ((((*HitTest) != HTCLIENT) ||
598 (IntGetClassLong(Window, GCL_STYLE, FALSE) & CS_DBLCLKS)) &&
599 MsqIsDblClk(Msg, Remove))
600 {
601 Msg->message += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
602 }
603 }
604
605 if(Msg->message != WM_MOUSEWHEEL)
606 {
607
608 if ((*HitTest) != HTCLIENT)
609 {
610 Msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
611 if((Msg->message == WM_NCRBUTTONUP) &&
612 (((*HitTest) == HTCAPTION) || ((*HitTest) == HTSYSMENU)))
613 {
614 Msg->message = WM_CONTEXTMENU;
615 Msg->wParam = (WPARAM)Window->Self;
616 }
617 else
618 {
619 Msg->wParam = *HitTest;
620 }
621 Msg->lParam = MAKELONG(Msg->pt.x, Msg->pt.y);
622 }
623 else if(ThreadQueue->MoveSize == NULL &&
624 ThreadQueue->MenuOwner == NULL)
625 {
626 /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
627 Msg->lParam = MAKELONG(
628 Msg->pt.x - (WORD)Window->ClientRect.left,
629 Msg->pt.y - (WORD)Window->ClientRect.top);
630 }
631 }
632
633 IntReleaseWindowObject(Window);
634 return FALSE;
635 }
636
637
638 /*
639 * Internal version of PeekMessage() doing all the work
640 */
641 BOOL FASTCALL
642 co_IntPeekMessage(PUSER_MESSAGE Msg,
643 HWND Wnd,
644 UINT MsgFilterMin,
645 UINT MsgFilterMax,
646 UINT RemoveMsg)
647 {
648 LARGE_INTEGER LargeTickCount;
649 PUSER_MESSAGE_QUEUE ThreadQueue;
650 PUSER_MESSAGE Message;
651 BOOL Present, RemoveMessages;
652
653 /* The queues and order in which they are checked are documented in the MSDN
654 article on GetMessage() */
655
656 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
657
658 /* Inspect RemoveMsg flags */
659 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
660 RemoveMessages = RemoveMsg & PM_REMOVE;
661
662 CheckMessages:
663
664 Present = FALSE;
665
666 KeQueryTickCount(&LargeTickCount);
667 ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
668
669 /* Dispatch sent messages here. */
670 while (co_MsqDispatchOneSentMessage(ThreadQueue));
671
672 /* Now look for a quit message. */
673
674 if (ThreadQueue->QuitPosted)
675 {
676 /* According to the PSDK, WM_QUIT messages are always returned, regardless
677 of the filter specified */
678 Msg->Msg.hwnd = NULL;
679 Msg->Msg.message = WM_QUIT;
680 Msg->Msg.wParam = ThreadQueue->QuitExitCode;
681 Msg->Msg.lParam = 0;
682 Msg->FreeLParam = FALSE;
683 if (RemoveMessages)
684 {
685 ThreadQueue->QuitPosted = FALSE;
686 }
687 return TRUE;
688 }
689
690 /* Now check for normal messages. */
691 Present = co_MsqFindMessage(ThreadQueue,
692 FALSE,
693 RemoveMessages,
694 Wnd,
695 MsgFilterMin,
696 MsgFilterMax,
697 &Message);
698 if (Present)
699 {
700 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
701 if (RemoveMessages)
702 {
703 MsqDestroyMessage(Message);
704 }
705 goto MessageFound;
706 }
707
708 /* Check for hardware events. */
709 Present = co_MsqFindMessage(ThreadQueue,
710 TRUE,
711 RemoveMessages,
712 Wnd,
713 MsgFilterMin,
714 MsgFilterMax,
715 &Message);
716 if (Present)
717 {
718 RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
719 if (RemoveMessages)
720 {
721 MsqDestroyMessage(Message);
722 }
723 goto MessageFound;
724 }
725
726 /* Check for sent messages again. */
727 while (co_MsqDispatchOneSentMessage(ThreadQueue));
728
729 /* Check for paint messages. */
730 if (IntGetPaintMessage(Wnd, MsgFilterMin, MsgFilterMax, PsGetWin32Thread(), &Msg->Msg, RemoveMessages))
731 {
732 Msg->FreeLParam = FALSE;
733 return TRUE;
734 }
735
736 /* Check for WM_(SYS)TIMER messages */
737 Present = MsqGetTimerMessage(ThreadQueue, Wnd, MsgFilterMin, MsgFilterMax,
738 &Msg->Msg, RemoveMessages);
739 if (Present)
740 {
741 Msg->FreeLParam = FALSE;
742 goto MessageFound;
743 }
744
745 if(Present)
746 {
747 MessageFound:
748
749 if(RemoveMessages)
750 {
751 PWINDOW_OBJECT MsgWindow = NULL;
752
753 if(Msg->Msg.hwnd && (MsgWindow = IntGetWindowObject(Msg->Msg.hwnd)) &&
754 Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST)
755 {
756 USHORT HitTest;
757
758 if(co_IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, TRUE))
759 /* FIXME - check message filter again, if the message doesn't match anymore,
760 search again */
761 {
762 IntReleaseWindowObject(MsgWindow);
763 /* eat the message, search again */
764 goto CheckMessages;
765 }
766 if(ThreadQueue->CaptureWindow == NULL)
767 {
768 co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
769 if((Msg->Msg.message != WM_MOUSEMOVE && Msg->Msg.message != WM_NCMOUSEMOVE) &&
770 IS_BTN_MESSAGE(Msg->Msg.message, DOWN) &&
771 co_IntActivateWindowMouse(ThreadQueue, &Msg->Msg, MsgWindow, &HitTest))
772 {
773 IntReleaseWindowObject(MsgWindow);
774 /* eat the message, search again */
775 goto CheckMessages;
776 }
777 }
778 }
779 else
780 {
781 co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
782 }
783
784 if(MsgWindow)
785 {
786 IntReleaseWindowObject(MsgWindow);
787 }
788
789 return TRUE;
790 }
791
792 USHORT HitTest;
793 if((Msg->Msg.hwnd && Msg->Msg.message >= WM_MOUSEFIRST && Msg->Msg.message <= WM_MOUSELAST) &&
794 co_IntTranslateMouseMessage(ThreadQueue, &Msg->Msg, &HitTest, FALSE))
795 /* FIXME - check message filter again, if the message doesn't match anymore,
796 search again */
797 {
798 /* eat the message, search again */
799 goto CheckMessages;
800 }
801
802 return TRUE;
803 }
804
805 return Present;
806 }
807
808 BOOL STDCALL
809 NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
810 HWND Wnd,
811 UINT MsgFilterMin,
812 UINT MsgFilterMax,
813 UINT RemoveMsg)
814 {
815 NTSTATUS Status;
816 BOOL Present;
817 NTUSERGETMESSAGEINFO Info;
818 PWINDOW_OBJECT Window;
819 PMSGMEMORY MsgMemoryEntry;
820 PVOID UserMem;
821 UINT Size;
822 USER_MESSAGE Msg;
823 DECLARE_RETURN(BOOL);
824
825 DPRINT("Enter NtUserPeekMessage\n");
826 UserEnterExclusive();
827
828 /* Validate input */
829 if (NULL != Wnd)
830 {
831 Window = IntGetWindowObject(Wnd);
832 if (NULL == Window)
833 {
834 Wnd = NULL;
835 }
836 else
837 {
838 IntReleaseWindowObject(Window);
839 }
840 }
841
842 if (MsgFilterMax < MsgFilterMin)
843 {
844 MsgFilterMin = 0;
845 MsgFilterMax = 0;
846 }
847
848 Present = co_IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, RemoveMsg);
849 if (Present)
850 {
851 Info.Msg = Msg.Msg;
852 /* See if this message type is present in the table */
853 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
854 if (NULL == MsgMemoryEntry)
855 {
856 /* Not present, no copying needed */
857 Info.LParamSize = 0;
858 }
859 else
860 {
861 /* Determine required size */
862 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
863 Info.Msg.lParam);
864 /* Allocate required amount of user-mode memory */
865 Info.LParamSize = Size;
866 UserMem = NULL;
867 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
868 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
869 if (! NT_SUCCESS(Status))
870 {
871 SetLastNtError(Status);
872 RETURN( (BOOL) -1);
873 }
874 /* Transfer lParam data to user-mode mem */
875 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
876 if (! NT_SUCCESS(Status))
877 {
878 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
879 &Info.LParamSize, MEM_DECOMMIT);
880 SetLastNtError(Status);
881 RETURN( (BOOL) -1);
882 }
883 Info.Msg.lParam = (LPARAM) UserMem;
884 }
885 if (RemoveMsg && Msg.FreeLParam && 0 != Msg.Msg.lParam)
886 {
887 ExFreePool((void *) Msg.Msg.lParam);
888 }
889 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
890 if (! NT_SUCCESS(Status))
891 {
892 SetLastNtError(Status);
893 RETURN( (BOOL) -1);
894 }
895 }
896
897 RETURN( Present);
898
899 CLEANUP:
900 DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
901 UserLeave();
902 END_CLEANUP;
903 }
904
905 static BOOL FASTCALL
906 co_IntWaitMessage(HWND Wnd,
907 UINT MsgFilterMin,
908 UINT MsgFilterMax)
909 {
910 PUSER_MESSAGE_QUEUE ThreadQueue;
911 NTSTATUS Status;
912 USER_MESSAGE Msg;
913
914 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
915
916 do
917 {
918 if (co_IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, PM_NOREMOVE))
919 {
920 return TRUE;
921 }
922
923 /* Nothing found. Wait for new messages. */
924 Status = co_MsqWaitForNewMessages(ThreadQueue, Wnd, MsgFilterMin, MsgFilterMax);
925 }
926 while ((STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) || STATUS_TIMEOUT == Status);
927
928 SetLastNtError(Status);
929
930 return FALSE;
931 }
932
933 BOOL STDCALL
934 NtUserGetMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
935 HWND Wnd,
936 UINT MsgFilterMin,
937 UINT MsgFilterMax)
938 /*
939 * FUNCTION: Get a message from the calling thread's message queue.
940 * ARGUMENTS:
941 * UnsafeMsg - Pointer to the structure which receives the returned message.
942 * Wnd - Window whose messages are to be retrieved.
943 * MsgFilterMin - Integer value of the lowest message value to be
944 * retrieved.
945 * MsgFilterMax - Integer value of the highest message value to be
946 * retrieved.
947 */
948 {
949 BOOL GotMessage;
950 NTUSERGETMESSAGEINFO Info;
951 NTSTATUS Status;
952 PWINDOW_OBJECT Window;
953 PMSGMEMORY MsgMemoryEntry;
954 PVOID UserMem;
955 UINT Size;
956 USER_MESSAGE Msg;
957 DECLARE_RETURN(BOOL);
958
959 DPRINT("Enter NtUserGetMessage\n");
960 UserEnterExclusive();
961
962 /* Validate input */
963 if (NULL != Wnd)
964 {
965 Window = IntGetWindowObject(Wnd);
966 if(!Window)
967 Wnd = NULL;
968 else
969 IntReleaseWindowObject(Window);
970 }
971 if (MsgFilterMax < MsgFilterMin)
972 {
973 MsgFilterMin = 0;
974 MsgFilterMax = 0;
975 }
976
977 do
978 {
979 GotMessage = co_IntPeekMessage(&Msg, Wnd, MsgFilterMin, MsgFilterMax, PM_REMOVE);
980 if (GotMessage)
981 {
982 Info.Msg = Msg.Msg;
983 /* See if this message type is present in the table */
984 MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
985 if (NULL == MsgMemoryEntry)
986 {
987 /* Not present, no copying needed */
988 Info.LParamSize = 0;
989 }
990 else
991 {
992 /* Determine required size */
993 Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
994 Info.Msg.lParam);
995 /* Allocate required amount of user-mode memory */
996 Info.LParamSize = Size;
997 UserMem = NULL;
998 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
999 &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
1000
1001 if (! NT_SUCCESS(Status))
1002 {
1003 SetLastNtError(Status);
1004 RETURN( (BOOL) -1);
1005 }
1006 /* Transfer lParam data to user-mode mem */
1007 Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
1008 if (! NT_SUCCESS(Status))
1009 {
1010 ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
1011 &Info.LParamSize, MEM_DECOMMIT);
1012 SetLastNtError(Status);
1013 RETURN( (BOOL) -1);
1014 }
1015 Info.Msg.lParam = (LPARAM) UserMem;
1016 }
1017 if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
1018 {
1019 ExFreePool((void *) Msg.Msg.lParam);
1020 }
1021 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
1022 if (! NT_SUCCESS(Status))
1023 {
1024 SetLastNtError(Status);
1025 RETURN( (BOOL) -1);
1026 }
1027 }
1028 else if (! co_IntWaitMessage(Wnd, MsgFilterMin, MsgFilterMax))
1029 {
1030 RETURN( (BOOL) -1);
1031 }
1032 }
1033 while (! GotMessage);
1034
1035 RETURN( WM_QUIT != Info.Msg.message);
1036
1037 CLEANUP:
1038 DPRINT("Leave NtUserGetMessage\n");
1039 UserLeave();
1040 END_CLEANUP;
1041 }
1042
1043 DWORD
1044 STDCALL
1045 NtUserMessageCall(
1046 DWORD Unknown0,
1047 DWORD Unknown1,
1048 DWORD Unknown2,
1049 DWORD Unknown3,
1050 DWORD Unknown4,
1051 DWORD Unknown5,
1052 DWORD Unknown6)
1053 {
1054 UNIMPLEMENTED
1055
1056 return 0;
1057 }
1058
1059 static NTSTATUS FASTCALL
1060 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
1061 {
1062 NTSTATUS Status;
1063
1064 PVOID KernelMem;
1065 UINT Size;
1066
1067 *KernelModeMsg = *UserModeMsg;
1068
1069 /* See if this message type is present in the table */
1070 if (NULL == MsgMemoryEntry)
1071 {
1072 /* Not present, no copying needed */
1073 return STATUS_SUCCESS;
1074 }
1075
1076 /* Determine required size */
1077 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1078
1079 if (0 != Size)
1080 {
1081 /* Allocate kernel mem */
1082 KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
1083 if (NULL == KernelMem)
1084 {
1085 DPRINT1("Not enough memory to copy message to kernel mem\n");
1086 return STATUS_NO_MEMORY;
1087 }
1088 KernelModeMsg->lParam = (LPARAM) KernelMem;
1089
1090 /* Copy data if required */
1091 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
1092 {
1093 Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
1094 if (! NT_SUCCESS(Status))
1095 {
1096 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
1097 ExFreePool(KernelMem);
1098 return Status;
1099 }
1100 }
1101 else
1102 {
1103 /* Make sure we don't pass any secrets to usermode */
1104 RtlZeroMemory(KernelMem, Size);
1105 }
1106 }
1107 else
1108 {
1109 KernelModeMsg->lParam = 0;
1110 }
1111
1112 return STATUS_SUCCESS;
1113 }
1114
1115 static NTSTATUS FASTCALL
1116 CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
1117 {
1118 NTSTATUS Status;
1119 PMSGMEMORY MsgMemoryEntry;
1120 UINT Size;
1121
1122 /* See if this message type is present in the table */
1123 MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
1124 if (NULL == MsgMemoryEntry)
1125 {
1126 /* Not present, no copying needed */
1127 return STATUS_SUCCESS;
1128 }
1129
1130 /* Determine required size */
1131 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
1132
1133 if (0 != Size)
1134 {
1135 /* Copy data if required */
1136 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
1137 {
1138 Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
1139 if (! NT_SUCCESS(Status))
1140 {
1141 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
1142 ExFreePool((PVOID) KernelModeMsg->lParam);
1143 return Status;
1144 }
1145 }
1146
1147 ExFreePool((PVOID) KernelModeMsg->lParam);
1148 }
1149
1150 return STATUS_SUCCESS;
1151 }
1152
1153 BOOL FASTCALL
1154 UserPostMessage(HWND Wnd,
1155 UINT Msg,
1156 WPARAM wParam,
1157 LPARAM lParam)
1158 {
1159 PWINDOW_OBJECT Window;
1160 MSG UserModeMsg, KernelModeMsg;
1161 LARGE_INTEGER LargeTickCount;
1162 NTSTATUS Status;
1163 PMSGMEMORY MsgMemoryEntry;
1164
1165 if (WM_QUIT == Msg)
1166 {
1167 MsqPostQuitMessage(PsGetWin32Thread()->MessageQueue, wParam);
1168 }
1169 else if (Wnd == HWND_BROADCAST)
1170 {
1171 HWND *List;
1172 PWINDOW_OBJECT DesktopWindow;
1173 ULONG i;
1174
1175 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
1176 List = IntWinListChildren(DesktopWindow);
1177 IntReleaseWindowObject(DesktopWindow);
1178 if (List != NULL)
1179 {
1180 for (i = 0; List[i]; i++)
1181 UserPostMessage(List[i], Msg, wParam, lParam);
1182 ExFreePool(List);
1183 }
1184 }
1185 else
1186 {
1187 Window = IntGetWindowObject(Wnd);
1188 if (NULL == Window)
1189 {
1190 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1191 return FALSE;
1192 }
1193 if(Window->Status & WINDOWSTATUS_DESTROYING)
1194 {
1195 IntReleaseWindowObject(Window);
1196 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1197 /* FIXME - last error code? */
1198 return FALSE;
1199 }
1200
1201 UserModeMsg.hwnd = Wnd;
1202 UserModeMsg.message = Msg;
1203 UserModeMsg.wParam = wParam;
1204 UserModeMsg.lParam = lParam;
1205 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1206 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1207 if (! NT_SUCCESS(Status))
1208 {
1209 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1210 return FALSE;
1211 }
1212 IntGetCursorLocation(PsGetWin32Thread()->Desktop->WindowStation,
1213 &KernelModeMsg.pt);
1214 KeQueryTickCount(&LargeTickCount);
1215 KernelModeMsg.time = LargeTickCount.u.LowPart;
1216 MsqPostMessage(Window->MessageQueue, &KernelModeMsg,
1217 NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
1218 QS_POSTMESSAGE);
1219 IntReleaseWindowObject(Window);
1220 }
1221
1222 return TRUE;
1223 }
1224
1225
1226 BOOL STDCALL
1227 NtUserPostMessage(HWND hWnd,
1228 UINT Msg,
1229 WPARAM wParam,
1230 LPARAM lParam)
1231 {
1232 DECLARE_RETURN(BOOL);
1233
1234 DPRINT("Enter NtUserPostMessage\n");
1235 UserEnterExclusive();
1236
1237 RETURN(UserPostMessage(hWnd, Msg, wParam, lParam));
1238
1239 CLEANUP:
1240 DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_);
1241 UserLeave();
1242 END_CLEANUP;
1243 }
1244
1245
1246
1247 BOOL STDCALL
1248 NtUserPostThreadMessage(DWORD idThread,
1249 UINT Msg,
1250 WPARAM wParam,
1251 LPARAM lParam)
1252 {
1253 MSG UserModeMsg, KernelModeMsg;
1254 PETHREAD peThread;
1255 PW32THREAD pThread;
1256 NTSTATUS Status;
1257 PMSGMEMORY MsgMemoryEntry;
1258 DECLARE_RETURN(BOOL);
1259
1260 DPRINT("Enter NtUserPostThreadMessage\n");
1261 UserEnterExclusive();
1262
1263 Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
1264
1265 if( Status == STATUS_SUCCESS ) {
1266 pThread = peThread->Tcb.Win32Thread;
1267 if( !pThread || !pThread->MessageQueue )
1268 {
1269 ObDereferenceObject( peThread );
1270 RETURN( FALSE);
1271 }
1272
1273 UserModeMsg.hwnd = NULL;
1274 UserModeMsg.message = Msg;
1275 UserModeMsg.wParam = wParam;
1276 UserModeMsg.lParam = lParam;
1277 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1278 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1279 if (! NT_SUCCESS(Status))
1280 {
1281 ObDereferenceObject( peThread );
1282 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1283 RETURN( FALSE);
1284 }
1285 MsqPostMessage(pThread->MessageQueue, &KernelModeMsg,
1286 NULL != MsgMemoryEntry && 0 != KernelModeMsg.lParam,
1287 QS_POSTMESSAGE);
1288 ObDereferenceObject( peThread );
1289 RETURN( TRUE);
1290 } else {
1291 SetLastNtError( Status );
1292 RETURN( FALSE);
1293 }
1294
1295 CLEANUP:
1296 DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_);
1297 UserLeave();
1298 END_CLEANUP;
1299 }
1300
1301 DWORD STDCALL
1302 NtUserQuerySendMessage(DWORD Unknown0)
1303 {
1304 UNIMPLEMENTED;
1305
1306 return 0;
1307 }
1308
1309 LRESULT FASTCALL
1310 co_IntSendMessage(HWND hWnd,
1311 UINT Msg,
1312 WPARAM wParam,
1313 LPARAM lParam)
1314 {
1315 ULONG_PTR Result = 0;
1316 if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1317 {
1318 return (LRESULT)Result;
1319 }
1320 return 0;
1321 }
1322
1323 static LRESULT FASTCALL
1324 co_IntSendMessageTimeoutSingle(HWND hWnd,
1325 UINT Msg,
1326 WPARAM wParam,
1327 LPARAM lParam,
1328 UINT uFlags,
1329 UINT uTimeout,
1330 ULONG_PTR *uResult)
1331 {
1332 ULONG_PTR Result;
1333 NTSTATUS Status;
1334 PWINDOW_OBJECT Window;
1335 PMSGMEMORY MsgMemoryEntry;
1336 INT lParamBufferSize;
1337 LPARAM lParamPacked;
1338 PW32THREAD Win32Thread;
1339
1340 /* FIXME: Call hooks. */
1341 Window = IntGetWindowObject(hWnd);
1342 if (!Window)
1343 {
1344 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1345 return FALSE;
1346 }
1347
1348 Win32Thread = PsGetWin32Thread();
1349
1350 if (NULL != Win32Thread &&
1351 Window->MessageQueue == Win32Thread->MessageQueue)
1352 {
1353 if (Win32Thread->IsExiting)
1354 {
1355 /* Never send messages to exiting threads */
1356 IntReleaseWindowObject(Window);
1357 return FALSE;
1358 }
1359
1360 /* See if this message type is present in the table */
1361 MsgMemoryEntry = FindMsgMemory(Msg);
1362 if (NULL == MsgMemoryEntry)
1363 {
1364 lParamBufferSize = -1;
1365 }
1366 else
1367 {
1368 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1369 }
1370
1371 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
1372 {
1373 IntReleaseWindowObject(Window);
1374 DPRINT1("Failed to pack message parameters\n");
1375 return FALSE;
1376 }
1377 if (0xFFFF0000 != ((DWORD) Window->WndProcW & 0xFFFF0000))
1378 {
1379 Result = (ULONG_PTR)co_IntCallWindowProc(Window->WndProcW, FALSE, hWnd, Msg, wParam,
1380 lParamPacked,lParamBufferSize);
1381 }
1382 else
1383 {
1384 Result = (ULONG_PTR)co_IntCallWindowProc(Window->WndProcA, TRUE, hWnd, Msg, wParam,
1385 lParamPacked,lParamBufferSize);
1386 }
1387
1388 if(uResult)
1389 {
1390 *uResult = Result;
1391 }
1392
1393 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
1394 {
1395 IntReleaseWindowObject(Window);
1396 DPRINT1("Failed to unpack message parameters\n");
1397 return TRUE;
1398 }
1399
1400 IntReleaseWindowObject(Window);
1401 return TRUE;
1402 }
1403
1404 if(uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
1405 {
1406 IntReleaseWindowObject(Window);
1407 /* FIXME - Set a LastError? */
1408 return FALSE;
1409 }
1410
1411 if(Window->Status & WINDOWSTATUS_DESTROYING)
1412 {
1413 IntReleaseWindowObject(Window);
1414 /* FIXME - last error? */
1415 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1416 return FALSE;
1417 }
1418
1419 Status = co_MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam,
1420 uTimeout, (uFlags & SMTO_BLOCK), FALSE, uResult);
1421 IntReleaseWindowObject(Window);
1422 if (STATUS_TIMEOUT == Status)
1423 {
1424 /* MSDN says GetLastError() should return 0 after timeout */
1425 SetLastWin32Error(0);
1426 return FALSE;
1427 }
1428 else if (! NT_SUCCESS(Status))
1429 {
1430 SetLastNtError(Status);
1431 return FALSE;
1432 }
1433
1434 return TRUE;
1435 }
1436
1437 LRESULT FASTCALL
1438 co_IntSendMessageTimeout(HWND hWnd,
1439 UINT Msg,
1440 WPARAM wParam,
1441 LPARAM lParam,
1442 UINT uFlags,
1443 UINT uTimeout,
1444 ULONG_PTR *uResult)
1445 {
1446 PWINDOW_OBJECT DesktopWindow;
1447 HWND *Children;
1448 HWND *Child;
1449
1450 if (HWND_BROADCAST != hWnd)
1451 {
1452 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1453 }
1454
1455 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
1456 if (NULL == DesktopWindow)
1457 {
1458 SetLastWin32Error(ERROR_INTERNAL_ERROR);
1459 return 0;
1460 }
1461 Children = IntWinListChildren(DesktopWindow);
1462 IntReleaseWindowObject(DesktopWindow);
1463 if (NULL == Children)
1464 {
1465 return 0;
1466 }
1467
1468 for (Child = Children; NULL != *Child; Child++)
1469 {
1470 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1471 }
1472
1473 ExFreePool(Children);
1474
1475 return (LRESULT) TRUE;
1476 }
1477
1478
1479 /* This function posts a message if the destination's message queue belongs to
1480 another thread, otherwise it sends the message. It does not support broadcast
1481 messages! */
1482 LRESULT FASTCALL
1483 co_IntPostOrSendMessage(HWND hWnd,
1484 UINT Msg,
1485 WPARAM wParam,
1486 LPARAM lParam)
1487 {
1488 ULONG_PTR Result;
1489 PWINDOW_OBJECT Window;
1490
1491 if(hWnd == HWND_BROADCAST)
1492 {
1493 return 0;
1494 }
1495
1496 Window = IntGetWindowObject(hWnd);
1497 if(!Window)
1498 {
1499 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1500 return 0;
1501 }
1502
1503 if(Window->MessageQueue != PsGetWin32Thread()->MessageQueue)
1504 {
1505 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1506 }
1507 else
1508 {
1509 if(!co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1510 {
1511 Result = 0;
1512 }
1513 }
1514
1515 IntReleaseWindowObject(Window);
1516
1517 return (LRESULT)Result;
1518 }
1519
1520 LRESULT FASTCALL
1521 co_IntDoSendMessage(HWND Wnd,
1522 UINT Msg,
1523 WPARAM wParam,
1524 LPARAM lParam,
1525 PDOSENDMESSAGE dsm,
1526 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1527 {
1528 LRESULT Result = TRUE;
1529 NTSTATUS Status;
1530 PWINDOW_OBJECT Window;
1531 NTUSERSENDMESSAGEINFO Info;
1532 MSG UserModeMsg;
1533 MSG KernelModeMsg;
1534 PMSGMEMORY MsgMemoryEntry;
1535
1536 RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
1537
1538 /* FIXME: Call hooks. */
1539 if (HWND_BROADCAST != Wnd)
1540 {
1541 Window = IntGetWindowObject(Wnd);
1542 if (NULL == Window)
1543 {
1544 /* Tell usermode to not touch this one */
1545 Info.HandledByKernel = TRUE;
1546 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1547 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1548 return 0;
1549 }
1550 }
1551
1552 /* FIXME: Check for an exiting window. */
1553
1554 /* See if the current thread can handle the message */
1555 if (HWND_BROADCAST != Wnd && NULL != PsGetWin32Thread() &&
1556 Window->MessageQueue == PsGetWin32Thread()->MessageQueue)
1557 {
1558 /* Gather the information usermode needs to call the window proc directly */
1559 Info.HandledByKernel = FALSE;
1560 if (0xFFFF0000 != ((DWORD) Window->WndProcW & 0xFFFF0000))
1561 {
1562 if (0xFFFF0000 != ((DWORD) Window->WndProcA & 0xFFFF0000))
1563 {
1564 /* Both Unicode and Ansi winprocs are real, see what usermode prefers */
1565 Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
1566 sizeof(BOOL));
1567 if (! NT_SUCCESS(Status))
1568 {
1569 Info.Ansi = ! Window->Unicode;
1570 }
1571 Info.Proc = (Info.Ansi ? Window->WndProcA : Window->WndProcW);
1572 }
1573 else
1574 {
1575 /* Real Unicode winproc */
1576 Info.Ansi = FALSE;
1577 Info.Proc = Window->WndProcW;
1578 }
1579 }
1580 else
1581 {
1582 /* Must have real Ansi winproc */
1583 Info.Ansi = TRUE;
1584 Info.Proc = Window->WndProcA;
1585 }
1586 IntReleaseWindowObject(Window);
1587 }
1588 else
1589 {
1590 /* Must be handled by other thread */
1591 if (HWND_BROADCAST != Wnd)
1592 {
1593 IntReleaseWindowObject(Window);
1594 }
1595 Info.HandledByKernel = TRUE;
1596 UserModeMsg.hwnd = Wnd;
1597 UserModeMsg.message = Msg;
1598 UserModeMsg.wParam = wParam;
1599 UserModeMsg.lParam = lParam;
1600 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1601 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1602 if (! NT_SUCCESS(Status))
1603 {
1604 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1605 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1606 return (dsm ? 0 : -1);
1607 }
1608 if(!dsm)
1609 {
1610 Result = co_IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
1611 KernelModeMsg.wParam, KernelModeMsg.lParam);
1612 }
1613 else
1614 {
1615 Result = co_IntSendMessageTimeout(KernelModeMsg.hwnd, KernelModeMsg.message,
1616 KernelModeMsg.wParam, KernelModeMsg.lParam,
1617 dsm->uFlags, dsm->uTimeout, &dsm->Result);
1618 }
1619 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1620 if (! NT_SUCCESS(Status))
1621 {
1622 MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1623 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1624 return(dsm ? 0 : -1);
1625 }
1626 }
1627
1628 Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
1629 if (! NT_SUCCESS(Status))
1630 {
1631 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1632 }
1633
1634 return (LRESULT)Result;
1635 }
1636
1637 LRESULT STDCALL
1638 NtUserSendMessageTimeout(HWND hWnd,
1639 UINT Msg,
1640 WPARAM wParam,
1641 LPARAM lParam,
1642 UINT uFlags,
1643 UINT uTimeout,
1644 ULONG_PTR *uResult,
1645 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1646 {
1647 DOSENDMESSAGE dsm;
1648 LRESULT Result;
1649 DECLARE_RETURN(BOOL);
1650
1651 DPRINT("Enter NtUserSendMessageTimeout\n");
1652 UserEnterExclusive();
1653
1654 dsm.uFlags = uFlags;
1655 dsm.uTimeout = uTimeout;
1656 Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
1657 if(uResult != NULL && Result != 0)
1658 {
1659 NTSTATUS Status;
1660
1661 Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
1662 if(!NT_SUCCESS(Status))
1663 {
1664 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1665 RETURN( FALSE);
1666 }
1667 }
1668 RETURN( Result);
1669
1670 CLEANUP:
1671 DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_);
1672 UserLeave();
1673 END_CLEANUP;
1674 }
1675
1676 LRESULT STDCALL
1677 NtUserSendMessage(HWND Wnd,
1678 UINT Msg,
1679 WPARAM wParam,
1680 LPARAM lParam,
1681 PNTUSERSENDMESSAGEINFO UnsafeInfo)
1682 {
1683 DECLARE_RETURN(BOOL);
1684
1685 DPRINT("Enter NtUserSendMessage\n");
1686 UserEnterExclusive();
1687
1688 RETURN(co_IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo));
1689
1690 CLEANUP:
1691 DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_);
1692 UserLeave();
1693 END_CLEANUP;
1694 }
1695
1696 BOOL STDCALL
1697 NtUserSendMessageCallback(HWND hWnd,
1698 UINT Msg,
1699 WPARAM wParam,
1700 LPARAM lParam,
1701 SENDASYNCPROC lpCallBack,
1702 ULONG_PTR dwData)
1703 {
1704 UNIMPLEMENTED;
1705
1706 return 0;
1707 }
1708
1709 BOOL STDCALL
1710 NtUserSendNotifyMessage(HWND hWnd,
1711 UINT Msg,
1712 WPARAM wParam,
1713 LPARAM lParam)
1714 {
1715 UNIMPLEMENTED;
1716
1717 return 0;
1718 }
1719
1720 BOOL STDCALL
1721 NtUserWaitMessage(VOID)
1722 {
1723 DECLARE_RETURN(BOOL);
1724
1725 DPRINT("EnterNtUserWaitMessage\n");
1726 UserEnterExclusive();
1727
1728 RETURN(co_IntWaitMessage(NULL, 0, 0));
1729
1730 CLEANUP:
1731 DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_);
1732 UserLeave();
1733 END_CLEANUP;
1734 }
1735
1736 DWORD STDCALL
1737 NtUserGetQueueStatus(BOOL ClearChanges)
1738 {
1739 PUSER_MESSAGE_QUEUE Queue;
1740 DWORD Result;
1741 DECLARE_RETURN(DWORD);
1742
1743 DPRINT("Enter NtUserGetQueueStatus\n");
1744 UserEnterExclusive();
1745
1746 Queue = PsGetWin32Thread()->MessageQueue;
1747
1748 Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
1749 if (ClearChanges)
1750 {
1751 Queue->ChangedBits = 0;
1752 }
1753
1754 RETURN( Result);
1755
1756 CLEANUP:
1757 DPRINT("Leave NtUserGetQueueStatus, ret=%i\n",_ret_);
1758 UserLeave();
1759 END_CLEANUP;
1760 }
1761
1762 BOOL STDCALL
1763 IntInitMessagePumpHook()
1764 {
1765 PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue++;
1766 return TRUE;
1767 }
1768
1769 BOOL STDCALL
1770 IntUninitMessagePumpHook()
1771 {
1772 if (PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue <= 0)
1773 {
1774 return FALSE;
1775 }
1776 PsGetCurrentThread()->Tcb.Win32Thread->MessagePumpHookValue--;
1777 return TRUE;
1778 }
1779
1780 /* EOF */