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