- Silence debug traces, SMWCB is the one to tracked.
[reactos.git] / reactos / win32ss / user / 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 USER_REFERENCE_ENTRY Ref;
598
599 if (!pWnd ||
600 pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
601 pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
602 return 0;
603
604 TRACE("Internal Event Msg %p\n",msg);
605
606 switch(msg)
607 {
608 case WM_ASYNC_SHOWWINDOW:
609 return co_WinPosShowWindow( pWnd, wparam );
610 case WM_ASYNC_SETWINDOWPOS:
611 {
612 PWINDOWPOS winpos = (PWINDOWPOS)lparam;
613 if (!winpos) return 0;
614 lRes = co_WinPosSetWindowPos( pWnd,
615 winpos->hwndInsertAfter,
616 winpos->x,
617 winpos->y,
618 winpos->cx,
619 winpos->cy,
620 winpos->flags);
621 ExFreePoolWithTag(winpos, USERTAG_SWP);
622 return lRes;
623 }
624 case WM_ASYNC_SETACTIVEWINDOW:
625 {
626 PWND Window = (PWND)wparam;
627 if (wparam) UserRefObjectCo(Window, &Ref);
628 lRes = (LRESULT)co_IntSetActiveWindow(Window,NULL,(BOOL)lparam,TRUE);
629 if (wparam) UserDerefObjectCo(Window);
630 return lRes;
631 }
632 }
633 return 0;
634 }
635
636 LRESULT FASTCALL
637 IntDispatchMessage(PMSG pMsg)
638 {
639 LARGE_INTEGER TickCount;
640 LONG Time;
641 LRESULT retval = 0;
642 PTHREADINFO pti;
643 PWND Window = NULL;
644 HRGN hrgn;
645
646 if (pMsg->hwnd)
647 {
648 Window = UserGetWindowObject(pMsg->hwnd);
649 if (!Window) return 0;
650 }
651
652 pti = PsGetCurrentThreadWin32Thread();
653
654 if ( Window && Window->head.pti != pti)
655 {
656 EngSetLastError( ERROR_MESSAGE_SYNC_ONLY );
657 return 0;
658 }
659
660 if (((pMsg->message == WM_SYSTIMER) ||
661 (pMsg->message == WM_TIMER)) &&
662 (pMsg->lParam) )
663 {
664 if (pMsg->message == WM_TIMER)
665 {
666 if (ValidateTimerCallback(pti,pMsg->lParam))
667 {
668 KeQueryTickCount(&TickCount);
669 Time = MsqCalculateMessageTime(&TickCount);
670 retval = co_IntCallWindowProc((WNDPROC)pMsg->lParam,
671 TRUE,
672 pMsg->hwnd,
673 WM_TIMER,
674 pMsg->wParam,
675 (LPARAM)Time,
676 0);
677 }
678 return retval;
679 }
680 else
681 {
682 PTIMER pTimer = FindSystemTimer(pMsg);
683 if (pTimer && pTimer->pfn)
684 {
685 KeQueryTickCount(&TickCount);
686 Time = MsqCalculateMessageTime(&TickCount);
687 pTimer->pfn(pMsg->hwnd, WM_SYSTIMER, (UINT)pMsg->wParam, Time);
688 }
689 return 0;
690 }
691 }
692 // Need a window!
693 if ( !Window ) return 0;
694
695 if (pMsg->message == WM_PAINT) Window->state |= WNDS_PAINTNOTPROCESSED;
696
697 if ( Window->state & WNDS_SERVERSIDEWINDOWPROC )
698 {
699 TRACE("Dispatch: Server Side Window Procedure\n");
700 }
701
702 /* Since we are doing a callback on the same thread right away, there is
703 no need to copy the lparam to kernel mode and then back to usermode.
704 We just pretend it isn't a pointer */
705
706 retval = co_IntCallWindowProc( Window->lpfnWndProc,
707 !Window->Unicode,
708 pMsg->hwnd,
709 pMsg->message,
710 pMsg->wParam,
711 pMsg->lParam,
712 0);
713
714 if (pMsg->message == WM_PAINT)
715 {
716 Window->state2 &= ~WNDS2_WMPAINTSENT;
717 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
718 hrgn = IntSysCreateRectRgn( 0, 0, 0, 0 );
719 co_UserGetUpdateRgn( Window, hrgn, TRUE );
720 GreDeleteObject(hrgn);
721 }
722
723 return retval;
724 }
725
726 /*
727 * Internal version of PeekMessage() doing all the work
728 */
729 BOOL FASTCALL
730 co_IntPeekMessage( PMSG Msg,
731 PWND Window,
732 UINT MsgFilterMin,
733 UINT MsgFilterMax,
734 UINT RemoveMsg,
735 BOOL bGMSG )
736 {
737 PTHREADINFO pti;
738 //PCLIENTINFO pci;
739 LARGE_INTEGER LargeTickCount;
740 PUSER_MESSAGE_QUEUE ThreadQueue;
741 BOOL RemoveMessages;
742 UINT ProcessMask;
743 BOOL Hit = FALSE;
744
745 pti = PsGetCurrentThreadWin32Thread();
746 ThreadQueue = pti->MessageQueue;
747 //pci = pti->pClientInfo;
748
749 RemoveMessages = RemoveMsg & PM_REMOVE;
750 ProcessMask = HIWORD(RemoveMsg);
751
752 /* Hint, "If wMsgFilterMin and wMsgFilterMax are both zero, PeekMessage returns
753 all available messages (that is, no range filtering is performed)". */
754 if (!ProcessMask) ProcessMask = (QS_ALLPOSTMESSAGE|QS_ALLINPUT);
755
756 IdlePong();
757
758 do
759 {
760 KeQueryTickCount(&LargeTickCount);
761 ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
762 pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart;
763
764 /* Dispatch sent messages here. */
765 while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
766 {
767 /* if some PM_QS* flags were specified, only handle sent messages from now on */
768 if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE; // wine does this; ProcessMask = QS_SENDMESSAGE;
769 }
770 if (Hit) return FALSE;
771
772 /* Clear changed bits so we can wait on them if we don't find a message */
773 if (ProcessMask & QS_POSTMESSAGE)
774 {
775 pti->pcti->fsChangeBits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER);
776 if (MsgFilterMin == 0 && MsgFilterMax == 0) // Wine hack does this; ~0U)
777 {
778 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
779 }
780 }
781
782 if (ProcessMask & QS_INPUT)
783 {
784 pti->pcti->fsChangeBits &= ~QS_INPUT;
785 }
786
787 /* Now check for normal messages. */
788 if (( (ProcessMask & QS_POSTMESSAGE) ||
789 (ProcessMask & QS_HOTKEY) ) &&
790 MsqPeekMessage( ThreadQueue,
791 RemoveMessages,
792 Window,
793 MsgFilterMin,
794 MsgFilterMax,
795 ProcessMask,
796 Msg ))
797 {
798 return TRUE;
799 }
800
801 /* Now look for a quit message. */
802 if (ThreadQueue->QuitPosted)
803 {
804 /* According to the PSDK, WM_QUIT messages are always returned, regardless
805 of the filter specified */
806 Msg->hwnd = NULL;
807 Msg->message = WM_QUIT;
808 Msg->wParam = ThreadQueue->QuitExitCode;
809 Msg->lParam = 0;
810 if (RemoveMessages)
811 {
812 ThreadQueue->QuitPosted = FALSE;
813 ClearMsgBitsMask(ThreadQueue, QS_POSTMESSAGE);
814 pti->pcti->fsWakeBits &= ~QS_ALLPOSTMESSAGE;
815 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
816 }
817 return TRUE;
818 }
819
820 /* Check for hardware events. */
821 if ((ProcessMask & QS_MOUSE) &&
822 co_MsqPeekMouseMove( ThreadQueue,
823 RemoveMessages,
824 Window,
825 MsgFilterMin,
826 MsgFilterMax,
827 Msg ))
828 {
829 return TRUE;
830 }
831
832 if ((ProcessMask & QS_INPUT) &&
833 co_MsqPeekHardwareMessage( ThreadQueue,
834 RemoveMessages,
835 Window,
836 MsgFilterMin,
837 MsgFilterMax,
838 ProcessMask,
839 Msg))
840 {
841 return TRUE;
842 }
843
844 /* Check for sent messages again. */
845 while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
846 {
847 if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE;
848 }
849 if (Hit) return FALSE;
850
851 /* Check for paint messages. */
852 if ((ProcessMask & QS_PAINT) &&
853 pti->cPaintsReady &&
854 IntGetPaintMessage( Window,
855 MsgFilterMin,
856 MsgFilterMax,
857 pti,
858 Msg,
859 RemoveMessages))
860 {
861 return TRUE;
862 }
863
864 /* This is correct, check for the current threads timers waiting to be
865 posted to this threads message queue. If any we loop again.
866 */
867 if ((ProcessMask & QS_TIMER) &&
868 PostTimerMessages(Window))
869 {
870 continue;
871 }
872
873 return FALSE;
874 }
875 while (TRUE);
876
877 return TRUE;
878 }
879
880 static BOOL FASTCALL
881 co_IntWaitMessage( PWND Window,
882 UINT MsgFilterMin,
883 UINT MsgFilterMax )
884 {
885 PTHREADINFO pti;
886 PUSER_MESSAGE_QUEUE ThreadQueue;
887 NTSTATUS Status = STATUS_SUCCESS;
888 MSG Msg;
889
890 pti = PsGetCurrentThreadWin32Thread();
891 ThreadQueue = pti->MessageQueue;
892
893 do
894 {
895 if ( co_IntPeekMessage( &Msg, // Dont reenter!
896 Window,
897 MsgFilterMin,
898 MsgFilterMax,
899 MAKELONG( PM_NOREMOVE, GetWakeMask( MsgFilterMin, MsgFilterMax)),
900 TRUE ) ) // act like GetMessage.
901 {
902 return TRUE;
903 }
904
905 /* Nothing found. Wait for new messages. */
906 Status = co_MsqWaitForNewMessages( ThreadQueue,
907 Window,
908 MsgFilterMin,
909 MsgFilterMax);
910 if (!NT_SUCCESS(Status))
911 {
912 SetLastNtError(Status);
913 ERR("Exit co_IntWaitMessage on error!\n");
914 return FALSE;
915 }
916 if (Status == STATUS_USER_APC || Status == STATUS_TIMEOUT)
917 {
918 return FALSE;
919 }
920 }
921 while ( TRUE );
922
923 return FALSE;
924 }
925
926 BOOL FASTCALL
927 co_IntGetPeekMessage( PMSG pMsg,
928 HWND hWnd,
929 UINT MsgFilterMin,
930 UINT MsgFilterMax,
931 UINT RemoveMsg,
932 BOOL bGMSG )
933 {
934 PWND Window;
935 PTHREADINFO pti;
936 BOOL Present = FALSE;
937 NTSTATUS Status;
938
939 if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST )
940 hWnd = HWND_BOTTOM;
941
942 /* Validate input */
943 if (hWnd && hWnd != HWND_BOTTOM)
944 {
945 if (!(Window = UserGetWindowObject(hWnd)))
946 {
947 if (bGMSG)
948 return -1;
949 else
950 return FALSE;
951 }
952 }
953 else
954 {
955 Window = (PWND)hWnd;
956 }
957
958 if (MsgFilterMax < MsgFilterMin)
959 {
960 MsgFilterMin = 0;
961 MsgFilterMax = 0;
962 }
963
964 if (bGMSG)
965 {
966 RemoveMsg |= ((GetWakeMask( MsgFilterMin, MsgFilterMax ))<< 16);
967 }
968
969 pti = PsGetCurrentThreadWin32Thread();
970 pti->pClientInfo->cSpins++; // Bump up the spin count.
971
972 do
973 {
974 Present = co_IntPeekMessage( pMsg,
975 Window,
976 MsgFilterMin,
977 MsgFilterMax,
978 RemoveMsg,
979 bGMSG );
980 if (Present)
981 {
982 /* GetMessage or PostMessage must never get messages that contain pointers */
983 ASSERT(FindMsgMemory(pMsg->message) == NULL);
984
985 if (pMsg->message != WM_PAINT && pMsg->message != WM_QUIT)
986 {
987 pti->timeLast = pMsg->time;
988 pti->ptLast = pMsg->pt;
989 }
990
991 // The WH_GETMESSAGE hook enables an application to monitor messages about to
992 // be returned by the GetMessage or PeekMessage function.
993
994 co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg);
995
996 if ( bGMSG ) break;
997 }
998
999 if ( bGMSG )
1000 {
1001 Status = co_MsqWaitForNewMessages( pti->MessageQueue,
1002 Window,
1003 MsgFilterMin,
1004 MsgFilterMax);
1005 if ( !NT_SUCCESS(Status) ||
1006 Status == STATUS_USER_APC ||
1007 Status == STATUS_TIMEOUT )
1008 {
1009 Present = -1;
1010 break;
1011 }
1012 }
1013 else
1014 {
1015 if (!(RemoveMsg & PM_NOYIELD))
1016 {
1017 IdlePing();
1018 // Yield this thread!
1019 UserLeave();
1020 ZwYieldExecution();
1021 UserEnterExclusive();
1022 // Fall through to exit.
1023 IdlePong();
1024 }
1025 break;
1026 }
1027 }
1028 while( bGMSG && !Present );
1029
1030 // Been spinning, time to swap vinyl...
1031 if (pti->pClientInfo->cSpins >= 100)
1032 {
1033 // Clear the spin cycle to fix the mix.
1034 pti->pClientInfo->cSpins = 0;
1035 //if (!(pti->TIF_flags & TIF_SPINNING)) // FIXME: Need to swap vinyl...
1036 }
1037 return Present;
1038 }
1039
1040 BOOL FASTCALL
1041 UserPostThreadMessage( DWORD idThread,
1042 UINT Msg,
1043 WPARAM wParam,
1044 LPARAM lParam )
1045 {
1046 MSG Message;
1047 PETHREAD peThread;
1048 PTHREADINFO pThread;
1049 LARGE_INTEGER LargeTickCount;
1050 NTSTATUS Status;
1051
1052 if (is_pointer_message(Msg))
1053 {
1054 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1055 return FALSE;
1056 }
1057
1058 Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
1059
1060 if( Status == STATUS_SUCCESS )
1061 {
1062 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
1063 if( !pThread ||
1064 !pThread->MessageQueue ||
1065 (pThread->TIF_flags & TIF_INCLEANUP))
1066 {
1067 ObDereferenceObject( peThread );
1068 return FALSE;
1069 }
1070
1071 Message.hwnd = NULL;
1072 Message.message = Msg;
1073 Message.wParam = wParam;
1074 Message.lParam = lParam;
1075 Message.pt = gpsi->ptCursor;
1076
1077 KeQueryTickCount(&LargeTickCount);
1078 Message.time = MsqCalculateMessageTime(&LargeTickCount);
1079 MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1080 ObDereferenceObject( peThread );
1081 return TRUE;
1082 }
1083 else
1084 {
1085 SetLastNtError( Status );
1086 }
1087 return FALSE;
1088 }
1089
1090 BOOL FASTCALL
1091 UserPostMessage( HWND Wnd,
1092 UINT Msg,
1093 WPARAM wParam,
1094 LPARAM lParam )
1095 {
1096 PTHREADINFO pti;
1097 MSG Message, KernelModeMsg;
1098 LARGE_INTEGER LargeTickCount;
1099
1100 Message.hwnd = Wnd;
1101 Message.message = Msg;
1102 Message.wParam = wParam;
1103 Message.lParam = lParam;
1104 Message.pt = gpsi->ptCursor;
1105 KeQueryTickCount(&LargeTickCount);
1106 Message.time = MsqCalculateMessageTime(&LargeTickCount);
1107
1108 if (is_pointer_message(Message.message))
1109 {
1110 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1111 return FALSE;
1112 }
1113
1114 if( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST )
1115 {
1116 NTSTATUS Status;
1117 PMSGMEMORY MsgMemoryEntry;
1118
1119 MsgMemoryEntry = FindMsgMemory(Message.message);
1120
1121 Status = CopyMsgToKernelMem(&KernelModeMsg, &Message, MsgMemoryEntry);
1122 if (! NT_SUCCESS(Status))
1123 {
1124 EngSetLastError(ERROR_INVALID_PARAMETER);
1125 return FALSE;
1126 }
1127 co_IntSendMessageNoWait(KernelModeMsg.hwnd,
1128 KernelModeMsg.message,
1129 KernelModeMsg.wParam,
1130 KernelModeMsg.lParam);
1131
1132 if (MsgMemoryEntry && KernelModeMsg.lParam)
1133 ExFreePool((PVOID) KernelModeMsg.lParam);
1134
1135 return TRUE;
1136 }
1137
1138 if (!Wnd)
1139 {
1140 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1141 Msg,
1142 wParam,
1143 lParam);
1144 }
1145 if (Wnd == HWND_BROADCAST)
1146 {
1147 HWND *List;
1148 PWND DesktopWindow;
1149 ULONG i;
1150
1151 DesktopWindow = UserGetDesktopWindow();
1152 List = IntWinListChildren(DesktopWindow);
1153
1154 if (List != NULL)
1155 {
1156 UserPostMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1157 for (i = 0; List[i]; i++)
1158 {
1159 PWND pwnd = UserGetWindowObject(List[i]);
1160 if (!pwnd) continue;
1161
1162 if ( pwnd->fnid == FNID_MENU || // Also need pwnd->pcls->atomClassName == gaOleMainThreadWndClass
1163 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
1164 continue;
1165
1166 UserPostMessage(List[i], Msg, wParam, lParam);
1167 }
1168 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1169 }
1170 }
1171 else
1172 {
1173 PWND Window;
1174
1175 Window = UserGetWindowObject(Wnd);
1176 if ( !Window )
1177 {
1178 return FALSE;
1179 }
1180
1181 pti = Window->head.pti;
1182 if ( pti->TIF_flags & TIF_INCLEANUP )
1183 {
1184 ERR("Attempted to post message to window 0x%x when the thread is in cleanup!\n", Wnd);
1185 return FALSE;
1186 }
1187
1188 if ( Window->state & WNDS_DESTROYED )
1189 {
1190 ERR("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1191 /* FIXME: Last error code? */
1192 return FALSE;
1193 }
1194
1195 if (WM_QUIT == Msg)
1196 {
1197 MsqPostQuitMessage(Window->head.pti->MessageQueue, wParam);
1198 }
1199 else
1200 {
1201 MsqPostMessage(Window->head.pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1202 }
1203 }
1204 return TRUE;
1205 }
1206
1207 LRESULT FASTCALL
1208 co_IntSendMessage( HWND hWnd,
1209 UINT Msg,
1210 WPARAM wParam,
1211 LPARAM lParam )
1212 {
1213 ULONG_PTR Result = 0;
1214 if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1215 {
1216 return (LRESULT)Result;
1217 }
1218 return 0;
1219 }
1220
1221 static LRESULT FASTCALL
1222 co_IntSendMessageTimeoutSingle( HWND hWnd,
1223 UINT Msg,
1224 WPARAM wParam,
1225 LPARAM lParam,
1226 UINT uFlags,
1227 UINT uTimeout,
1228 ULONG_PTR *uResult )
1229 {
1230 NTSTATUS Status;
1231 PWND Window = NULL;
1232 PMSGMEMORY MsgMemoryEntry;
1233 INT lParamBufferSize;
1234 LPARAM lParamPacked;
1235 PTHREADINFO Win32Thread;
1236 ULONG_PTR Hi, Lo, Result = 0;
1237 DECLARE_RETURN(LRESULT);
1238 USER_REFERENCE_ENTRY Ref;
1239
1240 if (!(Window = UserGetWindowObject(hWnd)))
1241 {
1242 RETURN( FALSE);
1243 }
1244
1245 UserRefObjectCo(Window, &Ref);
1246
1247 Win32Thread = PsGetCurrentThreadWin32Thread();
1248
1249 if ( Win32Thread &&
1250 Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1251 {
1252 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1253 {
1254 /* Never send messages to exiting threads */
1255 RETURN( FALSE);
1256 }
1257
1258 if (Msg & 0x80000000)
1259 {
1260 TRACE("SMTS: Internal Message!\n");
1261 Result = (ULONG_PTR)handle_internal_message( Window, Msg, wParam, lParam );
1262 if (uResult) *uResult = Result;
1263 RETURN( TRUE);
1264 }
1265
1266 // Only happens when calling the client!
1267 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1268
1269 if ( Window->state & WNDS_SERVERSIDEWINDOWPROC )
1270 {
1271 TRACE("SMT: Server Side Window Procedure\n");
1272 IoGetStackLimits(&Lo, &Hi);
1273 // Handle it here. Safeguard against excessive recursions.
1274 if (((ULONG_PTR)&uResult - Lo) < 4096 )
1275 {
1276 ERR("Server Callback Exceeded Stack!\n");
1277 RETURN( FALSE);
1278 }
1279 /* Return after server side call, IntCallWndProcRet will not be called. */
1280 }
1281 /* See if this message type is present in the table */
1282 MsgMemoryEntry = FindMsgMemory(Msg);
1283 if (NULL == MsgMemoryEntry)
1284 {
1285 lParamBufferSize = -1;
1286 }
1287 else
1288 {
1289 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1290 }
1291
1292 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
1293 {
1294 ERR("Failed to pack message parameters\n");
1295 RETURN( FALSE);
1296 }
1297
1298 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1299 !Window->Unicode,
1300 hWnd,
1301 Msg,
1302 wParam,
1303 lParamPacked,
1304 lParamBufferSize );
1305 if(uResult)
1306 {
1307 *uResult = Result;
1308 }
1309
1310 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1311 {
1312 ERR("Failed to unpack message parameters\n");
1313 RETURN( TRUE);
1314 }
1315
1316 // Only happens when calling the client!
1317 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1318
1319 RETURN( TRUE);
1320 }
1321
1322 if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->head.pti->MessageQueue))
1323 {
1324 // FIXME: Set window hung and add to a list.
1325 /* FIXME: Set a LastError? */
1326 RETURN( FALSE);
1327 }
1328
1329 if (Window->state & WNDS_DESTROYED)
1330 {
1331 /* FIXME: Last error? */
1332 ERR("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1333 RETURN( FALSE);
1334 }
1335
1336 do
1337 {
1338 Status = co_MsqSendMessage( Window->head.pti->MessageQueue,
1339 hWnd,
1340 Msg,
1341 wParam,
1342 lParam,
1343 uTimeout,
1344 (uFlags & SMTO_BLOCK),
1345 MSQ_NORMAL,
1346 uResult );
1347 }
1348 while ((STATUS_TIMEOUT == Status) &&
1349 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1350 !MsqIsHung(Window->head.pti->MessageQueue)); // FIXME: Set window hung and add to a list.
1351
1352 if (STATUS_TIMEOUT == Status)
1353 {
1354 /*
1355 * MSDN says:
1356 * Microsoft Windows 2000: If GetLastError returns zero, then the function
1357 * timed out.
1358 * XP+ : If the function fails or times out, the return value is zero.
1359 * To get extended error information, call GetLastError. If GetLastError
1360 * returns ERROR_TIMEOUT, then the function timed out.
1361 */
1362 EngSetLastError(ERROR_TIMEOUT);
1363 RETURN( FALSE);
1364 }
1365 else if (!NT_SUCCESS(Status))
1366 {
1367 SetLastNtError(Status);
1368 RETURN( FALSE);
1369 }
1370
1371 RETURN( TRUE);
1372
1373 CLEANUP:
1374 if (Window) UserDerefObjectCo(Window);
1375 END_CLEANUP;
1376 }
1377
1378 LRESULT FASTCALL
1379 co_IntSendMessageTimeout( HWND hWnd,
1380 UINT Msg,
1381 WPARAM wParam,
1382 LPARAM lParam,
1383 UINT uFlags,
1384 UINT uTimeout,
1385 ULONG_PTR *uResult )
1386 {
1387 PWND DesktopWindow;
1388 HWND *Children;
1389 HWND *Child;
1390
1391 if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST)
1392 {
1393 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1394 }
1395
1396 DesktopWindow = UserGetDesktopWindow();
1397 if (NULL == DesktopWindow)
1398 {
1399 EngSetLastError(ERROR_INTERNAL_ERROR);
1400 return 0;
1401 }
1402
1403 if (hWnd != HWND_TOPMOST)
1404 {
1405 /* Send message to the desktop window too! */
1406 co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1407 }
1408
1409 Children = IntWinListChildren(DesktopWindow);
1410 if (NULL == Children)
1411 {
1412 return 0;
1413 }
1414
1415 for (Child = Children; NULL != *Child; Child++)
1416 {
1417 if (hWnd == HWND_TOPMOST)
1418 {
1419 DesktopWindow = UserGetWindowObject(*Child);
1420 if (DesktopWindow && DesktopWindow->ExStyle & WS_EX_TOPMOST)
1421 {
1422 ERR("HWND_TOPMOST Found\n");
1423 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1424 }
1425 }
1426 else
1427 {
1428 PWND pwnd = UserGetWindowObject(*Child);
1429 if (!pwnd) continue;
1430
1431 if ( pwnd->fnid == FNID_MENU ||
1432 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
1433 continue;
1434
1435 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1436 }
1437 }
1438
1439 ExFreePool(Children);
1440
1441 return (LRESULT) TRUE;
1442 }
1443
1444 LRESULT FASTCALL
1445 co_IntSendMessageNoWait(HWND hWnd,
1446 UINT Msg,
1447 WPARAM wParam,
1448 LPARAM lParam)
1449 {
1450 ULONG_PTR Result = 0;
1451 return co_IntSendMessageWithCallBack( hWnd,
1452 Msg,
1453 wParam,
1454 lParam,
1455 NULL,
1456 0,
1457 &Result);
1458 }
1459 /* MSDN:
1460 If you send a message in the range below WM_USER to the asynchronous message
1461 functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its
1462 message parameters cannot include pointers. Otherwise, the operation will fail.
1463 The functions will return before the receiving thread has had a chance to
1464 process the message and the sender will free the memory before it is used.
1465 */
1466 LRESULT FASTCALL
1467 co_IntSendMessageWithCallBack( HWND hWnd,
1468 UINT Msg,
1469 WPARAM wParam,
1470 LPARAM lParam,
1471 SENDASYNCPROC CompletionCallback,
1472 ULONG_PTR CompletionCallbackContext,
1473 ULONG_PTR *uResult)
1474 {
1475 ULONG_PTR Result;
1476 PWND Window = NULL;
1477 PMSGMEMORY MsgMemoryEntry;
1478 INT lParamBufferSize;
1479 LPARAM lParamPacked;
1480 PTHREADINFO Win32Thread;
1481 DECLARE_RETURN(LRESULT);
1482 USER_REFERENCE_ENTRY Ref;
1483 PUSER_SENT_MESSAGE Message;
1484
1485 if (!(Window = UserGetWindowObject(hWnd)))
1486 {
1487 RETURN(FALSE);
1488 }
1489
1490 UserRefObjectCo(Window, &Ref);
1491
1492 if (Window->state & WNDS_DESTROYED)
1493 {
1494 /* FIXME: last error? */
1495 ERR("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1496 RETURN(FALSE);
1497 }
1498
1499 Win32Thread = PsGetCurrentThreadWin32Thread();
1500
1501 if (Win32Thread == NULL ||
1502 Win32Thread->TIF_flags & TIF_INCLEANUP)
1503 {
1504 RETURN(FALSE);
1505 }
1506
1507 if (Msg & 0x80000000 &&
1508 Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1509 {
1510 ERR("SMWCB: Internal Message!\n");
1511 Result = (ULONG_PTR)handle_internal_message( Window, Msg, wParam, lParam );
1512 if (uResult) *uResult = Result;
1513 RETURN( TRUE);
1514 }
1515
1516 /* See if this message type is present in the table */
1517 MsgMemoryEntry = FindMsgMemory(Msg);
1518 if (NULL == MsgMemoryEntry)
1519 {
1520 lParamBufferSize = -1;
1521 }
1522 else
1523 {
1524 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1525 }
1526
1527 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, Window->head.pti->MessageQueue != Win32Thread->MessageQueue)))
1528 {
1529 ERR("Failed to pack message parameters\n");
1530 RETURN( FALSE);
1531 }
1532
1533 /* If it can be sent now, then send it. */
1534 if (Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1535 {
1536 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1537 {
1538 UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE);
1539 /* Never send messages to exiting threads */
1540 RETURN(FALSE);
1541 }
1542
1543 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1544
1545 if ( Window->state & WNDS_SERVERSIDEWINDOWPROC )
1546 {
1547 TRACE("SMWCB: Server Side Window Procedure\n");
1548 }
1549
1550 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1551 !Window->Unicode,
1552 hWnd,
1553 Msg,
1554 wParam,
1555 lParamPacked,
1556 lParamBufferSize );
1557 if(uResult)
1558 {
1559 *uResult = Result;
1560 }
1561
1562 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1563
1564 if (CompletionCallback)
1565 {
1566 co_IntCallSentMessageCallback(CompletionCallback,
1567 hWnd,
1568 Msg,
1569 CompletionCallbackContext,
1570 Result);
1571 }
1572 }
1573
1574 if (Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1575 {
1576 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1577 {
1578 ERR("Failed to unpack message parameters\n");
1579 }
1580 RETURN(TRUE);
1581 }
1582
1583 if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
1584 {
1585 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1586 RETURN( FALSE);
1587 }
1588
1589 IntReferenceMessageQueue(Window->head.pti->MessageQueue);
1590 /* Take reference on this MessageQueue if its a callback. It will be released
1591 when message is processed or removed from target hwnd MessageQueue */
1592 if (CompletionCallback)
1593 IntReferenceMessageQueue(Win32Thread->MessageQueue);
1594
1595 Message->Msg.hwnd = hWnd;
1596 Message->Msg.message = Msg;
1597 Message->Msg.wParam = wParam;
1598 Message->Msg.lParam = lParamPacked;
1599 Message->CompletionEvent = NULL;
1600 Message->Result = 0;
1601 Message->lResult = 0;
1602 Message->QS_Flags = 0;
1603 Message->SenderQueue = NULL; // mjmartin, you are right! This is null.
1604 Message->CallBackSenderQueue = Win32Thread->MessageQueue;
1605 Message->DispatchingListEntry.Flink = NULL;
1606 Message->CompletionCallback = CompletionCallback;
1607 Message->CompletionCallbackContext = CompletionCallbackContext;
1608 Message->HookMessage = MSQ_NORMAL;
1609 Message->HasPackedLParam = (lParamBufferSize > 0);
1610 Message->QS_Flags = QS_SENDMESSAGE;
1611
1612 InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
1613 MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, TRUE);
1614 IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
1615
1616 RETURN(TRUE);
1617
1618 CLEANUP:
1619 if (Window) UserDerefObjectCo(Window);
1620 END_CLEANUP;
1621 }
1622
1623
1624 /*
1625 This HACK function posts a message if the destination's message queue belongs to
1626 another thread, otherwise it sends the message. It does not support broadcast
1627 messages!
1628 */
1629 LRESULT FASTCALL
1630 co_IntPostOrSendMessage( HWND hWnd,
1631 UINT Msg,
1632 WPARAM wParam,
1633 LPARAM lParam )
1634 {
1635 ULONG_PTR Result;
1636 PTHREADINFO pti;
1637 PWND Window;
1638
1639 if ( hWnd == HWND_BROADCAST )
1640 {
1641 return 0;
1642 }
1643
1644 if(!(Window = UserGetWindowObject(hWnd)))
1645 {
1646 return 0;
1647 }
1648
1649 pti = PsGetCurrentThreadWin32Thread();
1650
1651 if ( Window->head.pti->MessageQueue != pti->MessageQueue &&
1652 FindMsgMemory(Msg) == 0 )
1653 {
1654 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1655 }
1656 else
1657 {
1658 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1659 {
1660 Result = 0;
1661 }
1662 }
1663
1664 return (LRESULT)Result;
1665 }
1666
1667 LRESULT FASTCALL
1668 co_IntDoSendMessage( HWND hWnd,
1669 UINT Msg,
1670 WPARAM wParam,
1671 LPARAM lParam,
1672 PDOSENDMESSAGE dsm)
1673 {
1674 //PTHREADINFO pti;
1675 LRESULT Result = TRUE;
1676 NTSTATUS Status;
1677 PWND Window = NULL;
1678 MSG UserModeMsg;
1679 MSG KernelModeMsg;
1680 PMSGMEMORY MsgMemoryEntry;
1681
1682 if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST)
1683 {
1684 Window = UserGetWindowObject(hWnd);
1685 if ( !Window )
1686 {
1687 return 0;
1688 }
1689 }
1690
1691 /* Check for an exiting window. */
1692 if (Window && Window->state & WNDS_DESTROYED)
1693 {
1694 ERR("co_IntDoSendMessage Window Exiting!\n");
1695 }
1696
1697 /* See if the current thread can handle the message */
1698 //pti = PsGetCurrentThreadWin32Thread();
1699
1700 UserModeMsg.hwnd = hWnd;
1701 UserModeMsg.message = Msg;
1702 UserModeMsg.wParam = wParam;
1703 UserModeMsg.lParam = lParam;
1704 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1705
1706 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1707 if (! NT_SUCCESS(Status))
1708 {
1709 EngSetLastError(ERROR_INVALID_PARAMETER);
1710 return (dsm ? 0 : -1);
1711 }
1712
1713 if (!dsm)
1714 {
1715 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1716 KernelModeMsg.message,
1717 KernelModeMsg.wParam,
1718 KernelModeMsg.lParam );
1719 }
1720 else
1721 {
1722 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1723 KernelModeMsg.message,
1724 KernelModeMsg.wParam,
1725 KernelModeMsg.lParam,
1726 dsm->uFlags,
1727 dsm->uTimeout,
1728 &dsm->Result );
1729 }
1730
1731 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1732 if (! NT_SUCCESS(Status))
1733 {
1734 EngSetLastError(ERROR_INVALID_PARAMETER);
1735 return(dsm ? 0 : -1);
1736 }
1737
1738 return (LRESULT)Result;
1739 }
1740
1741 BOOL FASTCALL
1742 UserSendNotifyMessage( HWND hWnd,
1743 UINT Msg,
1744 WPARAM wParam,
1745 LPARAM lParam )
1746 {
1747 BOOL Ret = TRUE;
1748
1749 if (is_pointer_message(Msg))
1750 {
1751 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1752 return FALSE;
1753 }
1754
1755 // Basicly the same as IntPostOrSendMessage
1756 if (hWnd == HWND_BROADCAST) // Handle Broadcast
1757 {
1758 HWND *List;
1759 PWND DesktopWindow;
1760 ULONG i;
1761
1762 DesktopWindow = UserGetDesktopWindow();
1763 List = IntWinListChildren(DesktopWindow);
1764
1765 if (List != NULL)
1766 {
1767 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1768 for (i = 0; List[i]; i++)
1769 {
1770 PWND pwnd = UserGetWindowObject(List[i]);
1771 if (!pwnd) continue;
1772
1773 if ( pwnd->fnid == FNID_MENU ||
1774 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
1775 continue;
1776
1777 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1778 }
1779 ExFreePool(List);
1780 }
1781 }
1782 else
1783 {
1784 Ret = co_IntSendMessageNoWait( hWnd, Msg, wParam, lParam);
1785 }
1786 return Ret;
1787 }
1788
1789
1790 DWORD APIENTRY
1791 IntGetQueueStatus(DWORD Changes)
1792 {
1793 PTHREADINFO pti;
1794 //PUSER_MESSAGE_QUEUE Queue;
1795 DWORD Result;
1796
1797 pti = PsGetCurrentThreadWin32Thread();
1798 //Queue = pti->MessageQueue;
1799 // wine:
1800 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1801
1802 /* High word, types of messages currently in the queue.
1803 Low word, types of messages that have been added to the queue and that
1804 are still in the queue
1805 */
1806 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
1807
1808 pti->pcti->fsChangeBits &= ~Changes;
1809
1810 return Result;
1811 }
1812
1813 BOOL APIENTRY
1814 IntInitMessagePumpHook()
1815 {
1816 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1817
1818 if (pti->pcti)
1819 {
1820 pti->pcti->dwcPumpHook++;
1821 return TRUE;
1822 }
1823 return FALSE;
1824 }
1825
1826 BOOL APIENTRY
1827 IntUninitMessagePumpHook()
1828 {
1829 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1830
1831 if (pti->pcti)
1832 {
1833 if (pti->pcti->dwcPumpHook <= 0)
1834 {
1835 return FALSE;
1836 }
1837 pti->pcti->dwcPumpHook--;
1838 return TRUE;
1839 }
1840 return FALSE;
1841 }
1842
1843 /** Functions ******************************************************************/
1844
1845 BOOL
1846 APIENTRY
1847 NtUserDragDetect(
1848 HWND hWnd,
1849 POINT pt) // Just like the User call.
1850 {
1851 MSG msg;
1852 RECT rect;
1853 ULONG wDragWidth, wDragHeight;
1854 DECLARE_RETURN(BOOL);
1855
1856 TRACE("Enter NtUserDragDetect(%x)\n", hWnd);
1857 UserEnterExclusive();
1858
1859 wDragWidth = UserGetSystemMetrics(SM_CXDRAG);
1860 wDragHeight= UserGetSystemMetrics(SM_CYDRAG);
1861
1862 rect.left = pt.x - wDragWidth;
1863 rect.right = pt.x + wDragWidth;
1864
1865 rect.top = pt.y - wDragHeight;
1866 rect.bottom = pt.y + wDragHeight;
1867
1868 co_UserSetCapture(hWnd);
1869
1870 for (;;)
1871 {
1872 while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) ||
1873 co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC, WM_QUEUESYNC, PM_REMOVE, FALSE ) ||
1874 co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE, FALSE ) )
1875 {
1876 if ( msg.message == WM_LBUTTONUP )
1877 {
1878 co_UserSetCapture(NULL);
1879 RETURN( FALSE);
1880 }
1881 if ( msg.message == WM_MOUSEMOVE )
1882 {
1883 POINT tmp;
1884 tmp.x = (short)LOWORD(msg.lParam);
1885 tmp.y = (short)HIWORD(msg.lParam);
1886 if( !RECTL_bPointInRect( &rect, tmp.x, tmp.y ) )
1887 {
1888 co_UserSetCapture(NULL);
1889 RETURN( TRUE);
1890 }
1891 }
1892 if ( msg.message == WM_KEYDOWN )
1893 {
1894 if ( msg.wParam == VK_ESCAPE )
1895 {
1896 co_UserSetCapture(NULL);
1897 RETURN( TRUE);
1898 }
1899 }
1900 if ( msg.message == WM_QUEUESYNC )
1901 {
1902 co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 );
1903 }
1904 }
1905 co_IntWaitMessage(NULL, 0, 0);
1906 }
1907 RETURN( FALSE);
1908
1909 CLEANUP:
1910 TRACE("Leave NtUserDragDetect, ret=%i\n",_ret_);
1911 UserLeave();
1912 END_CLEANUP;
1913 }
1914
1915 BOOL APIENTRY
1916 NtUserPostMessage(HWND hWnd,
1917 UINT Msg,
1918 WPARAM wParam,
1919 LPARAM lParam)
1920 {
1921 BOOL ret;
1922
1923 UserEnterExclusive();
1924
1925 ret = UserPostMessage(hWnd, Msg, wParam, lParam);
1926
1927 UserLeave();
1928
1929 return ret;
1930 }
1931
1932 BOOL APIENTRY
1933 NtUserPostThreadMessage(DWORD idThread,
1934 UINT Msg,
1935 WPARAM wParam,
1936 LPARAM lParam)
1937 {
1938 BOOL ret;
1939
1940 UserEnterExclusive();
1941
1942 ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
1943
1944 UserLeave();
1945
1946 return ret;
1947 }
1948
1949 BOOL APIENTRY
1950 NtUserWaitMessage(VOID)
1951 {
1952 BOOL ret;
1953
1954 UserEnterExclusive();
1955 TRACE("NtUserWaitMessage Enter\n");
1956 ret = co_IntWaitMessage(NULL, 0, 0);
1957 TRACE("NtUserWaitMessage Leave\n");
1958 UserLeave();
1959
1960 return ret;
1961 }
1962
1963 BOOL APIENTRY
1964 NtUserGetMessage(PMSG pMsg,
1965 HWND hWnd,
1966 UINT MsgFilterMin,
1967 UINT MsgFilterMax )
1968 {
1969 MSG Msg;
1970 BOOL Ret;
1971
1972 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
1973 {
1974 EngSetLastError(ERROR_INVALID_PARAMETER);
1975 return FALSE;
1976 }
1977
1978 UserEnterExclusive();
1979
1980 RtlZeroMemory(&Msg, sizeof(MSG));
1981
1982 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
1983
1984 UserLeave();
1985
1986 if (Ret == TRUE)
1987 {
1988 _SEH2_TRY
1989 {
1990 ProbeForWrite(pMsg, sizeof(MSG), 1);
1991 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1992 }
1993 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1994 {
1995 SetLastNtError(_SEH2_GetExceptionCode());
1996 Ret = FALSE;
1997 }
1998 _SEH2_END;
1999 }
2000
2001 if ((INT)Ret != -1)
2002 Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE;
2003
2004 return Ret;
2005 }
2006
2007 BOOL APIENTRY
2008 NtUserPeekMessage( PMSG pMsg,
2009 HWND hWnd,
2010 UINT MsgFilterMin,
2011 UINT MsgFilterMax,
2012 UINT RemoveMsg)
2013 {
2014 MSG Msg;
2015 BOOL Ret;
2016
2017 if ( RemoveMsg & PM_BADMSGFLAGS )
2018 {
2019 EngSetLastError(ERROR_INVALID_FLAGS);
2020 return FALSE;
2021 }
2022
2023 UserEnterExclusive();
2024
2025 RtlZeroMemory(&Msg, sizeof(MSG));
2026
2027 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
2028
2029 UserLeave();
2030
2031 if (Ret)
2032 {
2033 _SEH2_TRY
2034 {
2035 ProbeForWrite(pMsg, sizeof(MSG), 1);
2036 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2037 }
2038 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2039 {
2040 SetLastNtError(_SEH2_GetExceptionCode());
2041 Ret = FALSE;
2042 }
2043 _SEH2_END;
2044 }
2045
2046 return Ret;
2047 }
2048
2049 BOOL APIENTRY
2050 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
2051 {
2052 BOOL Ret = FALSE;
2053 MSG Msg;
2054
2055 _SEH2_TRY
2056 {
2057 ProbeForRead(lpmsg, sizeof(MSG), 1);
2058 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
2059 }
2060 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2061 {
2062 _SEH2_YIELD(return FALSE);
2063 }
2064 _SEH2_END;
2065
2066 UserEnterExclusive();
2067
2068 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
2069 {
2070 Ret = TRUE;
2071 }
2072 else
2073 {
2074 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
2075 }
2076
2077 UserLeave();
2078
2079 _SEH2_TRY
2080 {
2081 ProbeForWrite(lpmsg, sizeof(MSG), 1);
2082 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
2083 }
2084 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2085 {
2086 Ret = FALSE;
2087 }
2088 _SEH2_END;
2089
2090 return Ret;
2091 }
2092
2093 LRESULT APIENTRY
2094 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
2095 {
2096 LRESULT Res = 0;
2097 MSG SafeMsg;
2098
2099 _SEH2_TRY
2100 {
2101 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
2102 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
2103 }
2104 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2105 {
2106 SetLastNtError(_SEH2_GetExceptionCode());
2107 _SEH2_YIELD(return FALSE);
2108 }
2109 _SEH2_END;
2110
2111 UserEnterExclusive();
2112
2113 Res = IntDispatchMessage(&SafeMsg);
2114
2115 UserLeave();
2116 return Res;
2117 }
2118
2119
2120 BOOL APIENTRY
2121 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
2122 {
2123 MSG SafeMsg;
2124 BOOL Ret;
2125
2126 _SEH2_TRY
2127 {
2128 ProbeForRead(lpMsg, sizeof(MSG), 1);
2129 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
2130 }
2131 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2132 {
2133 SetLastNtError(_SEH2_GetExceptionCode());
2134 _SEH2_YIELD(return FALSE);
2135 }
2136 _SEH2_END;
2137
2138 UserEnterExclusive();
2139
2140 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
2141
2142 UserLeave();
2143
2144 return Ret;
2145 }
2146
2147 BOOL APIENTRY
2148 NtUserMessageCall( HWND hWnd,
2149 UINT Msg,
2150 WPARAM wParam,
2151 LPARAM lParam,
2152 ULONG_PTR ResultInfo,
2153 DWORD dwType, // fnID?
2154 BOOL Ansi)
2155 {
2156 LRESULT lResult = 0;
2157 BOOL Ret = FALSE;
2158 PWND Window = NULL;
2159 USER_REFERENCE_ENTRY Ref;
2160
2161 UserEnterExclusive();
2162
2163 switch(dwType)
2164 {
2165 case FNID_SCROLLBAR:
2166 {
2167 switch(Msg)
2168 {
2169 case WM_ENABLE:
2170 {
2171 Window = UserGetWindowObject(hWnd);
2172 if (Window->pSBInfo)
2173 {
2174 Window->pSBInfo->WSBflags = wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
2175 }
2176 }
2177 break;
2178 }
2179 break;
2180 }
2181 case FNID_DEFWINDOWPROC:
2182 /* Validate input */
2183 if (hWnd)
2184 {
2185 Window = UserGetWindowObject(hWnd);
2186 if (!Window)
2187 {
2188 UserLeave();
2189 return FALSE;
2190 }
2191 UserRefObjectCo(Window, &Ref);
2192 }
2193 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2194 Ret = TRUE;
2195 if (hWnd)
2196 UserDerefObjectCo(Window);
2197 break;
2198 case FNID_SENDNOTIFYMESSAGE:
2199 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2200 break;
2201 case FNID_BROADCASTSYSTEMMESSAGE:
2202 {
2203 BROADCASTPARM parm, *retparam;
2204 DWORD_PTR RetVal = 0;
2205
2206 if (ResultInfo)
2207 {
2208 _SEH2_TRY
2209 {
2210 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
2211 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2212 }
2213 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2214 {
2215 _SEH2_YIELD(break);
2216 }
2217 _SEH2_END;
2218 }
2219 else
2220 break;
2221
2222 if ( parm.recipients & BSM_ALLDESKTOPS ||
2223 parm.recipients == BSM_ALLCOMPONENTS )
2224 {
2225 PLIST_ENTRY DesktopEntry;
2226 PDESKTOP rpdesk;
2227 HWND *List, hwndDenied = NULL;
2228 HDESK hDesk = NULL;
2229 PWND pwnd, pwndDesk;
2230 ULONG i;
2231 UINT fuFlags;
2232
2233 for (DesktopEntry = InputWindowStation->DesktopListHead.Flink;
2234 DesktopEntry != &InputWindowStation->DesktopListHead;
2235 DesktopEntry = DesktopEntry->Flink)
2236 {
2237 rpdesk = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
2238 pwndDesk = rpdesk->pDeskInfo->spwnd;
2239 List = IntWinListChildren(pwndDesk);
2240
2241 if (parm.flags & BSF_QUERY)
2242 {
2243 if (List != NULL)
2244 {
2245 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2246 {
2247 fuFlags = SMTO_ABORTIFHUNG;
2248 }
2249 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2250 {
2251 fuFlags = SMTO_NOTIMEOUTIFNOTHUNG;
2252 }
2253 else
2254 {
2255 fuFlags = SMTO_NORMAL;
2256 }
2257 co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk),
2258 Msg,
2259 wParam,
2260 lParam,
2261 fuFlags,
2262 2000,
2263 &RetVal);
2264 Ret = TRUE;
2265 for (i = 0; List[i]; i++)
2266 {
2267 pwnd = UserGetWindowObject(List[i]);
2268 if (!pwnd) continue;
2269
2270 if ( pwnd->fnid == FNID_MENU ||
2271 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2272 continue;
2273
2274 if ( parm.flags & BSF_IGNORECURRENTTASK )
2275 {
2276 if ( pwnd->head.pti->MessageQueue == gptiCurrent->MessageQueue )
2277 continue;
2278 }
2279 co_IntSendMessageTimeout( List[i],
2280 Msg,
2281 wParam,
2282 lParam,
2283 fuFlags,
2284 2000,
2285 &RetVal);
2286
2287 if (!RetVal && EngGetLastError() == ERROR_TIMEOUT)
2288 {
2289 if (!(parm.flags & BSF_FORCEIFHUNG))
2290 Ret = FALSE;
2291 }
2292 if (RetVal == BROADCAST_QUERY_DENY)
2293 {
2294 hwndDenied = List[i];
2295 hDesk = UserHMGetHandle(pwndDesk);
2296 Ret = FALSE;
2297 }
2298 }
2299 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2300 _SEH2_TRY
2301 {
2302 retparam = (PBROADCASTPARM) ResultInfo;
2303 retparam->hDesk = hDesk;
2304 retparam->hWnd = hwndDenied;
2305 }
2306 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2307 {
2308 _SEH2_YIELD(break);
2309 }
2310 _SEH2_END;
2311 if (!Ret) break; // Have a hit! Let everyone know!
2312 }
2313 }
2314 else if (parm.flags & BSF_POSTMESSAGE)
2315 {
2316 if (List != NULL)
2317 {
2318 UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2319
2320 for (i = 0; List[i]; i++)
2321 {
2322 pwnd = UserGetWindowObject(List[i]);
2323 if (!pwnd) continue;
2324
2325 if ( pwnd->fnid == FNID_MENU ||
2326 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2327 continue;
2328
2329 if ( parm.flags & BSF_IGNORECURRENTTASK )
2330 {
2331 if ( pwnd->head.pti->MessageQueue == gptiCurrent->MessageQueue )
2332 continue;
2333 }
2334 UserPostMessage(List[i], Msg, wParam, lParam);
2335 }
2336 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2337 }
2338 Ret = TRUE;
2339 }
2340 else
2341 {
2342 if (List != NULL)
2343 {
2344 UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2345
2346 for (i = 0; List[i]; i++)
2347 {
2348 pwnd = UserGetWindowObject(List[i]);
2349 if (!pwnd) continue;
2350
2351 if ( pwnd->fnid == FNID_MENU ||
2352 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2353 continue;
2354
2355 if ( parm.flags & BSF_IGNORECURRENTTASK )
2356 {
2357 if ( pwnd->head.pti->MessageQueue == gptiCurrent->MessageQueue )
2358 continue;
2359 }
2360 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
2361 }
2362 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2363 }
2364 Ret = TRUE;
2365 }
2366 }
2367 }
2368 else if (parm.recipients & BSM_APPLICATIONS)
2369 {
2370 HWND *List, hwndDenied = NULL;
2371 HDESK hDesk = NULL;
2372 PWND pwnd, pwndDesk;
2373 ULONG i;
2374 UINT fuFlags;
2375
2376 pwndDesk = UserGetDesktopWindow();
2377 List = IntWinListChildren(pwndDesk);
2378
2379 if (parm.flags & BSF_QUERY)
2380 {
2381 if (List != NULL)
2382 {
2383 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2384 {
2385 fuFlags = SMTO_ABORTIFHUNG;
2386 }
2387 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2388 {
2389 fuFlags = SMTO_NOTIMEOUTIFNOTHUNG;
2390 }
2391 else
2392 {
2393 fuFlags = SMTO_NORMAL;
2394 }
2395 co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk),
2396 Msg,
2397 wParam,
2398 lParam,
2399 fuFlags,
2400 2000,
2401 &RetVal);
2402 Ret = TRUE;
2403 for (i = 0; List[i]; i++)
2404 {
2405 pwnd = UserGetWindowObject(List[i]);
2406 if (!pwnd) continue;
2407
2408 if ( pwnd->fnid == FNID_MENU ||
2409 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2410 continue;
2411
2412 if ( parm.flags & BSF_IGNORECURRENTTASK )
2413 {
2414 if ( pwnd->head.pti->MessageQueue == gptiCurrent->MessageQueue )
2415 continue;
2416 }
2417 co_IntSendMessageTimeout( List[i],
2418 Msg,
2419 wParam,
2420 lParam,
2421 fuFlags,
2422 2000,
2423 &RetVal);
2424
2425 if (!RetVal && EngGetLastError() == ERROR_TIMEOUT)
2426 {
2427 if (!(parm.flags & BSF_FORCEIFHUNG))
2428 Ret = FALSE;
2429 }
2430 if (RetVal == BROADCAST_QUERY_DENY)
2431 {
2432 hwndDenied = List[i];
2433 hDesk = UserHMGetHandle(pwndDesk);
2434 Ret = FALSE;
2435 }
2436 }
2437 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2438 _SEH2_TRY
2439 {
2440 retparam = (PBROADCASTPARM) ResultInfo;
2441 retparam->hDesk = hDesk;
2442 retparam->hWnd = hwndDenied;
2443 }
2444 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2445 {
2446 _SEH2_YIELD(break);
2447 }
2448 _SEH2_END;
2449 }
2450 }
2451 else if (parm.flags & BSF_POSTMESSAGE)
2452 {
2453 if (List != NULL)
2454 {
2455 UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2456
2457 for (i = 0; List[i]; i++)
2458 {
2459 pwnd = UserGetWindowObject(List[i]);
2460 if (!pwnd) continue;
2461
2462 if ( pwnd->fnid == FNID_MENU ||
2463 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2464 continue;
2465
2466 if ( parm.flags & BSF_IGNORECURRENTTASK )
2467 {
2468 if ( pwnd->head.pti->MessageQueue == gptiCurrent->MessageQueue )
2469 continue;
2470 }
2471 UserPostMessage(List[i], Msg, wParam, lParam);
2472 }
2473 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2474 }
2475 Ret = TRUE;
2476 }
2477 else
2478 {
2479 if (List != NULL)
2480 {
2481 UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2482
2483 for (i = 0; List[i]; i++)
2484 {
2485 pwnd = UserGetWindowObject(List[i]);
2486 if (!pwnd) continue;
2487
2488 if ( pwnd->fnid == FNID_MENU ||
2489 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2490 continue;
2491
2492 if ( parm.flags & BSF_IGNORECURRENTTASK )
2493 {
2494 if ( pwnd->head.pti->MessageQueue == gptiCurrent->MessageQueue )
2495 continue;
2496 }
2497 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
2498 }
2499 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2500 }
2501 Ret = TRUE;
2502 }
2503 }
2504 }
2505 break;
2506 case FNID_SENDMESSAGECALLBACK:
2507 {
2508 CALL_BACK_INFO CallBackInfo;
2509 ULONG_PTR uResult;
2510
2511 _SEH2_TRY
2512 {
2513 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
2514 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
2515 }
2516 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2517 {
2518 _SEH2_YIELD(break);
2519 }
2520 _SEH2_END;
2521
2522 if (is_pointer_message(Msg))
2523 {
2524 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
2525 break;
2526 }
2527
2528 if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2529 CallBackInfo.CallBack, CallBackInfo.Context, &uResult)))
2530 {
2531 ERR("Callback failure!\n");
2532 }
2533 }
2534 break;
2535 case FNID_SENDMESSAGE:
2536 {
2537 Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
2538
2539 if (ResultInfo)
2540 {
2541 _SEH2_TRY
2542 {
2543 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
2544 RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
2545 }
2546 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2547 {
2548 Ret = FALSE;
2549 _SEH2_YIELD(break);
2550 }
2551 _SEH2_END;
2552 }
2553 break;
2554 }
2555 case FNID_SENDMESSAGEFF:
2556 case FNID_SENDMESSAGEWTOOPTION:
2557 {
2558 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
2559 if (ResultInfo)
2560 {
2561 _SEH2_TRY
2562 {
2563 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
2564 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
2565 }
2566 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2567 {
2568 _SEH2_YIELD(break);
2569 }
2570 _SEH2_END;
2571 }
2572
2573 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
2574
2575 if (pdsm)
2576 {
2577 _SEH2_TRY
2578 {
2579 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
2580 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2581 }
2582 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2583 {
2584 Ret = FALSE;
2585 _SEH2_YIELD(break);
2586 }
2587 _SEH2_END;
2588 }
2589 break;
2590 }
2591 // CallNextHook bypass.
2592 case FNID_CALLWNDPROC:
2593 case FNID_CALLWNDPROCRET:
2594 {
2595 PTHREADINFO pti;
2596 PCLIENTINFO ClientInfo;
2597 PHOOK NextObj, Hook;
2598
2599 pti = GetW32ThreadInfo();
2600
2601 Hook = pti->sphkCurrent;
2602
2603 if (!Hook) break;
2604
2605 NextObj = Hook->phkNext;
2606 ClientInfo = pti->pClientInfo;
2607 _SEH2_TRY
2608 {
2609 ClientInfo->phkCurrent = NextObj;
2610 }
2611 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2612 {
2613 ClientInfo = NULL;
2614 }
2615 _SEH2_END;
2616
2617 if (!ClientInfo || !NextObj) break;
2618
2619 NextObj->phkNext = IntGetNextHook(NextObj);
2620
2621 if ( Hook->HookId == WH_CALLWNDPROC)
2622 {
2623 CWPSTRUCT CWP;
2624 CWP.hwnd = hWnd;
2625 CWP.message = Msg;
2626 CWP.wParam = wParam;
2627 CWP.lParam = lParam;
2628 TRACE("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2629
2630 lResult = co_IntCallHookProc( Hook->HookId,
2631 HC_ACTION,
2632 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2633 (LPARAM)&CWP,
2634 Hook->Proc,
2635 Hook->Ansi,
2636 &Hook->ModuleName);
2637 }
2638 else
2639 {
2640 CWPRETSTRUCT CWPR;
2641 CWPR.hwnd = hWnd;
2642 CWPR.message = Msg;
2643 CWPR.wParam = wParam;
2644 CWPR.lParam = lParam;
2645 CWPR.lResult = ClientInfo->dwHookData;
2646
2647 lResult = co_IntCallHookProc( Hook->HookId,
2648 HC_ACTION,
2649 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2650 (LPARAM)&CWPR,
2651 Hook->Proc,
2652 Hook->Ansi,
2653 &Hook->ModuleName);
2654 }
2655 }
2656 break;
2657 }
2658
2659 switch(dwType)
2660 {
2661 case FNID_DEFWINDOWPROC:
2662 case FNID_CALLWNDPROC:
2663 case FNID_CALLWNDPROCRET:
2664 if (ResultInfo)
2665 {
2666 _SEH2_TRY
2667 {
2668 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2669 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2670 }
2671 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2672 {
2673 Ret = FALSE;
2674 }
2675 _SEH2_END;
2676 }
2677 break;
2678 default:
2679 break;
2680 }
2681
2682 UserLeave();
2683
2684 return Ret;
2685 }
2686
2687 #define INFINITE 0xFFFFFFFF
2688 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2689
2690 DWORD
2691 APIENTRY
2692 NtUserWaitForInputIdle( IN HANDLE hProcess,
2693 IN DWORD dwMilliseconds,
2694 IN BOOL Unknown2)
2695 {
2696 PEPROCESS Process;
2697 PPROCESSINFO W32Process;
2698 PTHREADINFO pti;
2699 NTSTATUS Status;
2700 HANDLE Handles[3];
2701 LARGE_INTEGER Timeout;
2702
2703 UserEnterExclusive();
2704
2705 Status = ObReferenceObjectByHandle(hProcess,
2706 PROCESS_QUERY_INFORMATION,
2707 PsProcessType,
2708 UserMode,
2709 (PVOID*)&Process,
2710 NULL);
2711
2712 if (!NT_SUCCESS(Status))
2713 {
2714 UserLeave();
2715 SetLastNtError(Status);
2716 return WAIT_FAILED;
2717 }
2718
2719 pti = PsGetCurrentThreadWin32Thread();
2720
2721 W32Process = (PPROCESSINFO)Process->Win32Process;
2722
2723 if ( PsGetProcessExitProcessCalled(Process) ||
2724 !W32Process ||
2725 pti->ppi == W32Process)
2726 {
2727 ObDereferenceObject(Process);
2728 UserLeave();
2729 EngSetLastError(ERROR_INVALID_PARAMETER);
2730 return WAIT_FAILED;
2731 }
2732
2733 Handles[0] = Process;
2734 Handles[1] = W32Process->InputIdleEvent;
2735 Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2736
2737 if (!Handles[1])
2738 {
2739 ObDereferenceObject(Process);
2740 UserLeave();
2741 return STATUS_SUCCESS; /* no event to wait on */
2742 }
2743
2744 if (dwMilliseconds != INFINITE)
2745 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2746
2747 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2748 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2749 {
2750 pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2751 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2752 }
2753
2754 TRACE("WFII: ppi 0x%x\n",W32Process);
2755 TRACE("WFII: waiting for %p\n", Handles[1] );
2756 do
2757 {
2758 UserLeave();
2759 Status = KeWaitForMultipleObjects( 3,
2760 Handles,
2761 WaitAny,
2762 UserRequest,
2763 UserMode,
2764 FALSE,
2765 dwMilliseconds == INFINITE ? NULL : &Timeout,
2766 NULL);
2767 UserEnterExclusive();
2768
2769 if (!NT_SUCCESS(Status))
2770 {
2771 SetLastNtError(Status);
2772 Status = WAIT_FAILED;
2773 goto WaitExit;
2774 }
2775
2776 switch (Status)
2777 {
2778 case STATUS_WAIT_0:
2779 goto WaitExit;
2780
2781 case STATUS_WAIT_2:
2782 {
2783 MSG Msg;
2784 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
2785 ERR("WFII: WAIT 2\n");
2786 }
2787 break;
2788
2789 case STATUS_TIMEOUT:
2790 ERR("WFII: timeout\n");
2791 case WAIT_FAILED:
2792 goto WaitExit;
2793
2794 default:
2795 ERR("WFII: finished\n");
2796 Status = STATUS_SUCCESS;
2797 goto WaitExit;
2798 }
2799 }
2800 while (TRUE);
2801
2802 WaitExit:
2803 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2804 {
2805 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
2806 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2807 }
2808 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
2809 ObDereferenceObject(Process);
2810 UserLeave();
2811 return Status;
2812 }
2813
2814 /* EOF */