2a2097f67037a4ecd2b883acfd2ad4dfcc272de0
[reactos.git] / subsystems / win32 / win32k / ntuser / message.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Messages
5 * FILE: subsystems/win32/win32k/ntuser/message.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <win32k.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 BOOLEAN NTAPI PsGetProcessExitProcessCalled(PEPROCESS Process);
19
20 #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
21
22 /* FUNCTIONS *****************************************************************/
23
24 NTSTATUS FASTCALL
25 IntInitMessageImpl(VOID)
26 {
27 return STATUS_SUCCESS;
28 }
29
30 NTSTATUS FASTCALL
31 IntCleanupMessageImpl(VOID)
32 {
33 return STATUS_SUCCESS;
34 }
35
36 /* From wine: */
37 /* flag for messages that contain pointers */
38 /* 32 messages per entry, messages 0..31 map to bits 0..31 */
39
40 #define SET(msg) (1 << ((msg) & 31))
41
42 static const unsigned int message_pointer_flags[] =
43 {
44 /* 0x00 - 0x1f */
45 SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
46 SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
47 /* 0x20 - 0x3f */
48 SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
49 SET(WM_COMPAREITEM),
50 /* 0x40 - 0x5f */
51 SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
52 SET(WM_COPYGLOBALDATA) | SET(WM_NOTIFY) | SET(WM_HELP),
53 /* 0x60 - 0x7f */
54 SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
55 /* 0x80 - 0x9f */
56 SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
57 /* 0xa0 - 0xbf */
58 SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
59 /* 0xc0 - 0xdf */
60 SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
61 /* 0xe0 - 0xff */
62 SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO),
63 /* 0x100 - 0x11f */
64 0,
65 /* 0x120 - 0x13f */
66 0,
67 /* 0x140 - 0x15f */
68 SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
69 SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
70 SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
71 /* 0x160 - 0x17f */
72 0,
73 /* 0x180 - 0x19f */
74 SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
75 SET(LB_DIR) | SET(LB_FINDSTRING) |
76 SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
77 /* 0x1a0 - 0x1bf */
78 SET(LB_FINDSTRINGEXACT),
79 /* 0x1c0 - 0x1df */
80 0,
81 /* 0x1e0 - 0x1ff */
82 0,
83 /* 0x200 - 0x21f */
84 SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
85 /* 0x220 - 0x23f */
86 SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
87 SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
88 /* 0x240 - 0x25f */
89 0,
90 /* 0x260 - 0x27f */
91 0,
92 /* 0x280 - 0x29f */
93 0,
94 /* 0x2a0 - 0x2bf */
95 0,
96 /* 0x2c0 - 0x2df */
97 0,
98 /* 0x2e0 - 0x2ff */
99 0,
100 /* 0x300 - 0x31f */
101 SET(WM_ASKCBFORMATNAME)
102 };
103
104 /* check whether a given message type includes pointers */
105 static inline int is_pointer_message( UINT message )
106 {
107 if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
108 return (message_pointer_flags[message / 32] & SET(message)) != 0;
109 }
110
111 #define MMS_SIZE_WPARAM -1
112 #define MMS_SIZE_WPARAMWCHAR -2
113 #define MMS_SIZE_LPARAMSZ -3
114 #define MMS_SIZE_SPECIAL -4
115 #define MMS_FLAG_READ 0x01
116 #define MMS_FLAG_WRITE 0x02
117 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
118 typedef struct tagMSGMEMORY
119 {
120 UINT Message;
121 UINT Size;
122 INT Flags;
123 }
124 MSGMEMORY, *PMSGMEMORY;
125
126 static MSGMEMORY MsgMemory[] =
127 {
128 { WM_CREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
129 { WM_DDE_ACK, sizeof(KMDDELPARAM), MMS_FLAG_READ },
130 { WM_DDE_EXECUTE, MMS_SIZE_WPARAM, MMS_FLAG_READ },
131 { WM_GETMINMAXINFO, sizeof(MINMAXINFO), MMS_FLAG_READWRITE },
132 { WM_GETTEXT, MMS_SIZE_WPARAMWCHAR, MMS_FLAG_WRITE },
133 { WM_NCCALCSIZE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
134 { WM_NCCREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
135 { WM_SETTEXT, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ },
136 { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ },
137 { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE },
138 { WM_COPYDATA, MMS_SIZE_SPECIAL, MMS_FLAG_READ },
139 { WM_COPYGLOBALDATA, MMS_SIZE_WPARAM, MMS_FLAG_READ },
140 { WM_WINDOWPOSCHANGED, sizeof(WINDOWPOS), MMS_FLAG_READ },
141 { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
142 };
143
144 static PMSGMEMORY FASTCALL
145 FindMsgMemory(UINT Msg)
146 {
147 PMSGMEMORY MsgMemoryEntry;
148
149 /* See if this message type is present in the table */
150 for (MsgMemoryEntry = MsgMemory;
151 MsgMemoryEntry < MsgMemory + sizeof(MsgMemory) / sizeof(MSGMEMORY);
152 MsgMemoryEntry++)
153 {
154 if (Msg == MsgMemoryEntry->Message)
155 {
156 return MsgMemoryEntry;
157 }
158 }
159
160 return NULL;
161 }
162
163 static UINT FASTCALL
164 MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
165 {
166 CREATESTRUCTW *Cs;
167 PUNICODE_STRING WindowName;
168 PUNICODE_STRING ClassName;
169 UINT Size = 0;
170
171 _SEH2_TRY
172 {
173 if (MMS_SIZE_WPARAM == MsgMemoryEntry->Size)
174 {
175 Size = (UINT)wParam;
176 }
177 else if (MMS_SIZE_WPARAMWCHAR == MsgMemoryEntry->Size)
178 {
179 Size = (UINT) (wParam * sizeof(WCHAR));
180 }
181 else if (MMS_SIZE_LPARAMSZ == MsgMemoryEntry->Size)
182 {
183 Size = (UINT) ((wcslen((PWSTR) lParam) + 1) * sizeof(WCHAR));
184 }
185 else if (MMS_SIZE_SPECIAL == MsgMemoryEntry->Size)
186 {
187 switch(MsgMemoryEntry->Message)
188 {
189 case WM_CREATE:
190 case WM_NCCREATE:
191 Cs = (CREATESTRUCTW *) lParam;
192 WindowName = (PUNICODE_STRING) Cs->lpszName;
193 ClassName = (PUNICODE_STRING) Cs->lpszClass;
194 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
195 if (IS_ATOM(ClassName->Buffer))
196 {
197 Size += sizeof(WCHAR) + sizeof(ATOM);
198 }
199 else
200 {
201 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
202 }
203 break;
204
205 case WM_NCCALCSIZE:
206 Size = wParam ? sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) : sizeof(RECT);
207 break;
208
209 case WM_COPYDATA:
210 Size = sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
211 break;
212
213 default:
214 ASSERT(FALSE);
215 Size = 0;
216 break;
217 }
218 }
219 else
220 {
221 Size = MsgMemoryEntry->Size;
222 }
223 }
224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
225 {
226 DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
227 Size = 0;
228 }
229 _SEH2_END;
230 return Size;
231 }
232
233 static NTSTATUS
234 PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolNeeded)
235 {
236 NCCALCSIZE_PARAMS *UnpackedNcCalcsize;
237 NCCALCSIZE_PARAMS *PackedNcCalcsize;
238 CREATESTRUCTW *UnpackedCs;
239 CREATESTRUCTW *PackedCs;
240 PLARGE_STRING WindowName;
241 PUNICODE_STRING ClassName;
242 POOL_TYPE PoolType;
243 UINT Size;
244 PCHAR CsData;
245
246 *lParamPacked = lParam;
247
248 if (NonPagedPoolNeeded)
249 PoolType = NonPagedPool;
250 else
251 PoolType = PagedPool;
252
253 if (WM_NCCALCSIZE == Msg && wParam)
254 {
255
256 UnpackedNcCalcsize = (NCCALCSIZE_PARAMS *) lParam;
257 PackedNcCalcsize = ExAllocatePoolWithTag(PoolType,
258 sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS),
259 TAG_MSG);
260
261 if (NULL == PackedNcCalcsize)
262 {
263 DPRINT1("Not enough memory to pack lParam\n");
264 return STATUS_NO_MEMORY;
265 }
266 RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS));
267 PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1);
268 RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS));
269 *lParamPacked = (LPARAM) PackedNcCalcsize;
270 }
271 else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
272 {
273 UnpackedCs = (CREATESTRUCTW *) lParam;
274 WindowName = (PLARGE_STRING) UnpackedCs->lpszName;
275 ClassName = (PUNICODE_STRING) UnpackedCs->lpszClass;
276 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
277 if (IS_ATOM(ClassName->Buffer))
278 {
279 Size += sizeof(WCHAR) + sizeof(ATOM);
280 }
281 else
282 {
283 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
284 }
285 PackedCs = ExAllocatePoolWithTag(PoolType, Size, TAG_MSG);
286 if (NULL == PackedCs)
287 {
288 DPRINT1("Not enough memory to pack lParam\n");
289 return STATUS_NO_MEMORY;
290 }
291 RtlCopyMemory(PackedCs, UnpackedCs, sizeof(CREATESTRUCTW));
292 CsData = (PCHAR) (PackedCs + 1);
293 PackedCs->lpszName = (LPCWSTR) (CsData - (PCHAR) PackedCs);
294 RtlCopyMemory(CsData, WindowName->Buffer, WindowName->Length);
295 CsData += WindowName->Length;
296 *((WCHAR *) CsData) = L'\0';
297 CsData += sizeof(WCHAR);
298 PackedCs->lpszClass = (LPCWSTR) (CsData - (PCHAR) PackedCs);
299 if (IS_ATOM(ClassName->Buffer))
300 {
301 *((WCHAR *) CsData) = L'A';
302 CsData += sizeof(WCHAR);
303 *((ATOM *) CsData) = (ATOM)(DWORD_PTR) ClassName->Buffer;
304 CsData += sizeof(ATOM);
305 }
306 else
307 {
308 *((WCHAR *) CsData) = L'S';
309 CsData += sizeof(WCHAR);
310 RtlCopyMemory(CsData, ClassName->Buffer, ClassName->Length);
311 CsData += ClassName->Length;
312 *((WCHAR *) CsData) = L'\0';
313 CsData += sizeof(WCHAR);
314 }
315 ASSERT(CsData == (PCHAR) PackedCs + Size);
316 *lParamPacked = (LPARAM) PackedCs;
317 }
318 else if (PoolType == NonPagedPool)
319 {
320 PMSGMEMORY MsgMemoryEntry;
321 PVOID PackedData;
322 SIZE_T size;
323
324 MsgMemoryEntry = FindMsgMemory(Msg);
325
326 if ((!MsgMemoryEntry) || (MsgMemoryEntry->Size < 0))
327 {
328 /* Keep previous behavior */
329 return STATUS_SUCCESS;
330 }
331 size = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
332 if (!size)
333 {
334 DPRINT1("No size for lParamPacked\n");
335 return STATUS_SUCCESS;
336 }
337 PackedData = ExAllocatePoolWithTag(NonPagedPool, size, TAG_MSG);
338 RtlCopyMemory(PackedData, (PVOID)lParam, MsgMemorySize(MsgMemoryEntry, wParam, lParam));
339 *lParamPacked = (LPARAM)PackedData;
340 }
341
342 return STATUS_SUCCESS;
343 }
344
345 static NTSTATUS
346 UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolUsed)
347 {
348 NCCALCSIZE_PARAMS *UnpackedParams;
349 NCCALCSIZE_PARAMS *PackedParams;
350 PWINDOWPOS UnpackedWindowPos;
351
352 if (lParamPacked == lParam)
353 {
354 return STATUS_SUCCESS;
355 }
356
357 if (WM_NCCALCSIZE == Msg && wParam)
358 {
359 PackedParams = (NCCALCSIZE_PARAMS *) lParamPacked;
360 UnpackedParams = (NCCALCSIZE_PARAMS *) lParam;
361 UnpackedWindowPos = UnpackedParams->lppos;
362 RtlCopyMemory(UnpackedParams, PackedParams, sizeof(NCCALCSIZE_PARAMS));
363 UnpackedParams->lppos = UnpackedWindowPos;
364 RtlCopyMemory(UnpackedWindowPos, PackedParams + 1, sizeof(WINDOWPOS));
365 ExFreePool((PVOID) lParamPacked);
366
367 return STATUS_SUCCESS;
368 }
369 else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
370 {
371 ExFreePool((PVOID) lParamPacked);
372
373 return STATUS_SUCCESS;
374 }
375 else if (NonPagedPoolUsed)
376 {
377 PMSGMEMORY MsgMemoryEntry;
378 MsgMemoryEntry = FindMsgMemory(Msg);
379 if (MsgMemoryEntry->Size < 0)
380 {
381 /* Keep previous behavior */
382 return STATUS_INVALID_PARAMETER;
383 }
384
385 if (MsgMemory->Flags == MMS_FLAG_READWRITE)
386 {
387 //RtlCopyMemory((PVOID)lParam, (PVOID)lParamPacked, MsgMemory->Size);
388 }
389 ExFreePool((PVOID) lParamPacked);
390 return STATUS_SUCCESS;
391 }
392
393 ASSERT(FALSE);
394
395 return STATUS_INVALID_PARAMETER;
396 }
397
398 static NTSTATUS FASTCALL
399 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
400 {
401 NTSTATUS Status;
402
403 PVOID KernelMem;
404 UINT Size;
405
406 *KernelModeMsg = *UserModeMsg;
407
408 /* See if this message type is present in the table */
409 if (NULL == MsgMemoryEntry)
410 {
411 /* Not present, no copying needed */
412 return STATUS_SUCCESS;
413 }
414
415 /* Determine required size */
416 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
417
418 if (0 != Size)
419 {
420 /* Allocate kernel mem */
421 KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
422 if (NULL == KernelMem)
423 {
424 DPRINT1("Not enough memory to copy message to kernel mem\n");
425 return STATUS_NO_MEMORY;
426 }
427 KernelModeMsg->lParam = (LPARAM) KernelMem;
428
429 /* Copy data if required */
430 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
431 {
432 Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
433 if (! NT_SUCCESS(Status))
434 {
435 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
436 ExFreePoolWithTag(KernelMem, TAG_MSG);
437 return Status;
438 }
439 }
440 else
441 {
442 /* Make sure we don't pass any secrets to usermode */
443 RtlZeroMemory(KernelMem, Size);
444 }
445 }
446 else
447 {
448 KernelModeMsg->lParam = 0;
449 }
450
451 return STATUS_SUCCESS;
452 }
453
454 static NTSTATUS FASTCALL
455 CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
456 {
457 NTSTATUS Status;
458 PMSGMEMORY MsgMemoryEntry;
459 UINT Size;
460
461 /* See if this message type is present in the table */
462 MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
463 if (NULL == MsgMemoryEntry)
464 {
465 /* Not present, no copying needed */
466 return STATUS_SUCCESS;
467 }
468
469 /* Determine required size */
470 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
471
472 if (0 != Size)
473 {
474 /* Copy data if required */
475 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
476 {
477 Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
478 if (! NT_SUCCESS(Status))
479 {
480 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
481 ExFreePool((PVOID) KernelModeMsg->lParam);
482 return Status;
483 }
484 }
485
486 ExFreePool((PVOID) KernelModeMsg->lParam);
487 }
488
489 return STATUS_SUCCESS;
490 }
491
492 //
493 // Wakeup any thread/process waiting on idle input.
494 //
495 VOID FASTCALL
496 IdlePing(VOID)
497 {
498 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
499 PUSER_MESSAGE_QUEUE ForegroundQueue;
500 PTHREADINFO pti, ptiForeground = NULL;
501
502 ForegroundQueue = IntGetFocusMessageQueue();
503
504 if (ForegroundQueue)
505 ptiForeground = ForegroundQueue->Thread->Tcb.Win32Thread;
506
507 pti = PsGetCurrentThreadWin32Thread();
508
509 if ( pti )
510 {
511 pti->pClientInfo->cSpins = 0; // Reset spins.
512
513 if ( pti->pDeskInfo && pti == ptiForeground )
514 {
515 if ( pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) ||
516 pti->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) )
517 {
518 co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0);
519 }
520 }
521 }
522
523 DPRINT("IdlePing ppi 0x%x\n",ppi);
524 if ( ppi && ppi->InputIdleEvent )
525 {
526 DPRINT("InputIdleEvent\n");
527 KeSetEvent( ppi->InputIdleEvent, IO_NO_INCREMENT, FALSE);
528 }
529 }
530
531 VOID FASTCALL
532 IdlePong(VOID)
533 {
534 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
535
536 DPRINT("IdlePong ppi 0x%x\n",ppi);
537 if ( ppi && ppi->InputIdleEvent )
538 {
539 KeClearEvent(ppi->InputIdleEvent);
540 }
541 }
542
543 UINT FASTCALL
544 GetWakeMask(UINT first, UINT last )
545 {
546 UINT mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
547
548 if (first || last)
549 {
550 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
551 if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
552 ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
553 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
554 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
555 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
556 }
557 else mask = QS_ALLINPUT;
558
559 return mask;
560 }
561
562 static VOID FASTCALL
563 IntCallWndProc( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
564 {
565 BOOL SameThread = FALSE;
566 CWPSTRUCT CWP;
567
568 if (Window->head.pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
569 SameThread = TRUE;
570
571 CWP.hwnd = hWnd;
572 CWP.message = Msg;
573 CWP.wParam = wParam;
574 CWP.lParam = lParam;
575 co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP );
576 }
577
578 static VOID FASTCALL
579 IntCallWndProcRet ( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *uResult)
580 {
581 BOOL SameThread = FALSE;
582 CWPRETSTRUCT CWPR;
583
584 if (Window->head.pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
585 SameThread = TRUE;
586
587 CWPR.hwnd = hWnd;
588 CWPR.message = Msg;
589 CWPR.wParam = wParam;
590 CWPR.lParam = lParam;
591 CWPR.lResult = *uResult;
592 co_HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, SameThread, (LPARAM)&CWPR );
593 }
594
595 LRESULT FASTCALL
596 IntDispatchMessage(PMSG pMsg)
597 {
598 LARGE_INTEGER TickCount;
599 LONG Time;
600 LRESULT retval = 0;
601 PTHREADINFO pti;
602 PWND Window = NULL;
603
604 if (pMsg->hwnd)
605 {
606 Window = UserGetWindowObject(pMsg->hwnd);
607 if (!Window) return 0;
608 }
609
610 pti = PsGetCurrentThreadWin32Thread();
611
612 if ( Window->head.pti != pti)
613 {
614 EngSetLastError( ERROR_MESSAGE_SYNC_ONLY );
615 return 0;
616 }
617
618 if (((pMsg->message == WM_SYSTIMER) ||
619 (pMsg->message == WM_TIMER)) &&
620 (pMsg->lParam) )
621 {
622 if (pMsg->message == WM_TIMER)
623 {
624 if (ValidateTimerCallback(pti,pMsg->lParam))
625 {
626 KeQueryTickCount(&TickCount);
627 Time = MsqCalculateMessageTime(&TickCount);
628 retval = co_IntCallWindowProc((WNDPROC)pMsg->lParam,
629 TRUE,
630 pMsg->hwnd,
631 WM_TIMER,
632 pMsg->wParam,
633 (LPARAM)Time,
634 0);
635 }
636 return retval;
637 }
638 else
639 {
640 PTIMER pTimer = FindSystemTimer(pMsg);
641 if (pTimer && pTimer->pfn)
642 {
643 KeQueryTickCount(&TickCount);
644 Time = MsqCalculateMessageTime(&TickCount);
645 pTimer->pfn(pMsg->hwnd, WM_SYSTIMER, (UINT)pMsg->wParam, Time);
646 }
647 return 0;
648 }
649 }
650 // Need a window!
651 if ( !Window ) return 0;
652
653 /* Since we are doing a callback on the same thread right away, there is
654 no need to copy the lparam to kernel mode and then back to usermode.
655 We just pretend it isn't a pointer */
656
657 retval = co_IntCallWindowProc( Window->lpfnWndProc,
658 !Window->Unicode,
659 pMsg->hwnd,
660 pMsg->message,
661 pMsg->wParam,
662 pMsg->lParam,
663 0);
664
665 if (pMsg->message == WM_PAINT)
666 {
667 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
668 HRGN hrgn = IntSysCreateRectRgn( 0, 0, 0, 0 );
669 co_UserGetUpdateRgn( Window, hrgn, TRUE );
670 REGION_FreeRgnByHandle( hrgn );
671 }
672
673 return retval;
674 }
675
676 /*
677 * Internal version of PeekMessage() doing all the work
678 */
679 BOOL FASTCALL
680 co_IntPeekMessage( PMSG Msg,
681 PWND Window,
682 UINT MsgFilterMin,
683 UINT MsgFilterMax,
684 UINT RemoveMsg,
685 BOOL bGMSG )
686 {
687 PTHREADINFO pti;
688 PCLIENTINFO pci;
689 LARGE_INTEGER LargeTickCount;
690 PUSER_MESSAGE_QUEUE ThreadQueue;
691 BOOL RemoveMessages;
692 UINT ProcessMask;
693 BOOL Hit = FALSE;
694
695 pti = PsGetCurrentThreadWin32Thread();
696 ThreadQueue = pti->MessageQueue;
697 pci = pti->pClientInfo;
698
699 RemoveMessages = RemoveMsg & PM_REMOVE;
700 ProcessMask = HIWORD(RemoveMsg);
701
702 /* Hint, "If wMsgFilterMin and wMsgFilterMax are both zero, PeekMessage returns
703 all available messages (that is, no range filtering is performed)". */
704 if (!ProcessMask) ProcessMask = (QS_ALLPOSTMESSAGE|QS_ALLINPUT);
705
706 IdlePong();
707
708 do
709 {
710 KeQueryTickCount(&LargeTickCount);
711 ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
712 pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart;
713
714 /* Dispatch sent messages here. */
715 while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
716 {
717 /* if some PM_QS* flags were specified, only handle sent messages from now on */
718 if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE; // wine does this; ProcessMask = QS_SENDMESSAGE;
719 }
720 if (Hit) return FALSE;
721
722 /* Clear changed bits so we can wait on them if we don't find a message */
723 if (ProcessMask & QS_POSTMESSAGE)
724 {
725 pti->pcti->fsChangeBits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER);
726 if (MsgFilterMin == 0 && MsgFilterMax == 0) // wine hack does this; ~0U)
727 {
728 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
729 }
730 }
731
732 if (ProcessMask & QS_INPUT)
733 {
734 pti->pcti->fsChangeBits &= ~QS_INPUT;
735 }
736
737 /* Now check for normal messages. */
738 if ((ProcessMask & QS_POSTMESSAGE) &&
739 MsqPeekMessage( ThreadQueue,
740 RemoveMessages,
741 Window,
742 MsgFilterMin,
743 MsgFilterMax,
744 ProcessMask,
745 Msg ))
746 {
747 return TRUE;
748 }
749
750 /* Now look for a quit message. */
751 if (ThreadQueue->QuitPosted)
752 {
753 /* According to the PSDK, WM_QUIT messages are always returned, regardless
754 of the filter specified */
755 Msg->hwnd = NULL;
756 Msg->message = WM_QUIT;
757 Msg->wParam = ThreadQueue->QuitExitCode;
758 Msg->lParam = 0;
759 if (RemoveMessages)
760 {
761 ThreadQueue->QuitPosted = FALSE;
762 ClearMsgBitsMask(ThreadQueue, QS_POSTMESSAGE);
763 pti->pcti->fsWakeBits &= ~QS_ALLPOSTMESSAGE;
764 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
765 }
766 return TRUE;
767 }
768
769 /* Check for hardware events. */
770 if ((ProcessMask & QS_MOUSE) &&
771 co_MsqPeekMouseMove( ThreadQueue,
772 RemoveMessages,
773 Window,
774 MsgFilterMin,
775 MsgFilterMax,
776 Msg ))
777 {
778 return TRUE;
779 }
780
781 if ((ProcessMask & QS_INPUT) &&
782 co_MsqPeekHardwareMessage( ThreadQueue,
783 RemoveMessages,
784 Window,
785 MsgFilterMin,
786 MsgFilterMax,
787 ProcessMask,
788 Msg))
789 {
790 return TRUE;
791 }
792
793 /* Check for sent messages again. */
794 while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
795 {
796 if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE;
797 }
798 if (Hit) return FALSE;
799
800 /* Check for paint messages. */
801 if ((ProcessMask & QS_PAINT) &&
802 pti->cPaintsReady &&
803 IntGetPaintMessage( Window,
804 MsgFilterMin,
805 MsgFilterMax,
806 pti,
807 Msg,
808 RemoveMessages))
809 {
810 return TRUE;
811 }
812
813 /* This is correct, check for the current threads timers waiting to be
814 posted to this threads message queue. If any we loop again.
815 */
816 if ((ProcessMask & QS_TIMER) &&
817 PostTimerMessages(Window))
818 {
819 continue;
820 }
821
822 return FALSE;
823 }
824 while (TRUE);
825
826 return TRUE;
827 }
828
829 static BOOL FASTCALL
830 co_IntWaitMessage( PWND Window,
831 UINT MsgFilterMin,
832 UINT MsgFilterMax )
833 {
834 PTHREADINFO pti;
835 PUSER_MESSAGE_QUEUE ThreadQueue;
836 NTSTATUS Status = STATUS_SUCCESS;
837 MSG Msg;
838
839 pti = PsGetCurrentThreadWin32Thread();
840 ThreadQueue = pti->MessageQueue;
841
842 do
843 {
844 if ( co_IntPeekMessage( &Msg, // Dont reenter!
845 Window,
846 MsgFilterMin,
847 MsgFilterMax,
848 MAKELONG( PM_NOREMOVE, GetWakeMask( MsgFilterMin, MsgFilterMax)),
849 TRUE ) ) // act like GetMessage.
850 {
851 return TRUE;
852 }
853
854 /* Nothing found. Wait for new messages. */
855 Status = co_MsqWaitForNewMessages( ThreadQueue,
856 Window,
857 MsgFilterMin,
858 MsgFilterMax);
859 if (!NT_SUCCESS(Status))
860 {
861 SetLastNtError(Status);
862 DPRINT1("Exit co_IntWaitMessage on error!\n");
863 return FALSE;
864 }
865 if (Status == STATUS_USER_APC || Status == STATUS_TIMEOUT)
866 {
867 return FALSE;
868 }
869 }
870 while ( TRUE );
871
872 return FALSE;
873 }
874
875 BOOL FASTCALL
876 co_IntGetPeekMessage( PMSG pMsg,
877 HWND hWnd,
878 UINT MsgFilterMin,
879 UINT MsgFilterMax,
880 UINT RemoveMsg,
881 BOOL bGMSG )
882 {
883 PWND Window;
884 PTHREADINFO pti;
885 BOOL Present = FALSE;
886 NTSTATUS Status;
887
888 if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST )
889 hWnd = HWND_BOTTOM;
890
891 /* Validate input */
892 if (hWnd && hWnd != HWND_BOTTOM)
893 {
894 if (!(Window = UserGetWindowObject(hWnd)))
895 {
896 if (bGMSG)
897 return -1;
898 else
899 return FALSE;
900 }
901 }
902 else
903 {
904 Window = (PWND)hWnd;
905 }
906
907 if (MsgFilterMax < MsgFilterMin)
908 {
909 MsgFilterMin = 0;
910 MsgFilterMax = 0;
911 }
912
913 if (bGMSG)
914 {
915 RemoveMsg |= ((GetWakeMask( MsgFilterMin, MsgFilterMax ))<< 16);
916 }
917
918 pti = PsGetCurrentThreadWin32Thread();
919 pti->pClientInfo->cSpins++; // Bump up the spin count.
920
921 do
922 {
923 Present = co_IntPeekMessage( pMsg,
924 Window,
925 MsgFilterMin,
926 MsgFilterMax,
927 RemoveMsg,
928 bGMSG );
929 if (Present)
930 {
931 /* GetMessage or PostMessage must never get messages that contain pointers */
932 ASSERT(FindMsgMemory(pMsg->message) == NULL);
933
934 if (pMsg->message != WM_PAINT && pMsg->message != WM_QUIT)
935 {
936 pti->timeLast = pMsg->time;
937 pti->ptLast = pMsg->pt;
938 }
939
940 // The WH_GETMESSAGE hook enables an application to monitor messages about to
941 // be returned by the GetMessage or PeekMessage function.
942
943 co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg);
944
945 if ( bGMSG ) break;
946 }
947
948 if ( bGMSG )
949 {
950 Status = co_MsqWaitForNewMessages( pti->MessageQueue,
951 Window,
952 MsgFilterMin,
953 MsgFilterMax);
954 if ( !NT_SUCCESS(Status) ||
955 Status == STATUS_USER_APC ||
956 Status == STATUS_TIMEOUT )
957 {
958 Present = -1;
959 break;
960 }
961 }
962 else
963 {
964 if (!(RemoveMsg & PM_NOYIELD))
965 {
966 IdlePing();
967 // Yield this thread!
968 UserLeave();
969 ZwYieldExecution();
970 UserEnterExclusive();
971 // Fall through to exit.
972 IdlePong();
973 }
974 break;
975 }
976 }
977 while( bGMSG && !Present );
978
979 // Been spinning, time to swap vinyl...
980 if (pti->pClientInfo->cSpins >= 100)
981 {
982 // Clear the spin cycle to fix the mix.
983 pti->pClientInfo->cSpins = 0;
984 //if (!(pti->TIF_flags & TIF_SPINNING)) FIXME need to swap vinyl..
985 }
986 return Present;
987 }
988
989 BOOL FASTCALL
990 UserPostThreadMessage( DWORD idThread,
991 UINT Msg,
992 WPARAM wParam,
993 LPARAM lParam )
994 {
995 MSG Message;
996 PETHREAD peThread;
997 PTHREADINFO pThread;
998 LARGE_INTEGER LargeTickCount;
999 NTSTATUS Status;
1000
1001 if (is_pointer_message(Msg))
1002 {
1003 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1004 return FALSE;
1005 }
1006
1007 Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
1008
1009 if( Status == STATUS_SUCCESS )
1010 {
1011 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
1012 if( !pThread ||
1013 !pThread->MessageQueue ||
1014 (pThread->TIF_flags & TIF_INCLEANUP))
1015 {
1016 ObDereferenceObject( peThread );
1017 return FALSE;
1018 }
1019
1020 Message.hwnd = NULL;
1021 Message.message = Msg;
1022 Message.wParam = wParam;
1023 Message.lParam = lParam;
1024 Message.pt = gpsi->ptCursor;
1025
1026 KeQueryTickCount(&LargeTickCount);
1027 Message.time = MsqCalculateMessageTime(&LargeTickCount);
1028 MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1029 ObDereferenceObject( peThread );
1030 return TRUE;
1031 }
1032 else
1033 {
1034 SetLastNtError( Status );
1035 }
1036 return FALSE;
1037 }
1038
1039 BOOL FASTCALL
1040 UserPostMessage( HWND Wnd,
1041 UINT Msg,
1042 WPARAM wParam,
1043 LPARAM lParam )
1044 {
1045 PTHREADINFO pti;
1046 MSG Message, KernelModeMsg;
1047 LARGE_INTEGER LargeTickCount;
1048
1049 Message.hwnd = Wnd;
1050 Message.message = Msg;
1051 Message.wParam = wParam;
1052 Message.lParam = lParam;
1053 Message.pt = gpsi->ptCursor;
1054 KeQueryTickCount(&LargeTickCount);
1055 Message.time = MsqCalculateMessageTime(&LargeTickCount);
1056
1057 if (is_pointer_message(Message.message))
1058 {
1059 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1060 return FALSE;
1061 }
1062
1063 if( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST )
1064 {
1065 NTSTATUS Status;
1066 PMSGMEMORY MsgMemoryEntry;
1067
1068 MsgMemoryEntry = FindMsgMemory(Message.message);
1069
1070 Status = CopyMsgToKernelMem(&KernelModeMsg, &Message, MsgMemoryEntry);
1071 if (! NT_SUCCESS(Status))
1072 {
1073 EngSetLastError(ERROR_INVALID_PARAMETER);
1074 return FALSE;
1075 }
1076 co_IntSendMessageNoWait(KernelModeMsg.hwnd,
1077 KernelModeMsg.message,
1078 KernelModeMsg.wParam,
1079 KernelModeMsg.lParam);
1080
1081 if (MsgMemoryEntry && KernelModeMsg.lParam)
1082 ExFreePool((PVOID) KernelModeMsg.lParam);
1083
1084 return TRUE;
1085 }
1086
1087 if (!Wnd)
1088 {
1089 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1090 Msg,
1091 wParam,
1092 lParam);
1093 }
1094 if (Wnd == HWND_BROADCAST)
1095 {
1096 HWND *List;
1097 PWND DesktopWindow;
1098 ULONG i;
1099
1100 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1101 List = IntWinListChildren(DesktopWindow);
1102
1103 if (List != NULL)
1104 {
1105 UserPostMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1106 for (i = 0; List[i]; i++)
1107 {
1108 UserPostMessage(List[i], Msg, wParam, lParam);
1109 }
1110 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1111 }
1112 }
1113 else
1114 {
1115 PWND Window;
1116
1117 Window = UserGetWindowObject(Wnd);
1118 if ( !Window )
1119 {
1120 return FALSE;
1121 }
1122
1123 pti = Window->head.pti;
1124 if ( pti->TIF_flags & TIF_INCLEANUP )
1125 {
1126 DPRINT1("Attempted to post message to window 0x%x when the thread is in cleanup!\n", Wnd);
1127 return FALSE;
1128 }
1129
1130 if ( Window->state & WNDS_DESTROYED )
1131 {
1132 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1133 /* FIXME - last error code? */
1134 return FALSE;
1135 }
1136
1137 if (WM_QUIT == Msg)
1138 {
1139 MsqPostQuitMessage(Window->head.pti->MessageQueue, wParam);
1140 }
1141 else
1142 {
1143 MsqPostMessage(Window->head.pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1144 }
1145 }
1146 return TRUE;
1147 }
1148
1149
1150 LRESULT FASTCALL
1151 co_IntSendMessage( HWND hWnd,
1152 UINT Msg,
1153 WPARAM wParam,
1154 LPARAM lParam )
1155 {
1156 ULONG_PTR Result = 0;
1157 if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1158 {
1159 return (LRESULT)Result;
1160 }
1161 return 0;
1162 }
1163
1164 static LRESULT FASTCALL
1165 co_IntSendMessageTimeoutSingle( HWND hWnd,
1166 UINT Msg,
1167 WPARAM wParam,
1168 LPARAM lParam,
1169 UINT uFlags,
1170 UINT uTimeout,
1171 ULONG_PTR *uResult )
1172 {
1173 NTSTATUS Status;
1174 PWND Window = NULL;
1175 PMSGMEMORY MsgMemoryEntry;
1176 INT lParamBufferSize;
1177 LPARAM lParamPacked;
1178 PTHREADINFO Win32Thread;
1179 ULONG_PTR Result = 0;
1180 DECLARE_RETURN(LRESULT);
1181 USER_REFERENCE_ENTRY Ref;
1182
1183 if (!(Window = UserGetWindowObject(hWnd)))
1184 {
1185 RETURN( FALSE);
1186 }
1187
1188 UserRefObjectCo(Window, &Ref);
1189
1190 Win32Thread = PsGetCurrentThreadWin32Thread();
1191
1192 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1193
1194 if ( NULL != Win32Thread &&
1195 Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1196 {
1197 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1198 {
1199 /* Never send messages to exiting threads */
1200 RETURN( FALSE);
1201 }
1202
1203 /* See if this message type is present in the table */
1204 MsgMemoryEntry = FindMsgMemory(Msg);
1205 if (NULL == MsgMemoryEntry)
1206 {
1207 lParamBufferSize = -1;
1208 }
1209 else
1210 {
1211 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1212 }
1213
1214 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
1215 {
1216 DPRINT1("Failed to pack message parameters\n");
1217 RETURN( FALSE);
1218 }
1219
1220 ObReferenceObject(Win32Thread->pEThread);
1221 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1222 !Window->Unicode,
1223 hWnd,
1224 Msg,
1225 wParam,
1226 lParamPacked,
1227 lParamBufferSize );
1228 if(uResult)
1229 {
1230 *uResult = Result;
1231 }
1232
1233 ObDereferenceObject(Win32Thread->pEThread);
1234
1235 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1236
1237 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1238 {
1239 DPRINT1("Failed to unpack message parameters\n");
1240 RETURN( TRUE);
1241 }
1242
1243 RETURN( TRUE);
1244 }
1245
1246 if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->head.pti->MessageQueue))
1247 {
1248 // FIXME - Set window hung and add to a list.
1249 /* FIXME - Set a LastError? */
1250 RETURN( FALSE);
1251 }
1252
1253 if (Window->state & WNDS_DESTROYED)
1254 {
1255 /* FIXME - last error? */
1256 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1257 RETURN( FALSE);
1258 }
1259
1260 do
1261 {
1262 Status = co_MsqSendMessage( Window->head.pti->MessageQueue,
1263 hWnd,
1264 Msg,
1265 wParam,
1266 lParam,
1267 uTimeout,
1268 (uFlags & SMTO_BLOCK),
1269 MSQ_NORMAL,
1270 uResult );
1271 }
1272 while ((STATUS_TIMEOUT == Status) &&
1273 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1274 !MsqIsHung(Window->head.pti->MessageQueue)); // FIXME - Set window hung and add to a list.
1275
1276 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1277
1278 if (STATUS_TIMEOUT == Status)
1279 {
1280 /*
1281 MSDN says:
1282 Microsoft Windows 2000: If GetLastError returns zero, then the function
1283 timed out.
1284 XP+ : If the function fails or times out, the return value is zero.
1285 To get extended error information, call GetLastError. If GetLastError
1286 returns ERROR_TIMEOUT, then the function timed out.
1287 */
1288 EngSetLastError(ERROR_TIMEOUT);
1289 RETURN( FALSE);
1290 }
1291 else if (! NT_SUCCESS(Status))
1292 {
1293 SetLastNtError(Status);
1294 RETURN( FALSE);
1295 }
1296
1297 RETURN( TRUE);
1298
1299 CLEANUP:
1300 if (Window) UserDerefObjectCo(Window);
1301 END_CLEANUP;
1302 }
1303
1304 LRESULT FASTCALL
1305 co_IntSendMessageTimeout( HWND hWnd,
1306 UINT Msg,
1307 WPARAM wParam,
1308 LPARAM lParam,
1309 UINT uFlags,
1310 UINT uTimeout,
1311 ULONG_PTR *uResult )
1312 {
1313 PWND DesktopWindow;
1314 HWND *Children;
1315 HWND *Child;
1316
1317 if (HWND_BROADCAST != hWnd)
1318 {
1319 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1320 }
1321
1322 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1323 if (NULL == DesktopWindow)
1324 {
1325 EngSetLastError(ERROR_INTERNAL_ERROR);
1326 return 0;
1327 }
1328
1329 /* Send message to the desktop window too! */
1330 co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1331
1332 Children = IntWinListChildren(DesktopWindow);
1333 if (NULL == Children)
1334 {
1335 return 0;
1336 }
1337
1338 for (Child = Children; NULL != *Child; Child++)
1339 {
1340 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1341 }
1342
1343 ExFreePool(Children);
1344
1345 return (LRESULT) TRUE;
1346 }
1347
1348 LRESULT FASTCALL
1349 co_IntSendMessageNoWait(HWND hWnd,
1350 UINT Msg,
1351 WPARAM wParam,
1352 LPARAM lParam)
1353 {
1354 ULONG_PTR Result = 0;
1355 co_IntSendMessageWithCallBack(hWnd,
1356 Msg,
1357 wParam,
1358 lParam,
1359 NULL,
1360 0,
1361 &Result);
1362 return Result;
1363 }
1364 /* MSDN:
1365 If you send a message in the range below WM_USER to the asynchronous message
1366 functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its
1367 message parameters cannot include pointers. Otherwise, the operation will fail.
1368 The functions will return before the receiving thread has had a chance to
1369 process the message and the sender will free the memory before it is used.
1370 */
1371 LRESULT FASTCALL
1372 co_IntSendMessageWithCallBack( HWND hWnd,
1373 UINT Msg,
1374 WPARAM wParam,
1375 LPARAM lParam,
1376 SENDASYNCPROC CompletionCallback,
1377 ULONG_PTR CompletionCallbackContext,
1378 ULONG_PTR *uResult)
1379 {
1380 ULONG_PTR Result;
1381 PWND Window = NULL;
1382 PMSGMEMORY MsgMemoryEntry;
1383 INT lParamBufferSize;
1384 LPARAM lParamPacked;
1385 PTHREADINFO Win32Thread;
1386 DECLARE_RETURN(LRESULT);
1387 USER_REFERENCE_ENTRY Ref;
1388 PUSER_SENT_MESSAGE Message;
1389
1390 if (!(Window = UserGetWindowObject(hWnd)))
1391 {
1392 RETURN(FALSE);
1393 }
1394
1395 UserRefObjectCo(Window, &Ref);
1396
1397 if (Window->state & WNDS_DESTROYED)
1398 {
1399 /* FIXME - last error? */
1400 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1401 RETURN(FALSE);
1402 }
1403
1404 Win32Thread = PsGetCurrentThreadWin32Thread();
1405
1406 if (Win32Thread == NULL)
1407 {
1408 RETURN(FALSE);
1409 }
1410
1411 /* See if this message type is present in the table */
1412 MsgMemoryEntry = FindMsgMemory(Msg);
1413 if (NULL == MsgMemoryEntry)
1414 {
1415 lParamBufferSize = -1;
1416 }
1417 else
1418 {
1419 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1420 }
1421
1422 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, Window->head.pti->MessageQueue != Win32Thread->MessageQueue)))
1423 {
1424 DPRINT1("Failed to pack message parameters\n");
1425 RETURN( FALSE);
1426 }
1427
1428 /* If it can be sent now, then send it. */
1429 if (Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1430 {
1431 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1432 {
1433 UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE);
1434 /* Never send messages to exiting threads */
1435 RETURN(FALSE);
1436 }
1437
1438 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1439
1440 ObReferenceObject(Win32Thread->pEThread);
1441 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1442 !Window->Unicode,
1443 hWnd,
1444 Msg,
1445 wParam,
1446 lParamPacked,
1447 lParamBufferSize );
1448 if(uResult)
1449 {
1450 *uResult = Result;
1451 }
1452 ObDereferenceObject(Win32Thread->pEThread);
1453
1454 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1455
1456 if (CompletionCallback)
1457 {
1458 co_IntCallSentMessageCallback(CompletionCallback,
1459 hWnd,
1460 Msg,
1461 CompletionCallbackContext,
1462 Result);
1463 }
1464 }
1465
1466
1467
1468 if (Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1469 {
1470 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1471 {
1472 DPRINT1("Failed to unpack message parameters\n");
1473 }
1474 RETURN(TRUE);
1475 }
1476
1477 if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
1478 {
1479 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1480 RETURN( FALSE);
1481 }
1482
1483 IntReferenceMessageQueue(Window->head.pti->MessageQueue);
1484 /* Take reference on this MessageQueue if its a callback. It will be released
1485 when message is processed or removed from target hwnd MessageQueue */
1486 if (CompletionCallback)
1487 IntReferenceMessageQueue(Win32Thread->MessageQueue);
1488
1489 Message->Msg.hwnd = hWnd;
1490 Message->Msg.message = Msg;
1491 Message->Msg.wParam = wParam;
1492 Message->Msg.lParam = lParamPacked;
1493 Message->CompletionEvent = NULL;
1494 Message->Result = 0;
1495 Message->lResult = 0;
1496 Message->QS_Flags = 0;
1497 Message->SenderQueue = NULL; // mjmartin, you are right! This is null.
1498 Message->CallBackSenderQueue = Win32Thread->MessageQueue;
1499 Message->DispatchingListEntry.Flink = NULL;
1500 Message->CompletionCallback = CompletionCallback;
1501 Message->CompletionCallbackContext = CompletionCallbackContext;
1502 Message->HookMessage = MSQ_NORMAL;
1503 Message->HasPackedLParam = (lParamBufferSize > 0);
1504 Message->QS_Flags = QS_SENDMESSAGE;
1505
1506 InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
1507 MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, TRUE);
1508 IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
1509
1510 RETURN(TRUE);
1511
1512 CLEANUP:
1513 if (Window) UserDerefObjectCo(Window);
1514 END_CLEANUP;
1515 }
1516
1517 /* This function posts a message if the destination's message queue belongs to
1518 another thread, otherwise it sends the message. It does not support broadcast
1519 messages! */
1520 LRESULT FASTCALL
1521 co_IntPostOrSendMessage( HWND hWnd,
1522 UINT Msg,
1523 WPARAM wParam,
1524 LPARAM lParam )
1525 {
1526 ULONG_PTR Result;
1527 PTHREADINFO pti;
1528 PWND Window;
1529
1530 if ( hWnd == HWND_BROADCAST )
1531 {
1532 return 0;
1533 }
1534
1535 if(!(Window = UserGetWindowObject(hWnd)))
1536 {
1537 return 0;
1538 }
1539
1540 pti = PsGetCurrentThreadWin32Thread();
1541
1542 if ( Window->head.pti->MessageQueue != pti->MessageQueue &&
1543 FindMsgMemory(Msg) == 0 )
1544 {
1545 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1546 }
1547 else
1548 {
1549 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1550 {
1551 Result = 0;
1552 }
1553 }
1554
1555 return (LRESULT)Result;
1556 }
1557
1558 LRESULT FASTCALL
1559 co_IntDoSendMessage( HWND hWnd,
1560 UINT Msg,
1561 WPARAM wParam,
1562 LPARAM lParam,
1563 PDOSENDMESSAGE dsm)
1564 {
1565 PTHREADINFO pti;
1566 LRESULT Result = TRUE;
1567 NTSTATUS Status;
1568 PWND Window = NULL;
1569 MSG UserModeMsg;
1570 MSG KernelModeMsg;
1571 PMSGMEMORY MsgMemoryEntry;
1572
1573 if (HWND_BROADCAST != hWnd)
1574 {
1575 Window = UserGetWindowObject(hWnd);
1576 if ( !Window )
1577 {
1578 return 0;
1579 }
1580 }
1581
1582 /* Check for an exiting window. */
1583 if (Window && Window->state & WNDS_DESTROYED)
1584 {
1585 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1586 }
1587
1588 /* See if the current thread can handle the message */
1589 pti = PsGetCurrentThreadWin32Thread();
1590
1591 UserModeMsg.hwnd = hWnd;
1592 UserModeMsg.message = Msg;
1593 UserModeMsg.wParam = wParam;
1594 UserModeMsg.lParam = lParam;
1595 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1596
1597 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1598 if (! NT_SUCCESS(Status))
1599 {
1600 EngSetLastError(ERROR_INVALID_PARAMETER);
1601 return (dsm ? 0 : -1);
1602 }
1603
1604 if (!dsm)
1605 {
1606 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1607 KernelModeMsg.message,
1608 KernelModeMsg.wParam,
1609 KernelModeMsg.lParam );
1610 }
1611 else
1612 {
1613 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1614 KernelModeMsg.message,
1615 KernelModeMsg.wParam,
1616 KernelModeMsg.lParam,
1617 dsm->uFlags,
1618 dsm->uTimeout,
1619 &dsm->Result );
1620 }
1621
1622 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1623 if (! NT_SUCCESS(Status))
1624 {
1625 EngSetLastError(ERROR_INVALID_PARAMETER);
1626 return(dsm ? 0 : -1);
1627 }
1628
1629 return (LRESULT)Result;
1630 }
1631
1632 BOOL FASTCALL
1633 UserSendNotifyMessage( HWND hWnd,
1634 UINT Msg,
1635 WPARAM wParam,
1636 LPARAM lParam )
1637 {
1638 BOOL Ret = TRUE;
1639
1640 if (is_pointer_message(Msg))
1641 {
1642 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1643 return FALSE;
1644 }
1645
1646 // Basicly the same as IntPostOrSendMessage
1647 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1648 {
1649 HWND *List;
1650 PWND DesktopWindow;
1651 ULONG i;
1652
1653 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1654 List = IntWinListChildren(DesktopWindow);
1655
1656 if (List != NULL)
1657 {
1658 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1659 for (i = 0; List[i]; i++)
1660 {
1661 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1662 }
1663 ExFreePool(List);
1664 }
1665 }
1666 else
1667 {
1668 ULONG_PTR lResult = 0;
1669 Ret = co_IntSendMessageWithCallBack( hWnd,
1670 Msg,
1671 wParam,
1672 lParam,
1673 NULL,
1674 0,
1675 &lResult);
1676 }
1677 return Ret;
1678 }
1679
1680
1681 DWORD APIENTRY
1682 IntGetQueueStatus(DWORD Changes)
1683 {
1684 PTHREADINFO pti;
1685 PUSER_MESSAGE_QUEUE Queue;
1686 DWORD Result;
1687
1688 pti = PsGetCurrentThreadWin32Thread();
1689 Queue = pti->MessageQueue;
1690 // wine:
1691 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1692
1693 /* High word, types of messages currently in the queue.
1694 Low word, types of messages that have been added to the queue and that
1695 are still in the queue
1696 */
1697 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
1698
1699 pti->pcti->fsChangeBits &= ~Changes;
1700
1701 return Result;
1702 }
1703
1704 BOOL APIENTRY
1705 IntInitMessagePumpHook()
1706 {
1707 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1708
1709 if (pti->pcti)
1710 {
1711 pti->pcti->dwcPumpHook++;
1712 return TRUE;
1713 }
1714 return FALSE;
1715 }
1716
1717 BOOL APIENTRY
1718 IntUninitMessagePumpHook()
1719 {
1720 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1721
1722 if (pti->pcti)
1723 {
1724 if (pti->pcti->dwcPumpHook <= 0)
1725 {
1726 return FALSE;
1727 }
1728 pti->pcti->dwcPumpHook--;
1729 return TRUE;
1730 }
1731 return FALSE;
1732 }
1733
1734 /** Functions ******************************************************************/
1735
1736 BOOL
1737 APIENTRY
1738 NtUserDragDetect(
1739 HWND hWnd,
1740 POINT pt) // Just like the User call.
1741 {
1742 MSG msg;
1743 RECT rect;
1744 WORD wDragWidth, wDragHeight;
1745 DECLARE_RETURN(BOOL);
1746
1747 DPRINT("Enter NtUserDragDetect(%x)\n", hWnd);
1748 UserEnterExclusive();
1749
1750 wDragWidth = UserGetSystemMetrics(SM_CXDRAG);
1751 wDragHeight= UserGetSystemMetrics(SM_CYDRAG);
1752
1753 rect.left = pt.x - wDragWidth;
1754 rect.right = pt.x + wDragWidth;
1755
1756 rect.top = pt.y - wDragHeight;
1757 rect.bottom = pt.y + wDragHeight;
1758
1759 co_UserSetCapture(hWnd);
1760
1761 for (;;)
1762 {
1763 while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) ||
1764 co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC, WM_QUEUESYNC, PM_REMOVE, FALSE ) ||
1765 co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE, FALSE ) )
1766 {
1767 if ( msg.message == WM_LBUTTONUP )
1768 {
1769 co_UserSetCapture(NULL);
1770 RETURN( FALSE);
1771 }
1772 if ( msg.message == WM_MOUSEMOVE )
1773 {
1774 POINT tmp;
1775 tmp.x = (short)LOWORD(msg.lParam);
1776 tmp.y = (short)HIWORD(msg.lParam);
1777 if( !IntPtInRect( &rect, tmp ) )
1778 {
1779 co_UserSetCapture(NULL);
1780 RETURN( TRUE);
1781 }
1782 }
1783 if ( msg.message == WM_KEYDOWN )
1784 {
1785 if ( msg.wParam == VK_ESCAPE )
1786 {
1787 co_UserSetCapture(NULL);
1788 RETURN( TRUE);
1789 }
1790 }
1791 if ( msg.message == WM_QUEUESYNC )
1792 {
1793 co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 );
1794 }
1795 }
1796 co_IntWaitMessage(NULL, 0, 0);
1797 }
1798 RETURN( FALSE);
1799
1800 CLEANUP:
1801 DPRINT("Leave NtUserDragDetect, ret=%i\n",_ret_);
1802 UserLeave();
1803 END_CLEANUP;
1804 }
1805
1806 BOOL APIENTRY
1807 NtUserPostMessage(HWND hWnd,
1808 UINT Msg,
1809 WPARAM wParam,
1810 LPARAM lParam)
1811 {
1812 BOOL ret;
1813
1814 UserEnterExclusive();
1815
1816 ret = UserPostMessage(hWnd, Msg, wParam, lParam);
1817
1818 UserLeave();
1819
1820 return ret;
1821 }
1822
1823 BOOL APIENTRY
1824 NtUserPostThreadMessage(DWORD idThread,
1825 UINT Msg,
1826 WPARAM wParam,
1827 LPARAM lParam)
1828 {
1829 BOOL ret;
1830
1831 UserEnterExclusive();
1832
1833 ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
1834
1835 UserLeave();
1836
1837 return ret;
1838 }
1839
1840 BOOL APIENTRY
1841 NtUserWaitMessage(VOID)
1842 {
1843 BOOL ret;
1844
1845 UserEnterExclusive();
1846 DPRINT("NtUserWaitMessage Enter\n");
1847 ret = co_IntWaitMessage(NULL, 0, 0);
1848 DPRINT("NtUserWaitMessage Leave\n");
1849 UserLeave();
1850
1851 return ret;
1852 }
1853
1854 BOOL APIENTRY
1855 NtUserGetMessage(PMSG pMsg,
1856 HWND hWnd,
1857 UINT MsgFilterMin,
1858 UINT MsgFilterMax )
1859 {
1860 MSG Msg;
1861 BOOL Ret;
1862
1863 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
1864 {
1865 EngSetLastError(ERROR_INVALID_PARAMETER);
1866 return FALSE;
1867 }
1868
1869 UserEnterExclusive();
1870
1871 RtlZeroMemory(&Msg, sizeof(MSG));
1872
1873 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
1874
1875 UserLeave();
1876
1877 if (Ret == TRUE)
1878 {
1879 _SEH2_TRY
1880 {
1881 ProbeForWrite(pMsg, sizeof(MSG), 1);
1882 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1883 }
1884 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1885 {
1886 SetLastNtError(_SEH2_GetExceptionCode());
1887 Ret = FALSE;
1888 }
1889 _SEH2_END;
1890 }
1891
1892 if ((INT)Ret != -1)
1893 Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE;
1894
1895 return Ret;
1896 }
1897
1898 BOOL APIENTRY
1899 NtUserPeekMessage( PMSG pMsg,
1900 HWND hWnd,
1901 UINT MsgFilterMin,
1902 UINT MsgFilterMax,
1903 UINT RemoveMsg)
1904 {
1905 MSG Msg;
1906 BOOL Ret;
1907
1908 if ( RemoveMsg & PM_BADMSGFLAGS )
1909 {
1910 EngSetLastError(ERROR_INVALID_FLAGS);
1911 return FALSE;
1912 }
1913
1914 UserEnterExclusive();
1915
1916 RtlZeroMemory(&Msg, sizeof(MSG));
1917
1918 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
1919
1920 UserLeave();
1921
1922 if (Ret)
1923 {
1924 _SEH2_TRY
1925 {
1926 ProbeForWrite(pMsg, sizeof(MSG), 1);
1927 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1928 }
1929 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1930 {
1931 SetLastNtError(_SEH2_GetExceptionCode());
1932 Ret = FALSE;
1933 }
1934 _SEH2_END;
1935 }
1936
1937 return Ret;
1938 }
1939
1940 BOOL APIENTRY
1941 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
1942 {
1943 BOOL Ret = FALSE;
1944 MSG Msg;
1945
1946 _SEH2_TRY
1947 {
1948 ProbeForRead(lpmsg, sizeof(MSG), 1);
1949 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
1950 }
1951 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1952 {
1953 _SEH2_YIELD(return FALSE);
1954 }
1955 _SEH2_END;
1956
1957 UserEnterExclusive();
1958
1959 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
1960 {
1961 Ret = TRUE;
1962 }
1963 else
1964 {
1965 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
1966 }
1967
1968 UserLeave();
1969
1970 _SEH2_TRY
1971 {
1972 ProbeForWrite(lpmsg, sizeof(MSG), 1);
1973 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
1974 }
1975 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1976 {
1977 Ret = FALSE;
1978 }
1979 _SEH2_END;
1980
1981 return Ret;
1982 }
1983
1984 LRESULT APIENTRY
1985 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
1986 {
1987 LRESULT Res = 0;
1988 MSG SafeMsg;
1989
1990 _SEH2_TRY
1991 {
1992 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
1993 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
1994 }
1995 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1996 {
1997 SetLastNtError(_SEH2_GetExceptionCode());
1998 _SEH2_YIELD(return FALSE);
1999 }
2000 _SEH2_END;
2001
2002 UserEnterExclusive();
2003
2004 Res = IntDispatchMessage(&SafeMsg);
2005
2006 UserLeave();
2007 return Res;
2008 }
2009
2010
2011 BOOL APIENTRY
2012 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
2013 {
2014 MSG SafeMsg;
2015 BOOL Ret;
2016
2017 _SEH2_TRY
2018 {
2019 ProbeForRead(lpMsg, sizeof(MSG), 1);
2020 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
2021 }
2022 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2023 {
2024 SetLastNtError(_SEH2_GetExceptionCode());
2025 _SEH2_YIELD(return FALSE);
2026 }
2027 _SEH2_END;
2028
2029 UserEnterExclusive();
2030
2031 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
2032
2033 UserLeave();
2034
2035 return Ret;
2036 }
2037
2038 BOOL APIENTRY
2039 NtUserMessageCall( HWND hWnd,
2040 UINT Msg,
2041 WPARAM wParam,
2042 LPARAM lParam,
2043 ULONG_PTR ResultInfo,
2044 DWORD dwType, // fnID?
2045 BOOL Ansi)
2046 {
2047 LRESULT lResult = 0;
2048 BOOL Ret = FALSE;
2049 PWND Window = NULL;
2050 USER_REFERENCE_ENTRY Ref;
2051
2052 UserEnterExclusive();
2053
2054 switch(dwType)
2055 {
2056 case FNID_DEFWINDOWPROC:
2057 /* Validate input */
2058 if (hWnd && (hWnd != INVALID_HANDLE_VALUE))
2059 {
2060 Window = UserGetWindowObject(hWnd);
2061 if (!Window)
2062 {
2063 UserLeave();
2064 return FALSE;
2065 }
2066 }
2067 UserRefObjectCo(Window, &Ref);
2068 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2069 Ret = TRUE;
2070 UserDerefObjectCo(Window);
2071 break;
2072 case FNID_SENDNOTIFYMESSAGE:
2073 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2074 break;
2075 case FNID_BROADCASTSYSTEMMESSAGE:
2076 {
2077 BROADCASTPARM parm;
2078 DWORD_PTR RetVal = 0;
2079
2080 if (ResultInfo)
2081 {
2082 _SEH2_TRY
2083 {
2084 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
2085 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2086 }
2087 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2088 {
2089 _SEH2_YIELD(break);
2090 }
2091 _SEH2_END;
2092 }
2093 else
2094 break;
2095
2096 if ( parm.recipients & BSM_ALLDESKTOPS ||
2097 parm.recipients == BSM_ALLCOMPONENTS )
2098 {
2099 }
2100 else if (parm.recipients & BSM_APPLICATIONS)
2101 {
2102 if (parm.flags & BSF_QUERY)
2103 {
2104 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2105 {
2106 co_IntSendMessageTimeout( HWND_BROADCAST,
2107 Msg,
2108 wParam,
2109 lParam,
2110 SMTO_ABORTIFHUNG,
2111 2000,
2112 &RetVal);
2113 }
2114 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2115 {
2116 co_IntSendMessageTimeout( HWND_BROADCAST,
2117 Msg,
2118 wParam,
2119 lParam,
2120 SMTO_NOTIMEOUTIFNOTHUNG,
2121 2000,
2122 &RetVal);
2123 }
2124 else
2125 {
2126 co_IntSendMessageTimeout( HWND_BROADCAST,
2127 Msg,
2128 wParam,
2129 lParam,
2130 SMTO_NORMAL,
2131 2000,
2132 &RetVal);
2133 }
2134 Ret = RetVal;
2135 }
2136 else if (parm.flags & BSF_POSTMESSAGE)
2137 {
2138 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2139 }
2140 else //Everything else,,,, if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2141 {
2142 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2143 }
2144 }
2145 }
2146 break;
2147 case FNID_SENDMESSAGECALLBACK:
2148 {
2149 CALL_BACK_INFO CallBackInfo;
2150 ULONG_PTR uResult;
2151
2152 _SEH2_TRY
2153 {
2154 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
2155 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
2156 }
2157 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2158 {
2159 _SEH2_YIELD(break);
2160 }
2161 _SEH2_END;
2162
2163 if (is_pointer_message(Msg))
2164 {
2165 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
2166 break;
2167 }
2168
2169 if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2170 CallBackInfo.CallBack, CallBackInfo.Context, &uResult)))
2171 {
2172 DPRINT1("Callback failure!\n");
2173 }
2174 }
2175 break;
2176 case FNID_SENDMESSAGE:
2177 {
2178 Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
2179
2180 if (ResultInfo)
2181 {
2182 _SEH2_TRY
2183 {
2184 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
2185 RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
2186 }
2187 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2188 {
2189 Ret = FALSE;
2190 _SEH2_YIELD(break);
2191 }
2192 _SEH2_END;
2193 }
2194 break;
2195 }
2196 case FNID_SENDMESSAGETIMEOUT:
2197 {
2198 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
2199 if (ResultInfo)
2200 {
2201 _SEH2_TRY
2202 {
2203 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
2204 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
2205 }
2206 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2207 {
2208 _SEH2_YIELD(break);
2209 }
2210 _SEH2_END;
2211 }
2212
2213 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
2214
2215 if (pdsm)
2216 {
2217 _SEH2_TRY
2218 {
2219 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
2220 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2221 }
2222 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2223 {
2224 Ret = FALSE;
2225 _SEH2_YIELD(break);
2226 }
2227 _SEH2_END;
2228 }
2229 break;
2230 }
2231 // CallNextHook bypass.
2232 case FNID_CALLWNDPROC:
2233 case FNID_CALLWNDPROCRET:
2234 {
2235 PTHREADINFO pti;
2236 PCLIENTINFO ClientInfo;
2237 PHOOK NextObj, Hook;
2238
2239 pti = GetW32ThreadInfo();
2240
2241 Hook = pti->sphkCurrent;
2242
2243 if (!Hook) break;
2244
2245 NextObj = Hook->phkNext;
2246 ClientInfo = pti->pClientInfo;
2247 _SEH2_TRY
2248 {
2249 ClientInfo->phkCurrent = NextObj;
2250 }
2251 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2252 {
2253 ClientInfo = NULL;
2254 }
2255 _SEH2_END;
2256
2257 if (!ClientInfo || !NextObj) break;
2258
2259 NextObj->phkNext = IntGetNextHook(NextObj);
2260
2261 if ( Hook->HookId == WH_CALLWNDPROC)
2262 {
2263 CWPSTRUCT CWP;
2264 CWP.hwnd = hWnd;
2265 CWP.message = Msg;
2266 CWP.wParam = wParam;
2267 CWP.lParam = lParam;
2268 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2269
2270 lResult = co_IntCallHookProc( Hook->HookId,
2271 HC_ACTION,
2272 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2273 (LPARAM)&CWP,
2274 Hook->Proc,
2275 Hook->Ansi,
2276 &Hook->ModuleName);
2277 }
2278 else
2279 {
2280 CWPRETSTRUCT CWPR;
2281 CWPR.hwnd = hWnd;
2282 CWPR.message = Msg;
2283 CWPR.wParam = wParam;
2284 CWPR.lParam = lParam;
2285 CWPR.lResult = ClientInfo->dwHookData;
2286
2287 lResult = co_IntCallHookProc( Hook->HookId,
2288 HC_ACTION,
2289 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2290 (LPARAM)&CWPR,
2291 Hook->Proc,
2292 Hook->Ansi,
2293 &Hook->ModuleName);
2294 }
2295 }
2296 break;
2297 }
2298
2299 switch(dwType)
2300 {
2301 case FNID_DEFWINDOWPROC:
2302 case FNID_CALLWNDPROC:
2303 case FNID_CALLWNDPROCRET:
2304 if (ResultInfo)
2305 {
2306 _SEH2_TRY
2307 {
2308 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2309 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2310 }
2311 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2312 {
2313 Ret = FALSE;
2314 }
2315 _SEH2_END;
2316 }
2317 break;
2318 default:
2319 break;
2320 }
2321
2322 UserLeave();
2323
2324 return Ret;
2325 }
2326
2327 #define INFINITE 0xFFFFFFFF
2328 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2329
2330 DWORD
2331 APIENTRY
2332 NtUserWaitForInputIdle( IN HANDLE hProcess,
2333 IN DWORD dwMilliseconds,
2334 IN BOOL Unknown2)
2335 {
2336 PEPROCESS Process;
2337 PPROCESSINFO W32Process;
2338 PTHREADINFO pti;
2339 NTSTATUS Status;
2340 HANDLE Handles[3];
2341 LARGE_INTEGER Timeout;
2342
2343 UserEnterExclusive();
2344
2345 Status = ObReferenceObjectByHandle(hProcess,
2346 PROCESS_QUERY_INFORMATION,
2347 PsProcessType,
2348 UserMode,
2349 (PVOID*)&Process,
2350 NULL);
2351
2352 if (!NT_SUCCESS(Status))
2353 {
2354 UserLeave();
2355 SetLastNtError(Status);
2356 return WAIT_FAILED;
2357 }
2358
2359 pti = PsGetCurrentThreadWin32Thread();
2360
2361 W32Process = (PPROCESSINFO)Process->Win32Process;
2362
2363 if ( PsGetProcessExitProcessCalled(Process) ||
2364 !W32Process ||
2365 pti->ppi == W32Process)
2366 {
2367 ObDereferenceObject(Process);
2368 UserLeave();
2369 EngSetLastError(ERROR_INVALID_PARAMETER);
2370 return WAIT_FAILED;
2371 }
2372
2373 Handles[0] = Process;
2374 Handles[1] = W32Process->InputIdleEvent;
2375 Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2376
2377 if (!Handles[1])
2378 {
2379 ObDereferenceObject(Process);
2380 UserLeave();
2381 return STATUS_SUCCESS; /* no event to wait on */
2382 }
2383
2384 if (dwMilliseconds != INFINITE)
2385 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2386
2387 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2388 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2389 {
2390 pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2391 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2392 }
2393
2394 DPRINT("WFII: ppi 0x%x\n",W32Process);
2395 DPRINT("WFII: waiting for %p\n", Handles[1] );
2396 do
2397 {
2398 UserLeave();
2399 Status = KeWaitForMultipleObjects( 3,
2400 Handles,
2401 WaitAny,
2402 UserRequest,
2403 UserMode,
2404 FALSE,
2405 dwMilliseconds == INFINITE ? NULL : &Timeout,
2406 NULL);
2407 UserEnterExclusive();
2408
2409 if (!NT_SUCCESS(Status))
2410 {
2411 SetLastNtError(Status);
2412 Status = WAIT_FAILED;
2413 goto WaitExit;
2414 }
2415
2416 switch (Status)
2417 {
2418 case STATUS_WAIT_0:
2419 goto WaitExit;
2420
2421 case STATUS_WAIT_2:
2422 {
2423 MSG Msg;
2424 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
2425 DPRINT1("WFII: WAIT 2\n");
2426 }
2427 break;
2428
2429 case STATUS_TIMEOUT:
2430 DPRINT1("WFII: timeout\n");
2431 case WAIT_FAILED:
2432 goto WaitExit;
2433
2434 default:
2435 DPRINT1("WFII: finished\n");
2436 Status = STATUS_SUCCESS;
2437 goto WaitExit;
2438 }
2439 }
2440 while (TRUE);
2441
2442 WaitExit:
2443 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2444 {
2445 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
2446 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2447 }
2448 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
2449 ObDereferenceObject(Process);
2450 UserLeave();
2451 return Status;
2452 }
2453
2454 /* EOF */