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