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