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