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