fbe7a93d0331d954d8ab2bb388cbf4d64b24b8e6
[reactos.git] / reactos / 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 GreDeleteObject(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 (ProcessMask & QS_HOTKEY) ) &&
740 MsqPeekMessage( ThreadQueue,
741 RemoveMessages,
742 Window,
743 MsgFilterMin,
744 MsgFilterMax,
745 ProcessMask,
746 Msg ))
747 {
748 return TRUE;
749 }
750
751 /* Now look for a quit message. */
752 if (ThreadQueue->QuitPosted)
753 {
754 /* According to the PSDK, WM_QUIT messages are always returned, regardless
755 of the filter specified */
756 Msg->hwnd = NULL;
757 Msg->message = WM_QUIT;
758 Msg->wParam = ThreadQueue->QuitExitCode;
759 Msg->lParam = 0;
760 if (RemoveMessages)
761 {
762 ThreadQueue->QuitPosted = FALSE;
763 ClearMsgBitsMask(ThreadQueue, QS_POSTMESSAGE);
764 pti->pcti->fsWakeBits &= ~QS_ALLPOSTMESSAGE;
765 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
766 }
767 return TRUE;
768 }
769
770 /* Check for hardware events. */
771 if ((ProcessMask & QS_MOUSE) &&
772 co_MsqPeekMouseMove( ThreadQueue,
773 RemoveMessages,
774 Window,
775 MsgFilterMin,
776 MsgFilterMax,
777 Msg ))
778 {
779 return TRUE;
780 }
781
782 if ((ProcessMask & QS_INPUT) &&
783 co_MsqPeekHardwareMessage( ThreadQueue,
784 RemoveMessages,
785 Window,
786 MsgFilterMin,
787 MsgFilterMax,
788 ProcessMask,
789 Msg))
790 {
791 return TRUE;
792 }
793
794 /* Check for sent messages again. */
795 while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
796 {
797 if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE;
798 }
799 if (Hit) return FALSE;
800
801 /* Check for paint messages. */
802 if ((ProcessMask & QS_PAINT) &&
803 pti->cPaintsReady &&
804 IntGetPaintMessage( Window,
805 MsgFilterMin,
806 MsgFilterMax,
807 pti,
808 Msg,
809 RemoveMessages))
810 {
811 return TRUE;
812 }
813
814 /* This is correct, check for the current threads timers waiting to be
815 posted to this threads message queue. If any we loop again.
816 */
817 if ((ProcessMask & QS_TIMER) &&
818 PostTimerMessages(Window))
819 {
820 continue;
821 }
822
823 return FALSE;
824 }
825 while (TRUE);
826
827 return TRUE;
828 }
829
830 static BOOL FASTCALL
831 co_IntWaitMessage( PWND Window,
832 UINT MsgFilterMin,
833 UINT MsgFilterMax )
834 {
835 PTHREADINFO pti;
836 PUSER_MESSAGE_QUEUE ThreadQueue;
837 NTSTATUS Status = STATUS_SUCCESS;
838 MSG Msg;
839
840 pti = PsGetCurrentThreadWin32Thread();
841 ThreadQueue = pti->MessageQueue;
842
843 do
844 {
845 if ( co_IntPeekMessage( &Msg, // Dont reenter!
846 Window,
847 MsgFilterMin,
848 MsgFilterMax,
849 MAKELONG( PM_NOREMOVE, GetWakeMask( MsgFilterMin, MsgFilterMax)),
850 TRUE ) ) // act like GetMessage.
851 {
852 return TRUE;
853 }
854
855 /* Nothing found. Wait for new messages. */
856 Status = co_MsqWaitForNewMessages( ThreadQueue,
857 Window,
858 MsgFilterMin,
859 MsgFilterMax);
860 if (!NT_SUCCESS(Status))
861 {
862 SetLastNtError(Status);
863 DPRINT1("Exit co_IntWaitMessage on error!\n");
864 return FALSE;
865 }
866 if (Status == STATUS_USER_APC || Status == STATUS_TIMEOUT)
867 {
868 return FALSE;
869 }
870 }
871 while ( TRUE );
872
873 return FALSE;
874 }
875
876 BOOL FASTCALL
877 co_IntGetPeekMessage( PMSG pMsg,
878 HWND hWnd,
879 UINT MsgFilterMin,
880 UINT MsgFilterMax,
881 UINT RemoveMsg,
882 BOOL bGMSG )
883 {
884 PWND Window;
885 PTHREADINFO pti;
886 BOOL Present = FALSE;
887 NTSTATUS Status;
888
889 if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST )
890 hWnd = HWND_BOTTOM;
891
892 /* Validate input */
893 if (hWnd && hWnd != HWND_BOTTOM)
894 {
895 if (!(Window = UserGetWindowObject(hWnd)))
896 {
897 if (bGMSG)
898 return -1;
899 else
900 return FALSE;
901 }
902 }
903 else
904 {
905 Window = (PWND)hWnd;
906 }
907
908 if (MsgFilterMax < MsgFilterMin)
909 {
910 MsgFilterMin = 0;
911 MsgFilterMax = 0;
912 }
913
914 if (bGMSG)
915 {
916 RemoveMsg |= ((GetWakeMask( MsgFilterMin, MsgFilterMax ))<< 16);
917 }
918
919 pti = PsGetCurrentThreadWin32Thread();
920 pti->pClientInfo->cSpins++; // Bump up the spin count.
921
922 do
923 {
924 Present = co_IntPeekMessage( pMsg,
925 Window,
926 MsgFilterMin,
927 MsgFilterMax,
928 RemoveMsg,
929 bGMSG );
930 if (Present)
931 {
932 /* GetMessage or PostMessage must never get messages that contain pointers */
933 ASSERT(FindMsgMemory(pMsg->message) == NULL);
934
935 if (pMsg->message != WM_PAINT && pMsg->message != WM_QUIT)
936 {
937 pti->timeLast = pMsg->time;
938 pti->ptLast = pMsg->pt;
939 }
940
941 // The WH_GETMESSAGE hook enables an application to monitor messages about to
942 // be returned by the GetMessage or PeekMessage function.
943
944 co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg);
945
946 if ( bGMSG ) break;
947 }
948
949 if ( bGMSG )
950 {
951 Status = co_MsqWaitForNewMessages( pti->MessageQueue,
952 Window,
953 MsgFilterMin,
954 MsgFilterMax);
955 if ( !NT_SUCCESS(Status) ||
956 Status == STATUS_USER_APC ||
957 Status == STATUS_TIMEOUT )
958 {
959 Present = -1;
960 break;
961 }
962 }
963 else
964 {
965 if (!(RemoveMsg & PM_NOYIELD))
966 {
967 IdlePing();
968 // Yield this thread!
969 UserLeave();
970 ZwYieldExecution();
971 UserEnterExclusive();
972 // Fall through to exit.
973 IdlePong();
974 }
975 break;
976 }
977 }
978 while( bGMSG && !Present );
979
980 // Been spinning, time to swap vinyl...
981 if (pti->pClientInfo->cSpins >= 100)
982 {
983 // Clear the spin cycle to fix the mix.
984 pti->pClientInfo->cSpins = 0;
985 //if (!(pti->TIF_flags & TIF_SPINNING)) FIXME need to swap vinyl..
986 }
987 return Present;
988 }
989
990 BOOL FASTCALL
991 UserPostThreadMessage( DWORD idThread,
992 UINT Msg,
993 WPARAM wParam,
994 LPARAM lParam )
995 {
996 MSG Message;
997 PETHREAD peThread;
998 PTHREADINFO pThread;
999 LARGE_INTEGER LargeTickCount;
1000 NTSTATUS Status;
1001
1002 if (is_pointer_message(Msg))
1003 {
1004 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1005 return FALSE;
1006 }
1007
1008 Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
1009
1010 if( Status == STATUS_SUCCESS )
1011 {
1012 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
1013 if( !pThread ||
1014 !pThread->MessageQueue ||
1015 (pThread->TIF_flags & TIF_INCLEANUP))
1016 {
1017 ObDereferenceObject( peThread );
1018 return FALSE;
1019 }
1020
1021 Message.hwnd = NULL;
1022 Message.message = Msg;
1023 Message.wParam = wParam;
1024 Message.lParam = lParam;
1025 Message.pt = gpsi->ptCursor;
1026
1027 KeQueryTickCount(&LargeTickCount);
1028 Message.time = MsqCalculateMessageTime(&LargeTickCount);
1029 MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1030 ObDereferenceObject( peThread );
1031 return TRUE;
1032 }
1033 else
1034 {
1035 SetLastNtError( Status );
1036 }
1037 return FALSE;
1038 }
1039
1040 BOOL FASTCALL
1041 UserPostMessage( HWND Wnd,
1042 UINT Msg,
1043 WPARAM wParam,
1044 LPARAM lParam )
1045 {
1046 PTHREADINFO pti;
1047 MSG Message, KernelModeMsg;
1048 LARGE_INTEGER LargeTickCount;
1049
1050 Message.hwnd = Wnd;
1051 Message.message = Msg;
1052 Message.wParam = wParam;
1053 Message.lParam = lParam;
1054 Message.pt = gpsi->ptCursor;
1055 KeQueryTickCount(&LargeTickCount);
1056 Message.time = MsqCalculateMessageTime(&LargeTickCount);
1057
1058 if (is_pointer_message(Message.message))
1059 {
1060 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1061 return FALSE;
1062 }
1063
1064 if( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST )
1065 {
1066 NTSTATUS Status;
1067 PMSGMEMORY MsgMemoryEntry;
1068
1069 MsgMemoryEntry = FindMsgMemory(Message.message);
1070
1071 Status = CopyMsgToKernelMem(&KernelModeMsg, &Message, MsgMemoryEntry);
1072 if (! NT_SUCCESS(Status))
1073 {
1074 EngSetLastError(ERROR_INVALID_PARAMETER);
1075 return FALSE;
1076 }
1077 co_IntSendMessageNoWait(KernelModeMsg.hwnd,
1078 KernelModeMsg.message,
1079 KernelModeMsg.wParam,
1080 KernelModeMsg.lParam);
1081
1082 if (MsgMemoryEntry && KernelModeMsg.lParam)
1083 ExFreePool((PVOID) KernelModeMsg.lParam);
1084
1085 return TRUE;
1086 }
1087
1088 if (!Wnd)
1089 {
1090 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1091 Msg,
1092 wParam,
1093 lParam);
1094 }
1095 if (Wnd == HWND_BROADCAST)
1096 {
1097 HWND *List;
1098 PWND DesktopWindow;
1099 ULONG i;
1100
1101 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1102 List = IntWinListChildren(DesktopWindow);
1103
1104 if (List != NULL)
1105 {
1106 UserPostMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1107 for (i = 0; List[i]; i++)
1108 {
1109 UserPostMessage(List[i], Msg, wParam, lParam);
1110 }
1111 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1112 }
1113 }
1114 else
1115 {
1116 PWND Window;
1117
1118 Window = UserGetWindowObject(Wnd);
1119 if ( !Window )
1120 {
1121 return FALSE;
1122 }
1123
1124 pti = Window->head.pti;
1125 if ( pti->TIF_flags & TIF_INCLEANUP )
1126 {
1127 DPRINT1("Attempted to post message to window 0x%x when the thread is in cleanup!\n", Wnd);
1128 return FALSE;
1129 }
1130
1131 if ( Window->state & WNDS_DESTROYED )
1132 {
1133 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1134 /* FIXME - last error code? */
1135 return FALSE;
1136 }
1137
1138 if (WM_QUIT == Msg)
1139 {
1140 MsqPostQuitMessage(Window->head.pti->MessageQueue, wParam);
1141 }
1142 else
1143 {
1144 MsqPostMessage(Window->head.pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1145 }
1146 }
1147 return TRUE;
1148 }
1149
1150
1151 LRESULT FASTCALL
1152 co_IntSendMessage( HWND hWnd,
1153 UINT Msg,
1154 WPARAM wParam,
1155 LPARAM lParam )
1156 {
1157 ULONG_PTR Result = 0;
1158 if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1159 {
1160 return (LRESULT)Result;
1161 }
1162 return 0;
1163 }
1164
1165 static LRESULT FASTCALL
1166 co_IntSendMessageTimeoutSingle( HWND hWnd,
1167 UINT Msg,
1168 WPARAM wParam,
1169 LPARAM lParam,
1170 UINT uFlags,
1171 UINT uTimeout,
1172 ULONG_PTR *uResult )
1173 {
1174 NTSTATUS Status;
1175 PWND Window = NULL;
1176 PMSGMEMORY MsgMemoryEntry;
1177 INT lParamBufferSize;
1178 LPARAM lParamPacked;
1179 PTHREADINFO Win32Thread;
1180 ULONG_PTR Result = 0;
1181 DECLARE_RETURN(LRESULT);
1182 USER_REFERENCE_ENTRY Ref;
1183
1184 if (!(Window = UserGetWindowObject(hWnd)))
1185 {
1186 RETURN( FALSE);
1187 }
1188
1189 UserRefObjectCo(Window, &Ref);
1190
1191 Win32Thread = PsGetCurrentThreadWin32Thread();
1192
1193 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1194
1195 if ( NULL != Win32Thread &&
1196 Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1197 {
1198 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1199 {
1200 /* Never send messages to exiting threads */
1201 RETURN( FALSE);
1202 }
1203
1204 /* See if this message type is present in the table */
1205 MsgMemoryEntry = FindMsgMemory(Msg);
1206 if (NULL == MsgMemoryEntry)
1207 {
1208 lParamBufferSize = -1;
1209 }
1210 else
1211 {
1212 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1213 }
1214
1215 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
1216 {
1217 DPRINT1("Failed to pack message parameters\n");
1218 RETURN( FALSE);
1219 }
1220
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 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1234
1235 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1236 {
1237 DPRINT1("Failed to unpack message parameters\n");
1238 RETURN( TRUE);
1239 }
1240
1241 RETURN( TRUE);
1242 }
1243
1244 if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->head.pti->MessageQueue))
1245 {
1246 // FIXME - Set window hung and add to a list.
1247 /* FIXME - Set a LastError? */
1248 RETURN( FALSE);
1249 }
1250
1251 if (Window->state & WNDS_DESTROYED)
1252 {
1253 /* FIXME - last error? */
1254 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1255 RETURN( FALSE);
1256 }
1257
1258 do
1259 {
1260 Status = co_MsqSendMessage( Window->head.pti->MessageQueue,
1261 hWnd,
1262 Msg,
1263 wParam,
1264 lParam,
1265 uTimeout,
1266 (uFlags & SMTO_BLOCK),
1267 MSQ_NORMAL,
1268 uResult );
1269 }
1270 while ((STATUS_TIMEOUT == Status) &&
1271 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1272 !MsqIsHung(Window->head.pti->MessageQueue)); // FIXME - Set window hung and add to a list.
1273
1274 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1275
1276 if (STATUS_TIMEOUT == Status)
1277 {
1278 /*
1279 MSDN says:
1280 Microsoft Windows 2000: If GetLastError returns zero, then the function
1281 timed out.
1282 XP+ : If the function fails or times out, the return value is zero.
1283 To get extended error information, call GetLastError. If GetLastError
1284 returns ERROR_TIMEOUT, then the function timed out.
1285 */
1286 EngSetLastError(ERROR_TIMEOUT);
1287 RETURN( FALSE);
1288 }
1289 else if (! NT_SUCCESS(Status))
1290 {
1291 SetLastNtError(Status);
1292 RETURN( FALSE);
1293 }
1294
1295 RETURN( TRUE);
1296
1297 CLEANUP:
1298 if (Window) UserDerefObjectCo(Window);
1299 END_CLEANUP;
1300 }
1301
1302 LRESULT FASTCALL
1303 co_IntSendMessageTimeout( HWND hWnd,
1304 UINT Msg,
1305 WPARAM wParam,
1306 LPARAM lParam,
1307 UINT uFlags,
1308 UINT uTimeout,
1309 ULONG_PTR *uResult )
1310 {
1311 PWND DesktopWindow;
1312 HWND *Children;
1313 HWND *Child;
1314
1315 if (HWND_BROADCAST != hWnd)
1316 {
1317 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1318 }
1319
1320 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1321 if (NULL == DesktopWindow)
1322 {
1323 EngSetLastError(ERROR_INTERNAL_ERROR);
1324 return 0;
1325 }
1326
1327 /* Send message to the desktop window too! */
1328 co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1329
1330 Children = IntWinListChildren(DesktopWindow);
1331 if (NULL == Children)
1332 {
1333 return 0;
1334 }
1335
1336 for (Child = Children; NULL != *Child; Child++)
1337 {
1338 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1339 }
1340
1341 ExFreePool(Children);
1342
1343 return (LRESULT) TRUE;
1344 }
1345
1346 LRESULT FASTCALL
1347 co_IntSendMessageNoWait(HWND hWnd,
1348 UINT Msg,
1349 WPARAM wParam,
1350 LPARAM lParam)
1351 {
1352 ULONG_PTR Result = 0;
1353 co_IntSendMessageWithCallBack(hWnd,
1354 Msg,
1355 wParam,
1356 lParam,
1357 NULL,
1358 0,
1359 &Result);
1360 return Result;
1361 }
1362 /* MSDN:
1363 If you send a message in the range below WM_USER to the asynchronous message
1364 functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its
1365 message parameters cannot include pointers. Otherwise, the operation will fail.
1366 The functions will return before the receiving thread has had a chance to
1367 process the message and the sender will free the memory before it is used.
1368 */
1369 LRESULT FASTCALL
1370 co_IntSendMessageWithCallBack( HWND hWnd,
1371 UINT Msg,
1372 WPARAM wParam,
1373 LPARAM lParam,
1374 SENDASYNCPROC CompletionCallback,
1375 ULONG_PTR CompletionCallbackContext,
1376 ULONG_PTR *uResult)
1377 {
1378 ULONG_PTR Result;
1379 PWND Window = NULL;
1380 PMSGMEMORY MsgMemoryEntry;
1381 INT lParamBufferSize;
1382 LPARAM lParamPacked;
1383 PTHREADINFO Win32Thread;
1384 DECLARE_RETURN(LRESULT);
1385 USER_REFERENCE_ENTRY Ref;
1386 PUSER_SENT_MESSAGE Message;
1387
1388 if (!(Window = UserGetWindowObject(hWnd)))
1389 {
1390 RETURN(FALSE);
1391 }
1392
1393 UserRefObjectCo(Window, &Ref);
1394
1395 if (Window->state & WNDS_DESTROYED)
1396 {
1397 /* FIXME - last error? */
1398 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1399 RETURN(FALSE);
1400 }
1401
1402 Win32Thread = PsGetCurrentThreadWin32Thread();
1403
1404 if (Win32Thread == NULL)
1405 {
1406 RETURN(FALSE);
1407 }
1408
1409 /* See if this message type is present in the table */
1410 MsgMemoryEntry = FindMsgMemory(Msg);
1411 if (NULL == MsgMemoryEntry)
1412 {
1413 lParamBufferSize = -1;
1414 }
1415 else
1416 {
1417 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1418 }
1419
1420 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, Window->head.pti->MessageQueue != Win32Thread->MessageQueue)))
1421 {
1422 DPRINT1("Failed to pack message parameters\n");
1423 RETURN( FALSE);
1424 }
1425
1426 /* If it can be sent now, then send it. */
1427 if (Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1428 {
1429 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1430 {
1431 UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE);
1432 /* Never send messages to exiting threads */
1433 RETURN(FALSE);
1434 }
1435
1436 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1437
1438 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1439 !Window->Unicode,
1440 hWnd,
1441 Msg,
1442 wParam,
1443 lParamPacked,
1444 lParamBufferSize );
1445 if(uResult)
1446 {
1447 *uResult = Result;
1448 }
1449
1450 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1451
1452 if (CompletionCallback)
1453 {
1454 co_IntCallSentMessageCallback(CompletionCallback,
1455 hWnd,
1456 Msg,
1457 CompletionCallbackContext,
1458 Result);
1459 }
1460 }
1461
1462
1463
1464 if (Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1465 {
1466 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1467 {
1468 DPRINT1("Failed to unpack message parameters\n");
1469 }
1470 RETURN(TRUE);
1471 }
1472
1473 if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
1474 {
1475 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1476 RETURN( FALSE);
1477 }
1478
1479 IntReferenceMessageQueue(Window->head.pti->MessageQueue);
1480 /* Take reference on this MessageQueue if its a callback. It will be released
1481 when message is processed or removed from target hwnd MessageQueue */
1482 if (CompletionCallback)
1483 IntReferenceMessageQueue(Win32Thread->MessageQueue);
1484
1485 Message->Msg.hwnd = hWnd;
1486 Message->Msg.message = Msg;
1487 Message->Msg.wParam = wParam;
1488 Message->Msg.lParam = lParamPacked;
1489 Message->CompletionEvent = NULL;
1490 Message->Result = 0;
1491 Message->lResult = 0;
1492 Message->QS_Flags = 0;
1493 Message->SenderQueue = NULL; // mjmartin, you are right! This is null.
1494 Message->CallBackSenderQueue = Win32Thread->MessageQueue;
1495 Message->DispatchingListEntry.Flink = NULL;
1496 Message->CompletionCallback = CompletionCallback;
1497 Message->CompletionCallbackContext = CompletionCallbackContext;
1498 Message->HookMessage = MSQ_NORMAL;
1499 Message->HasPackedLParam = (lParamBufferSize > 0);
1500 Message->QS_Flags = QS_SENDMESSAGE;
1501
1502 InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
1503 MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, TRUE);
1504 IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
1505
1506 RETURN(TRUE);
1507
1508 CLEANUP:
1509 if (Window) UserDerefObjectCo(Window);
1510 END_CLEANUP;
1511 }
1512
1513 /* This function posts a message if the destination's message queue belongs to
1514 another thread, otherwise it sends the message. It does not support broadcast
1515 messages! */
1516 LRESULT FASTCALL
1517 co_IntPostOrSendMessage( HWND hWnd,
1518 UINT Msg,
1519 WPARAM wParam,
1520 LPARAM lParam )
1521 {
1522 ULONG_PTR Result;
1523 PTHREADINFO pti;
1524 PWND Window;
1525
1526 if ( hWnd == HWND_BROADCAST )
1527 {
1528 return 0;
1529 }
1530
1531 if(!(Window = UserGetWindowObject(hWnd)))
1532 {
1533 return 0;
1534 }
1535
1536 pti = PsGetCurrentThreadWin32Thread();
1537
1538 if ( Window->head.pti->MessageQueue != pti->MessageQueue &&
1539 FindMsgMemory(Msg) == 0 )
1540 {
1541 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1542 }
1543 else
1544 {
1545 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1546 {
1547 Result = 0;
1548 }
1549 }
1550
1551 return (LRESULT)Result;
1552 }
1553
1554 LRESULT FASTCALL
1555 co_IntDoSendMessage( HWND hWnd,
1556 UINT Msg,
1557 WPARAM wParam,
1558 LPARAM lParam,
1559 PDOSENDMESSAGE dsm)
1560 {
1561 PTHREADINFO pti;
1562 LRESULT Result = TRUE;
1563 NTSTATUS Status;
1564 PWND Window = NULL;
1565 MSG UserModeMsg;
1566 MSG KernelModeMsg;
1567 PMSGMEMORY MsgMemoryEntry;
1568
1569 if (HWND_BROADCAST != hWnd)
1570 {
1571 Window = UserGetWindowObject(hWnd);
1572 if ( !Window )
1573 {
1574 return 0;
1575 }
1576 }
1577
1578 /* Check for an exiting window. */
1579 if (Window && Window->state & WNDS_DESTROYED)
1580 {
1581 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1582 }
1583
1584 /* See if the current thread can handle the message */
1585 pti = PsGetCurrentThreadWin32Thread();
1586
1587 UserModeMsg.hwnd = hWnd;
1588 UserModeMsg.message = Msg;
1589 UserModeMsg.wParam = wParam;
1590 UserModeMsg.lParam = lParam;
1591 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1592
1593 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1594 if (! NT_SUCCESS(Status))
1595 {
1596 EngSetLastError(ERROR_INVALID_PARAMETER);
1597 return (dsm ? 0 : -1);
1598 }
1599
1600 if (!dsm)
1601 {
1602 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1603 KernelModeMsg.message,
1604 KernelModeMsg.wParam,
1605 KernelModeMsg.lParam );
1606 }
1607 else
1608 {
1609 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1610 KernelModeMsg.message,
1611 KernelModeMsg.wParam,
1612 KernelModeMsg.lParam,
1613 dsm->uFlags,
1614 dsm->uTimeout,
1615 &dsm->Result );
1616 }
1617
1618 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1619 if (! NT_SUCCESS(Status))
1620 {
1621 EngSetLastError(ERROR_INVALID_PARAMETER);
1622 return(dsm ? 0 : -1);
1623 }
1624
1625 return (LRESULT)Result;
1626 }
1627
1628 BOOL FASTCALL
1629 UserSendNotifyMessage( HWND hWnd,
1630 UINT Msg,
1631 WPARAM wParam,
1632 LPARAM lParam )
1633 {
1634 BOOL Ret = TRUE;
1635
1636 if (is_pointer_message(Msg))
1637 {
1638 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1639 return FALSE;
1640 }
1641
1642 // Basicly the same as IntPostOrSendMessage
1643 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1644 {
1645 HWND *List;
1646 PWND DesktopWindow;
1647 ULONG i;
1648
1649 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1650 List = IntWinListChildren(DesktopWindow);
1651
1652 if (List != NULL)
1653 {
1654 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1655 for (i = 0; List[i]; i++)
1656 {
1657 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1658 }
1659 ExFreePool(List);
1660 }
1661 }
1662 else
1663 {
1664 ULONG_PTR lResult = 0;
1665 Ret = co_IntSendMessageWithCallBack( hWnd,
1666 Msg,
1667 wParam,
1668 lParam,
1669 NULL,
1670 0,
1671 &lResult);
1672 }
1673 return Ret;
1674 }
1675
1676
1677 DWORD APIENTRY
1678 IntGetQueueStatus(DWORD Changes)
1679 {
1680 PTHREADINFO pti;
1681 PUSER_MESSAGE_QUEUE Queue;
1682 DWORD Result;
1683
1684 pti = PsGetCurrentThreadWin32Thread();
1685 Queue = pti->MessageQueue;
1686 // wine:
1687 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1688
1689 /* High word, types of messages currently in the queue.
1690 Low word, types of messages that have been added to the queue and that
1691 are still in the queue
1692 */
1693 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
1694
1695 pti->pcti->fsChangeBits &= ~Changes;
1696
1697 return Result;
1698 }
1699
1700 BOOL APIENTRY
1701 IntInitMessagePumpHook()
1702 {
1703 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1704
1705 if (pti->pcti)
1706 {
1707 pti->pcti->dwcPumpHook++;
1708 return TRUE;
1709 }
1710 return FALSE;
1711 }
1712
1713 BOOL APIENTRY
1714 IntUninitMessagePumpHook()
1715 {
1716 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1717
1718 if (pti->pcti)
1719 {
1720 if (pti->pcti->dwcPumpHook <= 0)
1721 {
1722 return FALSE;
1723 }
1724 pti->pcti->dwcPumpHook--;
1725 return TRUE;
1726 }
1727 return FALSE;
1728 }
1729
1730 /** Functions ******************************************************************/
1731
1732 BOOL
1733 APIENTRY
1734 NtUserDragDetect(
1735 HWND hWnd,
1736 POINT pt) // Just like the User call.
1737 {
1738 MSG msg;
1739 RECT rect;
1740 WORD wDragWidth, wDragHeight;
1741 DECLARE_RETURN(BOOL);
1742
1743 DPRINT("Enter NtUserDragDetect(%x)\n", hWnd);
1744 UserEnterExclusive();
1745
1746 wDragWidth = UserGetSystemMetrics(SM_CXDRAG);
1747 wDragHeight= UserGetSystemMetrics(SM_CYDRAG);
1748
1749 rect.left = pt.x - wDragWidth;
1750 rect.right = pt.x + wDragWidth;
1751
1752 rect.top = pt.y - wDragHeight;
1753 rect.bottom = pt.y + wDragHeight;
1754
1755 co_UserSetCapture(hWnd);
1756
1757 for (;;)
1758 {
1759 while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) ||
1760 co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC, WM_QUEUESYNC, PM_REMOVE, FALSE ) ||
1761 co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE, FALSE ) )
1762 {
1763 if ( msg.message == WM_LBUTTONUP )
1764 {
1765 co_UserSetCapture(NULL);
1766 RETURN( FALSE);
1767 }
1768 if ( msg.message == WM_MOUSEMOVE )
1769 {
1770 POINT tmp;
1771 tmp.x = (short)LOWORD(msg.lParam);
1772 tmp.y = (short)HIWORD(msg.lParam);
1773 if( !IntPtInRect( &rect, tmp ) )
1774 {
1775 co_UserSetCapture(NULL);
1776 RETURN( TRUE);
1777 }
1778 }
1779 if ( msg.message == WM_KEYDOWN )
1780 {
1781 if ( msg.wParam == VK_ESCAPE )
1782 {
1783 co_UserSetCapture(NULL);
1784 RETURN( TRUE);
1785 }
1786 }
1787 if ( msg.message == WM_QUEUESYNC )
1788 {
1789 co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 );
1790 }
1791 }
1792 co_IntWaitMessage(NULL, 0, 0);
1793 }
1794 RETURN( FALSE);
1795
1796 CLEANUP:
1797 DPRINT("Leave NtUserDragDetect, ret=%i\n",_ret_);
1798 UserLeave();
1799 END_CLEANUP;
1800 }
1801
1802 BOOL APIENTRY
1803 NtUserPostMessage(HWND hWnd,
1804 UINT Msg,
1805 WPARAM wParam,
1806 LPARAM lParam)
1807 {
1808 BOOL ret;
1809
1810 UserEnterExclusive();
1811
1812 ret = UserPostMessage(hWnd, Msg, wParam, lParam);
1813
1814 UserLeave();
1815
1816 return ret;
1817 }
1818
1819 BOOL APIENTRY
1820 NtUserPostThreadMessage(DWORD idThread,
1821 UINT Msg,
1822 WPARAM wParam,
1823 LPARAM lParam)
1824 {
1825 BOOL ret;
1826
1827 UserEnterExclusive();
1828
1829 ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
1830
1831 UserLeave();
1832
1833 return ret;
1834 }
1835
1836 BOOL APIENTRY
1837 NtUserWaitMessage(VOID)
1838 {
1839 BOOL ret;
1840
1841 UserEnterExclusive();
1842 DPRINT("NtUserWaitMessage Enter\n");
1843 ret = co_IntWaitMessage(NULL, 0, 0);
1844 DPRINT("NtUserWaitMessage Leave\n");
1845 UserLeave();
1846
1847 return ret;
1848 }
1849
1850 BOOL APIENTRY
1851 NtUserGetMessage(PMSG pMsg,
1852 HWND hWnd,
1853 UINT MsgFilterMin,
1854 UINT MsgFilterMax )
1855 {
1856 MSG Msg;
1857 BOOL Ret;
1858
1859 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
1860 {
1861 EngSetLastError(ERROR_INVALID_PARAMETER);
1862 return FALSE;
1863 }
1864
1865 UserEnterExclusive();
1866
1867 RtlZeroMemory(&Msg, sizeof(MSG));
1868
1869 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
1870
1871 UserLeave();
1872
1873 if (Ret == TRUE)
1874 {
1875 _SEH2_TRY
1876 {
1877 ProbeForWrite(pMsg, sizeof(MSG), 1);
1878 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1879 }
1880 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1881 {
1882 SetLastNtError(_SEH2_GetExceptionCode());
1883 Ret = FALSE;
1884 }
1885 _SEH2_END;
1886 }
1887
1888 if ((INT)Ret != -1)
1889 Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE;
1890
1891 return Ret;
1892 }
1893
1894 BOOL APIENTRY
1895 NtUserPeekMessage( PMSG pMsg,
1896 HWND hWnd,
1897 UINT MsgFilterMin,
1898 UINT MsgFilterMax,
1899 UINT RemoveMsg)
1900 {
1901 MSG Msg;
1902 BOOL Ret;
1903
1904 if ( RemoveMsg & PM_BADMSGFLAGS )
1905 {
1906 EngSetLastError(ERROR_INVALID_FLAGS);
1907 return FALSE;
1908 }
1909
1910 UserEnterExclusive();
1911
1912 RtlZeroMemory(&Msg, sizeof(MSG));
1913
1914 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
1915
1916 UserLeave();
1917
1918 if (Ret)
1919 {
1920 _SEH2_TRY
1921 {
1922 ProbeForWrite(pMsg, sizeof(MSG), 1);
1923 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1924 }
1925 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1926 {
1927 SetLastNtError(_SEH2_GetExceptionCode());
1928 Ret = FALSE;
1929 }
1930 _SEH2_END;
1931 }
1932
1933 return Ret;
1934 }
1935
1936 BOOL APIENTRY
1937 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
1938 {
1939 BOOL Ret = FALSE;
1940 MSG Msg;
1941
1942 _SEH2_TRY
1943 {
1944 ProbeForRead(lpmsg, sizeof(MSG), 1);
1945 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
1946 }
1947 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1948 {
1949 _SEH2_YIELD(return FALSE);
1950 }
1951 _SEH2_END;
1952
1953 UserEnterExclusive();
1954
1955 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
1956 {
1957 Ret = TRUE;
1958 }
1959 else
1960 {
1961 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
1962 }
1963
1964 UserLeave();
1965
1966 _SEH2_TRY
1967 {
1968 ProbeForWrite(lpmsg, sizeof(MSG), 1);
1969 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
1970 }
1971 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1972 {
1973 Ret = FALSE;
1974 }
1975 _SEH2_END;
1976
1977 return Ret;
1978 }
1979
1980 LRESULT APIENTRY
1981 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
1982 {
1983 LRESULT Res = 0;
1984 MSG SafeMsg;
1985
1986 _SEH2_TRY
1987 {
1988 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
1989 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
1990 }
1991 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1992 {
1993 SetLastNtError(_SEH2_GetExceptionCode());
1994 _SEH2_YIELD(return FALSE);
1995 }
1996 _SEH2_END;
1997
1998 UserEnterExclusive();
1999
2000 Res = IntDispatchMessage(&SafeMsg);
2001
2002 UserLeave();
2003 return Res;
2004 }
2005
2006
2007 BOOL APIENTRY
2008 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
2009 {
2010 MSG SafeMsg;
2011 BOOL Ret;
2012
2013 _SEH2_TRY
2014 {
2015 ProbeForRead(lpMsg, sizeof(MSG), 1);
2016 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
2017 }
2018 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2019 {
2020 SetLastNtError(_SEH2_GetExceptionCode());
2021 _SEH2_YIELD(return FALSE);
2022 }
2023 _SEH2_END;
2024
2025 UserEnterExclusive();
2026
2027 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
2028
2029 UserLeave();
2030
2031 return Ret;
2032 }
2033
2034 BOOL APIENTRY
2035 NtUserMessageCall( HWND hWnd,
2036 UINT Msg,
2037 WPARAM wParam,
2038 LPARAM lParam,
2039 ULONG_PTR ResultInfo,
2040 DWORD dwType, // fnID?
2041 BOOL Ansi)
2042 {
2043 LRESULT lResult = 0;
2044 BOOL Ret = FALSE;
2045 PWND Window = NULL;
2046 USER_REFERENCE_ENTRY Ref;
2047
2048 UserEnterExclusive();
2049
2050 switch(dwType)
2051 {
2052 case FNID_DEFWINDOWPROC:
2053 /* Validate input */
2054 if (hWnd && (hWnd != INVALID_HANDLE_VALUE))
2055 {
2056 Window = UserGetWindowObject(hWnd);
2057 if (!Window)
2058 {
2059 UserLeave();
2060 return FALSE;
2061 }
2062 }
2063 UserRefObjectCo(Window, &Ref);
2064 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2065 Ret = TRUE;
2066 UserDerefObjectCo(Window);
2067 break;
2068 case FNID_SENDNOTIFYMESSAGE:
2069 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2070 break;
2071 case FNID_BROADCASTSYSTEMMESSAGE:
2072 {
2073 BROADCASTPARM parm;
2074 DWORD_PTR RetVal = 0;
2075
2076 if (ResultInfo)
2077 {
2078 _SEH2_TRY
2079 {
2080 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
2081 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2082 }
2083 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2084 {
2085 _SEH2_YIELD(break);
2086 }
2087 _SEH2_END;
2088 }
2089 else
2090 break;
2091
2092 if ( parm.recipients & BSM_ALLDESKTOPS ||
2093 parm.recipients == BSM_ALLCOMPONENTS )
2094 {
2095 }
2096 else if (parm.recipients & BSM_APPLICATIONS)
2097 {
2098 if (parm.flags & BSF_QUERY)
2099 {
2100 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2101 {
2102 co_IntSendMessageTimeout( HWND_BROADCAST,
2103 Msg,
2104 wParam,
2105 lParam,
2106 SMTO_ABORTIFHUNG,
2107 2000,
2108 &RetVal);
2109 }
2110 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2111 {
2112 co_IntSendMessageTimeout( HWND_BROADCAST,
2113 Msg,
2114 wParam,
2115 lParam,
2116 SMTO_NOTIMEOUTIFNOTHUNG,
2117 2000,
2118 &RetVal);
2119 }
2120 else
2121 {
2122 co_IntSendMessageTimeout( HWND_BROADCAST,
2123 Msg,
2124 wParam,
2125 lParam,
2126 SMTO_NORMAL,
2127 2000,
2128 &RetVal);
2129 }
2130 Ret = RetVal;
2131 }
2132 else if (parm.flags & BSF_POSTMESSAGE)
2133 {
2134 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2135 }
2136 else //Everything else,,,, if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2137 {
2138 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2139 }
2140 }
2141 }
2142 break;
2143 case FNID_SENDMESSAGECALLBACK:
2144 {
2145 CALL_BACK_INFO CallBackInfo;
2146 ULONG_PTR uResult;
2147
2148 _SEH2_TRY
2149 {
2150 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
2151 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
2152 }
2153 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2154 {
2155 _SEH2_YIELD(break);
2156 }
2157 _SEH2_END;
2158
2159 if (is_pointer_message(Msg))
2160 {
2161 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
2162 break;
2163 }
2164
2165 if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2166 CallBackInfo.CallBack, CallBackInfo.Context, &uResult)))
2167 {
2168 DPRINT1("Callback failure!\n");
2169 }
2170 }
2171 break;
2172 case FNID_SENDMESSAGE:
2173 {
2174 Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
2175
2176 if (ResultInfo)
2177 {
2178 _SEH2_TRY
2179 {
2180 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
2181 RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
2182 }
2183 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2184 {
2185 Ret = FALSE;
2186 _SEH2_YIELD(break);
2187 }
2188 _SEH2_END;
2189 }
2190 break;
2191 }
2192 case FNID_SENDMESSAGETIMEOUT:
2193 {
2194 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
2195 if (ResultInfo)
2196 {
2197 _SEH2_TRY
2198 {
2199 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
2200 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
2201 }
2202 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2203 {
2204 _SEH2_YIELD(break);
2205 }
2206 _SEH2_END;
2207 }
2208
2209 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
2210
2211 if (pdsm)
2212 {
2213 _SEH2_TRY
2214 {
2215 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
2216 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2217 }
2218 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2219 {
2220 Ret = FALSE;
2221 _SEH2_YIELD(break);
2222 }
2223 _SEH2_END;
2224 }
2225 break;
2226 }
2227 // CallNextHook bypass.
2228 case FNID_CALLWNDPROC:
2229 case FNID_CALLWNDPROCRET:
2230 {
2231 PTHREADINFO pti;
2232 PCLIENTINFO ClientInfo;
2233 PHOOK NextObj, Hook;
2234
2235 pti = GetW32ThreadInfo();
2236
2237 Hook = pti->sphkCurrent;
2238
2239 if (!Hook) break;
2240
2241 NextObj = Hook->phkNext;
2242 ClientInfo = pti->pClientInfo;
2243 _SEH2_TRY
2244 {
2245 ClientInfo->phkCurrent = NextObj;
2246 }
2247 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2248 {
2249 ClientInfo = NULL;
2250 }
2251 _SEH2_END;
2252
2253 if (!ClientInfo || !NextObj) break;
2254
2255 NextObj->phkNext = IntGetNextHook(NextObj);
2256
2257 if ( Hook->HookId == WH_CALLWNDPROC)
2258 {
2259 CWPSTRUCT CWP;
2260 CWP.hwnd = hWnd;
2261 CWP.message = Msg;
2262 CWP.wParam = wParam;
2263 CWP.lParam = lParam;
2264 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2265
2266 lResult = co_IntCallHookProc( Hook->HookId,
2267 HC_ACTION,
2268 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2269 (LPARAM)&CWP,
2270 Hook->Proc,
2271 Hook->Ansi,
2272 &Hook->ModuleName);
2273 }
2274 else
2275 {
2276 CWPRETSTRUCT CWPR;
2277 CWPR.hwnd = hWnd;
2278 CWPR.message = Msg;
2279 CWPR.wParam = wParam;
2280 CWPR.lParam = lParam;
2281 CWPR.lResult = ClientInfo->dwHookData;
2282
2283 lResult = co_IntCallHookProc( Hook->HookId,
2284 HC_ACTION,
2285 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2286 (LPARAM)&CWPR,
2287 Hook->Proc,
2288 Hook->Ansi,
2289 &Hook->ModuleName);
2290 }
2291 }
2292 break;
2293 }
2294
2295 switch(dwType)
2296 {
2297 case FNID_DEFWINDOWPROC:
2298 case FNID_CALLWNDPROC:
2299 case FNID_CALLWNDPROCRET:
2300 if (ResultInfo)
2301 {
2302 _SEH2_TRY
2303 {
2304 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2305 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2306 }
2307 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2308 {
2309 Ret = FALSE;
2310 }
2311 _SEH2_END;
2312 }
2313 break;
2314 default:
2315 break;
2316 }
2317
2318 UserLeave();
2319
2320 return Ret;
2321 }
2322
2323 #define INFINITE 0xFFFFFFFF
2324 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2325
2326 DWORD
2327 APIENTRY
2328 NtUserWaitForInputIdle( IN HANDLE hProcess,
2329 IN DWORD dwMilliseconds,
2330 IN BOOL Unknown2)
2331 {
2332 PEPROCESS Process;
2333 PPROCESSINFO W32Process;
2334 PTHREADINFO pti;
2335 NTSTATUS Status;
2336 HANDLE Handles[3];
2337 LARGE_INTEGER Timeout;
2338
2339 UserEnterExclusive();
2340
2341 Status = ObReferenceObjectByHandle(hProcess,
2342 PROCESS_QUERY_INFORMATION,
2343 PsProcessType,
2344 UserMode,
2345 (PVOID*)&Process,
2346 NULL);
2347
2348 if (!NT_SUCCESS(Status))
2349 {
2350 UserLeave();
2351 SetLastNtError(Status);
2352 return WAIT_FAILED;
2353 }
2354
2355 pti = PsGetCurrentThreadWin32Thread();
2356
2357 W32Process = (PPROCESSINFO)Process->Win32Process;
2358
2359 if ( PsGetProcessExitProcessCalled(Process) ||
2360 !W32Process ||
2361 pti->ppi == W32Process)
2362 {
2363 ObDereferenceObject(Process);
2364 UserLeave();
2365 EngSetLastError(ERROR_INVALID_PARAMETER);
2366 return WAIT_FAILED;
2367 }
2368
2369 Handles[0] = Process;
2370 Handles[1] = W32Process->InputIdleEvent;
2371 Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2372
2373 if (!Handles[1])
2374 {
2375 ObDereferenceObject(Process);
2376 UserLeave();
2377 return STATUS_SUCCESS; /* no event to wait on */
2378 }
2379
2380 if (dwMilliseconds != INFINITE)
2381 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2382
2383 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2384 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2385 {
2386 pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2387 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2388 }
2389
2390 DPRINT("WFII: ppi 0x%x\n",W32Process);
2391 DPRINT("WFII: waiting for %p\n", Handles[1] );
2392 do
2393 {
2394 UserLeave();
2395 Status = KeWaitForMultipleObjects( 3,
2396 Handles,
2397 WaitAny,
2398 UserRequest,
2399 UserMode,
2400 FALSE,
2401 dwMilliseconds == INFINITE ? NULL : &Timeout,
2402 NULL);
2403 UserEnterExclusive();
2404
2405 if (!NT_SUCCESS(Status))
2406 {
2407 SetLastNtError(Status);
2408 Status = WAIT_FAILED;
2409 goto WaitExit;
2410 }
2411
2412 switch (Status)
2413 {
2414 case STATUS_WAIT_0:
2415 goto WaitExit;
2416
2417 case STATUS_WAIT_2:
2418 {
2419 MSG Msg;
2420 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
2421 DPRINT1("WFII: WAIT 2\n");
2422 }
2423 break;
2424
2425 case STATUS_TIMEOUT:
2426 DPRINT1("WFII: timeout\n");
2427 case WAIT_FAILED:
2428 goto WaitExit;
2429
2430 default:
2431 DPRINT1("WFII: finished\n");
2432 Status = STATUS_SUCCESS;
2433 goto WaitExit;
2434 }
2435 }
2436 while (TRUE);
2437
2438 WaitExit:
2439 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2440 {
2441 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
2442 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2443 }
2444 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
2445 ObDereferenceObject(Process);
2446 UserLeave();
2447 return Status;
2448 }
2449
2450 /* EOF */