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