Revert r51031
[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 STATUS_INSUFFICIENT_RESOURCES;
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 Message->CallBackSenderQueue = Win32Thread->MessageQueue;
1463
1464 IntReferenceMessageQueue(Window->head.pti->MessageQueue);
1465 Message->CompletionCallback = CompletionCallback;
1466 Message->CompletionCallbackContext = CompletionCallbackContext;
1467 Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT;
1468 Message->HasPackedLParam = (lParamBufferSize > 0);
1469
1470 Message->QS_Flags = QS_SENDMESSAGE;
1471 MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, FALSE);
1472
1473 InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
1474 IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
1475
1476 RETURN(TRUE);
1477
1478 CLEANUP:
1479 if (Window) UserDerefObjectCo(Window);
1480 END_CLEANUP;
1481 }
1482
1483 /* This function posts a message if the destination's message queue belongs to
1484 another thread, otherwise it sends the message. It does not support broadcast
1485 messages! */
1486 LRESULT FASTCALL
1487 co_IntPostOrSendMessage( HWND hWnd,
1488 UINT Msg,
1489 WPARAM wParam,
1490 LPARAM lParam )
1491 {
1492 ULONG_PTR Result;
1493 PTHREADINFO pti;
1494 PWND Window;
1495
1496 if ( hWnd == HWND_BROADCAST )
1497 {
1498 return 0;
1499 }
1500
1501 if(!(Window = UserGetWindowObject(hWnd)))
1502 {
1503 return 0;
1504 }
1505
1506 pti = PsGetCurrentThreadWin32Thread();
1507
1508 if ( Window->head.pti->MessageQueue != pti->MessageQueue &&
1509 FindMsgMemory(Msg) == 0 )
1510 {
1511 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1512 }
1513 else
1514 {
1515 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1516 {
1517 Result = 0;
1518 }
1519 }
1520
1521 return (LRESULT)Result;
1522 }
1523
1524 LRESULT FASTCALL
1525 co_IntDoSendMessage( HWND hWnd,
1526 UINT Msg,
1527 WPARAM wParam,
1528 LPARAM lParam,
1529 PDOSENDMESSAGE dsm)
1530 {
1531 PTHREADINFO pti;
1532 LRESULT Result = TRUE;
1533 NTSTATUS Status;
1534 PWND Window = NULL;
1535 MSG UserModeMsg;
1536 MSG KernelModeMsg;
1537 PMSGMEMORY MsgMemoryEntry;
1538
1539 if (HWND_BROADCAST != hWnd)
1540 {
1541 Window = UserGetWindowObject(hWnd);
1542 if ( !Window )
1543 {
1544 return 0;
1545 }
1546 }
1547
1548 /* Check for an exiting window. */
1549 if (Window && Window->state & WNDS_DESTROYED)
1550 {
1551 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1552 }
1553
1554 /* See if the current thread can handle the message */
1555 pti = PsGetCurrentThreadWin32Thread();
1556
1557 UserModeMsg.hwnd = hWnd;
1558 UserModeMsg.message = Msg;
1559 UserModeMsg.wParam = wParam;
1560 UserModeMsg.lParam = lParam;
1561 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1562
1563 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1564 if (! NT_SUCCESS(Status))
1565 {
1566 EngSetLastError(ERROR_INVALID_PARAMETER);
1567 return (dsm ? 0 : -1);
1568 }
1569
1570 if (!dsm)
1571 {
1572 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1573 KernelModeMsg.message,
1574 KernelModeMsg.wParam,
1575 KernelModeMsg.lParam );
1576 }
1577 else
1578 {
1579 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1580 KernelModeMsg.message,
1581 KernelModeMsg.wParam,
1582 KernelModeMsg.lParam,
1583 dsm->uFlags,
1584 dsm->uTimeout,
1585 &dsm->Result );
1586 }
1587
1588 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1589 if (! NT_SUCCESS(Status))
1590 {
1591 EngSetLastError(ERROR_INVALID_PARAMETER);
1592 return(dsm ? 0 : -1);
1593 }
1594
1595 return (LRESULT)Result;
1596 }
1597
1598 BOOL FASTCALL
1599 UserSendNotifyMessage( HWND hWnd,
1600 UINT Msg,
1601 WPARAM wParam,
1602 LPARAM lParam )
1603 {
1604 BOOL Ret = TRUE;
1605
1606 if (is_pointer_message(Msg))
1607 {
1608 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1609 return FALSE;
1610 }
1611
1612 // Basicly the same as IntPostOrSendMessage
1613 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1614 {
1615 HWND *List;
1616 PWND DesktopWindow;
1617 ULONG i;
1618
1619 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1620 List = IntWinListChildren(DesktopWindow);
1621
1622 if (List != NULL)
1623 {
1624 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1625 for (i = 0; List[i]; i++)
1626 {
1627 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1628 }
1629 ExFreePool(List);
1630 }
1631 }
1632 else
1633 {
1634 ULONG_PTR lResult = 0;
1635 Ret = co_IntSendMessageWithCallBack( hWnd,
1636 Msg,
1637 wParam,
1638 lParam,
1639 NULL,
1640 0,
1641 &lResult);
1642 }
1643 return Ret;
1644 }
1645
1646
1647 DWORD APIENTRY
1648 IntGetQueueStatus(DWORD Changes)
1649 {
1650 PTHREADINFO pti;
1651 PUSER_MESSAGE_QUEUE Queue;
1652 DWORD Result;
1653
1654 pti = PsGetCurrentThreadWin32Thread();
1655 Queue = pti->MessageQueue;
1656 // wine:
1657 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1658
1659 /* High word, types of messages currently in the queue.
1660 Low word, types of messages that have been added to the queue and that
1661 are still in the queue
1662 */
1663 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
1664
1665 pti->pcti->fsChangeBits &= ~Changes;
1666
1667 return Result;
1668 }
1669
1670 BOOL APIENTRY
1671 IntInitMessagePumpHook()
1672 {
1673 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1674
1675 if (pti->pcti)
1676 {
1677 pti->pcti->dwcPumpHook++;
1678 return TRUE;
1679 }
1680 return FALSE;
1681 }
1682
1683 BOOL APIENTRY
1684 IntUninitMessagePumpHook()
1685 {
1686 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1687
1688 if (pti->pcti)
1689 {
1690 if (pti->pcti->dwcPumpHook <= 0)
1691 {
1692 return FALSE;
1693 }
1694 pti->pcti->dwcPumpHook--;
1695 return TRUE;
1696 }
1697 return FALSE;
1698 }
1699
1700 /** Functions ******************************************************************/
1701
1702 BOOL
1703 APIENTRY
1704 NtUserDragDetect(
1705 HWND hWnd,
1706 POINT pt) // Just like the User call.
1707 {
1708 MSG msg;
1709 RECT rect;
1710 WORD wDragWidth, wDragHeight;
1711 DECLARE_RETURN(BOOL);
1712
1713 DPRINT("Enter NtUserDragDetect(%x)\n", hWnd);
1714 UserEnterExclusive();
1715
1716 wDragWidth = UserGetSystemMetrics(SM_CXDRAG);
1717 wDragHeight= UserGetSystemMetrics(SM_CYDRAG);
1718
1719 rect.left = pt.x - wDragWidth;
1720 rect.right = pt.x + wDragWidth;
1721
1722 rect.top = pt.y - wDragHeight;
1723 rect.bottom = pt.y + wDragHeight;
1724
1725 co_UserSetCapture(hWnd);
1726
1727 for (;;)
1728 {
1729 while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) ||
1730 co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC, WM_QUEUESYNC, PM_REMOVE, FALSE ) ||
1731 co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE, FALSE ) )
1732 {
1733 if ( msg.message == WM_LBUTTONUP )
1734 {
1735 co_UserSetCapture(NULL);
1736 RETURN( FALSE);
1737 }
1738 if ( msg.message == WM_MOUSEMOVE )
1739 {
1740 POINT tmp;
1741 tmp.x = (short)LOWORD(msg.lParam);
1742 tmp.y = (short)HIWORD(msg.lParam);
1743 if( !IntPtInRect( &rect, tmp ) )
1744 {
1745 co_UserSetCapture(NULL);
1746 RETURN( TRUE);
1747 }
1748 }
1749 if ( msg.message == WM_KEYDOWN )
1750 {
1751 if ( msg.wParam == VK_ESCAPE )
1752 {
1753 co_UserSetCapture(NULL);
1754 RETURN( TRUE);
1755 }
1756 }
1757 if ( msg.message == WM_QUEUESYNC )
1758 {
1759 co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 );
1760 }
1761 }
1762 co_IntWaitMessage(NULL, 0, 0);
1763 }
1764 RETURN( FALSE);
1765
1766 CLEANUP:
1767 DPRINT("Leave NtUserDragDetect, ret=%i\n",_ret_);
1768 UserLeave();
1769 END_CLEANUP;
1770 }
1771
1772 BOOL APIENTRY
1773 NtUserPostMessage(HWND hWnd,
1774 UINT Msg,
1775 WPARAM wParam,
1776 LPARAM lParam)
1777 {
1778 BOOL ret;
1779
1780 UserEnterExclusive();
1781
1782 ret = UserPostMessage(hWnd, Msg, wParam, lParam);
1783
1784 UserLeave();
1785
1786 return ret;
1787 }
1788
1789 BOOL APIENTRY
1790 NtUserPostThreadMessage(DWORD idThread,
1791 UINT Msg,
1792 WPARAM wParam,
1793 LPARAM lParam)
1794 {
1795 BOOL ret;
1796
1797 UserEnterExclusive();
1798
1799 ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
1800
1801 UserLeave();
1802
1803 return ret;
1804 }
1805
1806 BOOL APIENTRY
1807 NtUserWaitMessage(VOID)
1808 {
1809 BOOL ret;
1810
1811 UserEnterExclusive();
1812 DPRINT("NtUserWaitMessage Enter\n");
1813 ret = co_IntWaitMessage(NULL, 0, 0);
1814 DPRINT("NtUserWaitMessage Leave\n");
1815 UserLeave();
1816
1817 return ret;
1818 }
1819
1820 BOOL APIENTRY
1821 NtUserGetMessage(PMSG pMsg,
1822 HWND hWnd,
1823 UINT MsgFilterMin,
1824 UINT MsgFilterMax )
1825 {
1826 MSG Msg;
1827 BOOL Ret;
1828
1829 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
1830 {
1831 EngSetLastError(ERROR_INVALID_PARAMETER);
1832 return FALSE;
1833 }
1834
1835 UserEnterExclusive();
1836
1837 RtlZeroMemory(&Msg, sizeof(MSG));
1838
1839 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
1840
1841 UserLeave();
1842
1843 if (Ret)
1844 {
1845 _SEH2_TRY
1846 {
1847 ProbeForWrite(pMsg, sizeof(MSG), 1);
1848 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1849 }
1850 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1851 {
1852 SetLastNtError(_SEH2_GetExceptionCode());
1853 Ret = FALSE;
1854 }
1855 _SEH2_END;
1856 }
1857
1858 return Ret;
1859 }
1860
1861 BOOL APIENTRY
1862 NtUserPeekMessage( PMSG pMsg,
1863 HWND hWnd,
1864 UINT MsgFilterMin,
1865 UINT MsgFilterMax,
1866 UINT RemoveMsg)
1867 {
1868 MSG Msg;
1869 BOOL Ret;
1870
1871 if ( RemoveMsg & PM_BADMSGFLAGS )
1872 {
1873 EngSetLastError(ERROR_INVALID_FLAGS);
1874 return FALSE;
1875 }
1876
1877 UserEnterExclusive();
1878
1879 RtlZeroMemory(&Msg, sizeof(MSG));
1880
1881 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
1882
1883 UserLeave();
1884
1885 if (Ret)
1886 {
1887 _SEH2_TRY
1888 {
1889 ProbeForWrite(pMsg, sizeof(MSG), 1);
1890 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1891 }
1892 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1893 {
1894 SetLastNtError(_SEH2_GetExceptionCode());
1895 Ret = FALSE;
1896 }
1897 _SEH2_END;
1898 }
1899
1900 return Ret;
1901 }
1902
1903 BOOL APIENTRY
1904 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
1905 {
1906 BOOL Ret = FALSE;
1907 MSG Msg;
1908
1909 _SEH2_TRY
1910 {
1911 ProbeForRead(lpmsg, sizeof(MSG), 1);
1912 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
1913 }
1914 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1915 {
1916 _SEH2_YIELD(return FALSE);
1917 }
1918 _SEH2_END;
1919
1920 UserEnterExclusive();
1921
1922 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
1923 {
1924 Ret = TRUE;
1925 }
1926 else
1927 {
1928 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
1929 }
1930
1931 UserLeave();
1932
1933 _SEH2_TRY
1934 {
1935 ProbeForWrite(lpmsg, sizeof(MSG), 1);
1936 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
1937 }
1938 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1939 {
1940 Ret = FALSE;
1941 }
1942 _SEH2_END;
1943
1944 return Ret;
1945 }
1946
1947 LRESULT APIENTRY
1948 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
1949 {
1950 LRESULT Res = 0;
1951 MSG SafeMsg;
1952
1953 _SEH2_TRY
1954 {
1955 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
1956 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
1957 }
1958 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1959 {
1960 SetLastNtError(_SEH2_GetExceptionCode());
1961 _SEH2_YIELD(return FALSE);
1962 }
1963 _SEH2_END;
1964
1965 UserEnterExclusive();
1966
1967 Res = IntDispatchMessage(&SafeMsg);
1968
1969 UserLeave();
1970 return Res;
1971 }
1972
1973
1974 BOOL APIENTRY
1975 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
1976 {
1977 MSG SafeMsg;
1978 BOOL Ret;
1979
1980 _SEH2_TRY
1981 {
1982 ProbeForRead(lpMsg, sizeof(MSG), 1);
1983 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
1984 }
1985 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1986 {
1987 SetLastNtError(_SEH2_GetExceptionCode());
1988 _SEH2_YIELD(return FALSE);
1989 }
1990 _SEH2_END;
1991
1992 UserEnterExclusive();
1993
1994 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
1995
1996 UserLeave();
1997
1998 return Ret;
1999 }
2000
2001 BOOL APIENTRY
2002 NtUserMessageCall( HWND hWnd,
2003 UINT Msg,
2004 WPARAM wParam,
2005 LPARAM lParam,
2006 ULONG_PTR ResultInfo,
2007 DWORD dwType, // fnID?
2008 BOOL Ansi)
2009 {
2010 LRESULT lResult = 0;
2011 BOOL Ret = FALSE;
2012 PWND Window = NULL;
2013 USER_REFERENCE_ENTRY Ref;
2014
2015 UserEnterExclusive();
2016
2017 /* Validate input */
2018 if (hWnd && (hWnd != INVALID_HANDLE_VALUE))
2019 {
2020 Window = UserGetWindowObject(hWnd);
2021 if (!Window)
2022 {
2023 UserLeave();
2024 return FALSE;
2025 }
2026 }
2027
2028 switch(dwType)
2029 {
2030 case FNID_DEFWINDOWPROC:
2031 if (Window) UserRefObjectCo(Window, &Ref);
2032 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2033 Ret = TRUE;
2034 if (Window) UserDerefObjectCo(Window);
2035 break;
2036 case FNID_SENDNOTIFYMESSAGE:
2037 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2038 break;
2039 case FNID_BROADCASTSYSTEMMESSAGE:
2040 {
2041 BROADCASTPARM parm;
2042 DWORD_PTR RetVal = 0;
2043
2044 if (ResultInfo)
2045 {
2046 _SEH2_TRY
2047 {
2048 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
2049 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2050 }
2051 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2052 {
2053 Ret = FALSE;
2054 _SEH2_YIELD(break);
2055 }
2056 _SEH2_END;
2057 }
2058 else
2059 break;
2060
2061 if ( parm.recipients & BSM_ALLDESKTOPS ||
2062 parm.recipients == BSM_ALLCOMPONENTS )
2063 {
2064 }
2065 else if (parm.recipients & BSM_APPLICATIONS)
2066 {
2067 if (parm.flags & BSF_QUERY)
2068 {
2069 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2070 {
2071 co_IntSendMessageTimeout( HWND_BROADCAST,
2072 Msg,
2073 wParam,
2074 lParam,
2075 SMTO_ABORTIFHUNG,
2076 2000,
2077 &RetVal);
2078 }
2079 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2080 {
2081 co_IntSendMessageTimeout( HWND_BROADCAST,
2082 Msg,
2083 wParam,
2084 lParam,
2085 SMTO_NOTIMEOUTIFNOTHUNG,
2086 2000,
2087 &RetVal);
2088 }
2089 else
2090 {
2091 co_IntSendMessageTimeout( HWND_BROADCAST,
2092 Msg,
2093 wParam,
2094 lParam,
2095 SMTO_NORMAL,
2096 2000,
2097 &RetVal);
2098 }
2099 Ret = RetVal;
2100 }
2101 else if (parm.flags & BSF_POSTMESSAGE)
2102 {
2103 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2104 }
2105 else //Everything else,,,, if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2106 {
2107 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2108 }
2109 }
2110 }
2111 break;
2112 case FNID_SENDMESSAGECALLBACK:
2113 {
2114 CALL_BACK_INFO CallBackInfo;
2115 ULONG_PTR uResult;
2116
2117 _SEH2_TRY
2118 {
2119 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
2120 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
2121 }
2122 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2123 {
2124 Ret = FALSE;
2125 _SEH2_YIELD(break);
2126 }
2127 _SEH2_END;
2128
2129 if (!co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2130 CallBackInfo.CallBack, CallBackInfo.Context, &uResult))
2131 {
2132 DPRINT1("Callback failure!\n");
2133 }
2134 }
2135 break;
2136 case FNID_SENDMESSAGE:
2137 {
2138 Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
2139
2140 if (ResultInfo)
2141 {
2142 _SEH2_TRY
2143 {
2144 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
2145 RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
2146 }
2147 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2148 {
2149 Ret = FALSE;
2150 _SEH2_YIELD(break);
2151 }
2152 _SEH2_END;
2153 }
2154 break;
2155 }
2156 case FNID_SENDMESSAGETIMEOUT:
2157 {
2158 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
2159 if (ResultInfo)
2160 {
2161 _SEH2_TRY
2162 {
2163 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
2164 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
2165 }
2166 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2167 {
2168 Ret = FALSE;
2169 _SEH2_YIELD(break);
2170 }
2171 _SEH2_END;
2172 }
2173
2174 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
2175
2176 if (pdsm)
2177 {
2178 _SEH2_TRY
2179 {
2180 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
2181 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2182 }
2183 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2184 {
2185 Ret = FALSE;
2186 _SEH2_YIELD(break);
2187 }
2188 _SEH2_END;
2189 }
2190 break;
2191 }
2192 // CallNextHook bypass.
2193 case FNID_CALLWNDPROC:
2194 case FNID_CALLWNDPROCRET:
2195 {
2196 PTHREADINFO pti;
2197 PCLIENTINFO ClientInfo;
2198 PHOOK NextObj, Hook;
2199
2200 pti = GetW32ThreadInfo();
2201
2202 Hook = pti->sphkCurrent;
2203
2204 if (!Hook) break;
2205
2206 NextObj = Hook->phkNext;
2207 ClientInfo = pti->pClientInfo;
2208 _SEH2_TRY
2209 {
2210 ClientInfo->phkCurrent = NextObj;
2211 }
2212 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2213 {
2214 ClientInfo = NULL;
2215 }
2216 _SEH2_END;
2217
2218 if (!ClientInfo || !NextObj) break;
2219
2220 NextObj->phkNext = IntGetNextHook(NextObj);
2221
2222 if ( Hook->HookId == WH_CALLWNDPROC)
2223 {
2224 CWPSTRUCT CWP;
2225 CWP.hwnd = hWnd;
2226 CWP.message = Msg;
2227 CWP.wParam = wParam;
2228 CWP.lParam = lParam;
2229 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2230
2231 lResult = co_IntCallHookProc( Hook->HookId,
2232 HC_ACTION,
2233 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2234 (LPARAM)&CWP,
2235 Hook->Proc,
2236 Hook->Ansi,
2237 &Hook->ModuleName);
2238 }
2239 else
2240 {
2241 CWPRETSTRUCT CWPR;
2242 CWPR.hwnd = hWnd;
2243 CWPR.message = Msg;
2244 CWPR.wParam = wParam;
2245 CWPR.lParam = lParam;
2246 CWPR.lResult = ClientInfo->dwHookData;
2247
2248 lResult = co_IntCallHookProc( Hook->HookId,
2249 HC_ACTION,
2250 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2251 (LPARAM)&CWPR,
2252 Hook->Proc,
2253 Hook->Ansi,
2254 &Hook->ModuleName);
2255 }
2256 }
2257 break;
2258 }
2259
2260 switch(dwType)
2261 {
2262 case FNID_DEFWINDOWPROC:
2263 case FNID_CALLWNDPROC:
2264 case FNID_CALLWNDPROCRET:
2265 if (ResultInfo)
2266 {
2267 _SEH2_TRY
2268 {
2269 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2270 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2271 }
2272 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2273 {
2274 Ret = FALSE;
2275 }
2276 _SEH2_END;
2277 }
2278 break;
2279 default:
2280 break;
2281 }
2282
2283 UserLeave();
2284
2285 return Ret;
2286 }
2287
2288 #define INFINITE 0xFFFFFFFF
2289 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2290
2291 DWORD
2292 APIENTRY
2293 NtUserWaitForInputIdle( IN HANDLE hProcess,
2294 IN DWORD dwMilliseconds,
2295 IN BOOL Unknown2)
2296 {
2297 PEPROCESS Process;
2298 PPROCESSINFO W32Process;
2299 PTHREADINFO pti;
2300 NTSTATUS Status;
2301 HANDLE Handles[3];
2302 LARGE_INTEGER Timeout;
2303
2304 UserEnterExclusive();
2305
2306 Status = ObReferenceObjectByHandle(hProcess,
2307 PROCESS_QUERY_INFORMATION,
2308 PsProcessType,
2309 UserMode,
2310 (PVOID*)&Process,
2311 NULL);
2312
2313 if (!NT_SUCCESS(Status))
2314 {
2315 UserLeave();
2316 SetLastNtError(Status);
2317 return WAIT_FAILED;
2318 }
2319
2320 pti = PsGetCurrentThreadWin32Thread();
2321
2322 W32Process = (PPROCESSINFO)Process->Win32Process;
2323
2324 if ( PsGetProcessExitProcessCalled(Process) ||
2325 !W32Process ||
2326 pti->ppi == W32Process)
2327 {
2328 ObDereferenceObject(Process);
2329 UserLeave();
2330 EngSetLastError(ERROR_INVALID_PARAMETER);
2331 return WAIT_FAILED;
2332 }
2333
2334 Handles[0] = Process;
2335 Handles[1] = W32Process->InputIdleEvent;
2336 Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2337
2338 if (!Handles[1])
2339 {
2340 ObDereferenceObject(Process);
2341 UserLeave();
2342 return STATUS_SUCCESS; /* no event to wait on */
2343 }
2344
2345 if (dwMilliseconds != INFINITE)
2346 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2347
2348 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2349 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2350 {
2351 pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2352 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2353 }
2354
2355 DPRINT("WFII: ppi 0x%x\n",W32Process);
2356 DPRINT("WFII: waiting for %p\n", Handles[1] );
2357 do
2358 {
2359 UserLeave();
2360 Status = KeWaitForMultipleObjects( 3,
2361 Handles,
2362 WaitAny,
2363 UserRequest,
2364 UserMode,
2365 FALSE,
2366 dwMilliseconds == INFINITE ? NULL : &Timeout,
2367 NULL);
2368 UserEnterExclusive();
2369
2370 if (!NT_SUCCESS(Status))
2371 {
2372 SetLastNtError(Status);
2373 Status = WAIT_FAILED;
2374 goto WaitExit;
2375 }
2376
2377 switch (Status)
2378 {
2379 case STATUS_WAIT_0:
2380 goto WaitExit;
2381
2382 case STATUS_WAIT_2:
2383 {
2384 MSG Msg;
2385 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
2386 DPRINT1("WFII: WAIT 2\n");
2387 }
2388 break;
2389
2390 case STATUS_TIMEOUT:
2391 DPRINT1("WFII: timeout\n");
2392 case WAIT_FAILED:
2393 goto WaitExit;
2394
2395 default:
2396 DPRINT1("WFII: finished\n");
2397 Status = STATUS_SUCCESS;
2398 goto WaitExit;
2399 }
2400 }
2401 while (TRUE);
2402
2403 WaitExit:
2404 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2405 {
2406 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
2407 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2408 }
2409 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
2410 ObDereferenceObject(Process);
2411 UserLeave();
2412 return Status;
2413 }
2414
2415 /* EOF */