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