[Win32SS]
[reactos.git] / reactos / win32ss / user / ntuser / message.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Messages
5 * FILE: subsystems/win32/win32k/ntuser/message.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserMsg);
11
12 #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
13
14 /* FUNCTIONS *****************************************************************/
15
16 NTSTATUS FASTCALL
17 IntInitMessageImpl(VOID)
18 {
19 return STATUS_SUCCESS;
20 }
21
22 NTSTATUS FASTCALL
23 IntCleanupMessageImpl(VOID)
24 {
25 return STATUS_SUCCESS;
26 }
27
28 /* From wine: */
29 /* flag for messages that contain pointers */
30 /* 32 messages per entry, messages 0..31 map to bits 0..31 */
31
32 #define SET(msg) (1 << ((msg) & 31))
33
34 static const unsigned int message_pointer_flags[] =
35 {
36 /* 0x00 - 0x1f */
37 SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
38 SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
39 /* 0x20 - 0x3f */
40 SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
41 SET(WM_COMPAREITEM),
42 /* 0x40 - 0x5f */
43 SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
44 SET(WM_COPYGLOBALDATA) | SET(WM_NOTIFY) | SET(WM_HELP),
45 /* 0x60 - 0x7f */
46 SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
47 /* 0x80 - 0x9f */
48 SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
49 /* 0xa0 - 0xbf */
50 SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
51 /* 0xc0 - 0xdf */
52 SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
53 /* 0xe0 - 0xff */
54 SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO),
55 /* 0x100 - 0x11f */
56 0,
57 /* 0x120 - 0x13f */
58 0,
59 /* 0x140 - 0x15f */
60 SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
61 SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
62 SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
63 /* 0x160 - 0x17f */
64 0,
65 /* 0x180 - 0x19f */
66 SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
67 SET(LB_DIR) | SET(LB_FINDSTRING) |
68 SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
69 /* 0x1a0 - 0x1bf */
70 SET(LB_FINDSTRINGEXACT),
71 /* 0x1c0 - 0x1df */
72 0,
73 /* 0x1e0 - 0x1ff */
74 0,
75 /* 0x200 - 0x21f */
76 SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
77 /* 0x220 - 0x23f */
78 SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
79 SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
80 /* 0x240 - 0x25f */
81 0,
82 /* 0x260 - 0x27f */
83 0,
84 /* 0x280 - 0x29f */
85 0,
86 /* 0x2a0 - 0x2bf */
87 0,
88 /* 0x2c0 - 0x2df */
89 0,
90 /* 0x2e0 - 0x2ff */
91 0,
92 /* 0x300 - 0x31f */
93 SET(WM_ASKCBFORMATNAME)
94 };
95
96 /* check whether a given message type includes pointers */
97 static inline int is_pointer_message( UINT message )
98 {
99 if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
100 return (message_pointer_flags[message / 32] & SET(message)) != 0;
101 }
102 #undef SET
103
104 #define MMS_SIZE_WPARAM -1
105 #define MMS_SIZE_WPARAMWCHAR -2
106 #define MMS_SIZE_LPARAMSZ -3
107 #define MMS_SIZE_SPECIAL -4
108 #define MMS_FLAG_READ 0x01
109 #define MMS_FLAG_WRITE 0x02
110 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
111 typedef struct tagMSGMEMORY
112 {
113 UINT Message;
114 UINT Size;
115 INT Flags;
116 }
117 MSGMEMORY, *PMSGMEMORY;
118
119 static MSGMEMORY g_MsgMemory[] =
120 {
121 { WM_CREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
122 { WM_DDE_ACK, sizeof(KMDDELPARAM), MMS_FLAG_READ },
123 { WM_DDE_EXECUTE, MMS_SIZE_WPARAM, MMS_FLAG_READ },
124 { WM_GETMINMAXINFO, sizeof(MINMAXINFO), MMS_FLAG_READWRITE },
125 { WM_GETTEXT, MMS_SIZE_WPARAMWCHAR, MMS_FLAG_WRITE },
126 { WM_NCCALCSIZE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
127 { WM_NCCREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
128 { WM_SETTEXT, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ },
129 { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ },
130 { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE },
131 { WM_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 }
1332
1333 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
1334 {
1335 ERR("Failed to pack message parameters\n");
1336 RETURN( FALSE);
1337 }
1338
1339 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1340 !Window->Unicode,
1341 hWnd,
1342 Msg,
1343 wParam,
1344 lParamPacked,
1345 lParamBufferSize );
1346 if(uResult)
1347 {
1348 *uResult = Result;
1349 }
1350
1351 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1352 {
1353 ERR("Failed to unpack message parameters\n");
1354 RETURN( TRUE);
1355 }
1356
1357 // Only happens when calling the client!
1358 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1359
1360 RETURN( TRUE);
1361 }
1362
1363 if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(ptiSendTo))
1364 {
1365 // FIXME: Set window hung and add to a list.
1366 /* FIXME: Set a LastError? */
1367 RETURN( FALSE);
1368 }
1369
1370 if (Window->state & WNDS_DESTROYED)
1371 {
1372 /* FIXME: Last error? */
1373 ERR("Attempted to send message to window %p that is being destroyed!\n", hWnd);
1374 RETURN( FALSE);
1375 }
1376
1377 do
1378 {
1379 Status = co_MsqSendMessage( ptiSendTo,
1380 hWnd,
1381 Msg,
1382 wParam,
1383 lParam,
1384 uTimeout,
1385 (uFlags & SMTO_BLOCK),
1386 MSQ_NORMAL,
1387 uResult );
1388 }
1389 while ((STATUS_TIMEOUT == Status) &&
1390 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1391 !MsqIsHung(ptiSendTo)); // FIXME: Set window hung and add to a list.
1392
1393 if (STATUS_TIMEOUT == Status)
1394 {
1395 /*
1396 * MSDN says:
1397 * Microsoft Windows 2000: If GetLastError returns zero, then the function
1398 * timed out.
1399 * XP+ : If the function fails or times out, the return value is zero.
1400 * To get extended error information, call GetLastError. If GetLastError
1401 * returns ERROR_TIMEOUT, then the function timed out.
1402 */
1403 EngSetLastError(ERROR_TIMEOUT);
1404 RETURN( FALSE);
1405 }
1406 else if (!NT_SUCCESS(Status))
1407 {
1408 SetLastNtError(Status);
1409 RETURN( FALSE);
1410 }
1411
1412 RETURN( TRUE);
1413
1414 CLEANUP:
1415 if (Window) UserDerefObjectCo(Window);
1416 END_CLEANUP;
1417 }
1418
1419 LRESULT FASTCALL
1420 co_IntSendMessageTimeout( HWND hWnd,
1421 UINT Msg,
1422 WPARAM wParam,
1423 LPARAM lParam,
1424 UINT uFlags,
1425 UINT uTimeout,
1426 ULONG_PTR *uResult )
1427 {
1428 PWND DesktopWindow;
1429 HWND *Children;
1430 HWND *Child;
1431
1432 if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST)
1433 {
1434 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1435 }
1436
1437 DesktopWindow = UserGetDesktopWindow();
1438 if (NULL == DesktopWindow)
1439 {
1440 EngSetLastError(ERROR_INTERNAL_ERROR);
1441 return 0;
1442 }
1443
1444 if (hWnd != HWND_TOPMOST)
1445 {
1446 /* Send message to the desktop window too! */
1447 co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1448 }
1449
1450 Children = IntWinListChildren(DesktopWindow);
1451 if (NULL == Children)
1452 {
1453 return 0;
1454 }
1455
1456 for (Child = Children; NULL != *Child; Child++)
1457 {
1458 if (hWnd == HWND_TOPMOST)
1459 {
1460 DesktopWindow = UserGetWindowObject(*Child);
1461 if (DesktopWindow && DesktopWindow->ExStyle & WS_EX_TOPMOST)
1462 {
1463 ERR("HWND_TOPMOST Found\n");
1464 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1465 }
1466 }
1467 else
1468 {
1469 PWND pwnd = UserGetWindowObject(*Child);
1470 if (!pwnd) continue;
1471
1472 if ( pwnd->fnid == FNID_MENU ||
1473 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
1474 continue;
1475
1476 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1477 }
1478 }
1479
1480 ExFreePool(Children);
1481
1482 return (LRESULT) TRUE;
1483 }
1484
1485 LRESULT FASTCALL
1486 co_IntSendMessageNoWait(HWND hWnd,
1487 UINT Msg,
1488 WPARAM wParam,
1489 LPARAM lParam)
1490 {
1491 ULONG_PTR Result = 0;
1492 return co_IntSendMessageWithCallBack( hWnd,
1493 Msg,
1494 wParam,
1495 lParam,
1496 NULL,
1497 0,
1498 &Result);
1499 }
1500 /* MSDN:
1501 If you send a message in the range below WM_USER to the asynchronous message
1502 functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its
1503 message parameters cannot include pointers. Otherwise, the operation will fail.
1504 The functions will return before the receiving thread has had a chance to
1505 process the message and the sender will free the memory before it is used.
1506 */
1507 LRESULT FASTCALL
1508 co_IntSendMessageWithCallBack( HWND hWnd,
1509 UINT Msg,
1510 WPARAM wParam,
1511 LPARAM lParam,
1512 SENDASYNCPROC CompletionCallback,
1513 ULONG_PTR CompletionCallbackContext,
1514 ULONG_PTR *uResult)
1515 {
1516 ULONG_PTR Result;
1517 PWND Window = NULL;
1518 PMSGMEMORY MsgMemoryEntry;
1519 INT lParamBufferSize;
1520 LPARAM lParamPacked;
1521 PTHREADINFO Win32Thread, ptiSendTo = NULL;
1522 DECLARE_RETURN(LRESULT);
1523 USER_REFERENCE_ENTRY Ref;
1524 PUSER_SENT_MESSAGE Message;
1525 BOOL DoCallBack = TRUE;
1526
1527 if (!(Window = UserGetWindowObject(hWnd)))
1528 {
1529 TRACE("SendMessageWithCallBack: Invalid handle 0x%p!\n",hWnd);
1530 RETURN(FALSE);
1531 }
1532
1533 UserRefObjectCo(Window, &Ref);
1534
1535 if (Window->state & WNDS_DESTROYED)
1536 {
1537 /* FIXME: last error? */
1538 ERR("Attempted to send message to window %p that is being destroyed!\n", hWnd);
1539 RETURN(FALSE);
1540 }
1541
1542 Win32Thread = PsGetCurrentThreadWin32Thread();
1543
1544 if (Win32Thread == NULL ||
1545 Win32Thread->TIF_flags & TIF_INCLEANUP)
1546 {
1547 RETURN(FALSE);
1548 }
1549
1550 ptiSendTo = IntSendTo(Window, Win32Thread, Msg);
1551
1552 if (Msg & 0x80000000 &&
1553 !ptiSendTo)
1554 {
1555 if (Win32Thread->TIF_flags & TIF_INCLEANUP) RETURN( FALSE);
1556
1557 TRACE("SMWCB: Internal Message!\n");
1558 Result = (ULONG_PTR)handle_internal_message( Window, Msg, wParam, lParam );
1559 if (uResult) *uResult = Result;
1560 RETURN( TRUE);
1561 }
1562
1563 /* See if this message type is present in the table */
1564 MsgMemoryEntry = FindMsgMemory(Msg);
1565 if (NULL == MsgMemoryEntry)
1566 {
1567 lParamBufferSize = -1;
1568 }
1569 else
1570 {
1571 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1572 }
1573
1574 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, !!ptiSendTo)))
1575 {
1576 ERR("Failed to pack message parameters\n");
1577 RETURN( FALSE);
1578 }
1579
1580 /* If it can be sent now, then send it. */
1581 if ( !ptiSendTo )
1582 {
1583 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1584 {
1585 UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE);
1586 /* Never send messages to exiting threads */
1587 RETURN(FALSE);
1588 }
1589
1590 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1591
1592 if ( Window->state & WNDS_SERVERSIDEWINDOWPROC )
1593 {
1594 TRACE("SMWCB: Server Side Window Procedure\n");
1595 switch(Window->fnid)
1596 {
1597 case FNID_DESKTOP:
1598 DoCallBack = !DesktopWindowProc(Window, Msg, wParam, lParamPacked, (LRESULT*)&Result);
1599 break;
1600 case FNID_MESSAGEWND:
1601 DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result);
1602 break;
1603 }
1604 }
1605
1606 if (DoCallBack)
1607 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1608 !Window->Unicode,
1609 hWnd,
1610 Msg,
1611 wParam,
1612 lParamPacked,
1613 lParamBufferSize );
1614 if(uResult)
1615 {
1616 *uResult = Result;
1617 }
1618
1619 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1620
1621 if (CompletionCallback)
1622 {
1623 co_IntCallSentMessageCallback(CompletionCallback,
1624 hWnd,
1625 Msg,
1626 CompletionCallbackContext,
1627 Result);
1628 }
1629 }
1630
1631 if ( !ptiSendTo)
1632 {
1633 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1634 {
1635 ERR("Failed to unpack message parameters\n");
1636 }
1637 RETURN(TRUE);
1638 }
1639
1640 if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
1641 {
1642 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1643 RETURN( FALSE);
1644 }
1645
1646 Message->Msg.hwnd = hWnd;
1647 Message->Msg.message = Msg;
1648 Message->Msg.wParam = wParam;
1649 Message->Msg.lParam = lParamPacked;
1650 Message->CompletionEvent = NULL;
1651 Message->Result = 0;
1652 Message->lResult = 0;
1653 Message->QS_Flags = 0;
1654 Message->ptiReceiver = ptiSendTo;
1655 Message->ptiSender = NULL; // mjmartin, you are right! This is null.
1656 Message->ptiCallBackSender = Win32Thread;
1657 Message->DispatchingListEntry.Flink = NULL;
1658 Message->CompletionCallback = CompletionCallback;
1659 Message->CompletionCallbackContext = CompletionCallbackContext;
1660 Message->HookMessage = MSQ_NORMAL;
1661 Message->HasPackedLParam = (lParamBufferSize > 0);
1662 Message->QS_Flags = QS_SENDMESSAGE;
1663
1664 if (Msg & 0x80000000) // Higher priority event message!
1665 InsertHeadList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry);
1666 else
1667 InsertTailList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry);
1668 MsqWakeQueue(ptiSendTo, QS_SENDMESSAGE, TRUE);
1669
1670 RETURN(TRUE);
1671
1672 CLEANUP:
1673 if (Window) UserDerefObjectCo(Window);
1674 END_CLEANUP;
1675 }
1676
1677
1678 /*
1679 This HACK function posts a message if the destination's message queue belongs to
1680 another thread, otherwise it sends the message. It does not support broadcast
1681 messages!
1682 */
1683 LRESULT FASTCALL
1684 co_IntPostOrSendMessage( HWND hWnd,
1685 UINT Msg,
1686 WPARAM wParam,
1687 LPARAM lParam )
1688 {
1689 ULONG_PTR Result;
1690 PTHREADINFO pti;
1691 PWND Window;
1692
1693 if ( hWnd == HWND_BROADCAST )
1694 {
1695 return 0;
1696 }
1697
1698 if(!(Window = UserGetWindowObject(hWnd)))
1699 {
1700 TRACE("PostOrSendMessage: Invalid handle 0x%p!\n",hWnd);
1701 return 0;
1702 }
1703
1704 pti = PsGetCurrentThreadWin32Thread();
1705
1706 if ( IntSendTo(Window, pti, Msg) &&
1707 FindMsgMemory(Msg) == 0 )
1708 {
1709 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1710 }
1711 else
1712 {
1713 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1714 {
1715 Result = 0;
1716 }
1717 }
1718
1719 return (LRESULT)Result;
1720 }
1721
1722 static LRESULT FASTCALL
1723 co_IntDoSendMessage( HWND hWnd,
1724 UINT Msg,
1725 WPARAM wParam,
1726 LPARAM lParam,
1727 PDOSENDMESSAGE dsm)
1728 {
1729 LRESULT Result = TRUE;
1730 NTSTATUS Status;
1731 PWND Window = NULL;
1732 MSG UserModeMsg, KernelModeMsg;
1733 PMSGMEMORY MsgMemoryEntry;
1734 PTHREADINFO ptiSendTo;
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 this message */
1752 ptiSendTo = IntSendTo(Window, gptiCurrent, Msg);
1753
1754 // If broadcasting or sending to another thread, save the users data.
1755 if (!Window || ptiSendTo )
1756 {
1757 UserModeMsg.hwnd = hWnd;
1758 UserModeMsg.message = Msg;
1759 UserModeMsg.wParam = wParam;
1760 UserModeMsg.lParam = lParam;
1761 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1762 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1763 if (!NT_SUCCESS(Status))
1764 {
1765 EngSetLastError(ERROR_INVALID_PARAMETER);
1766 return (dsm ? 0 : -1);
1767 }
1768 }
1769 else
1770 {
1771 KernelModeMsg.hwnd = hWnd;
1772 KernelModeMsg.message = Msg;
1773 KernelModeMsg.wParam = wParam;
1774 KernelModeMsg.lParam = lParam;
1775 }
1776
1777 if (!dsm)
1778 {
1779 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1780 KernelModeMsg.message,
1781 KernelModeMsg.wParam,
1782 KernelModeMsg.lParam );
1783 }
1784 else
1785 {
1786 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1787 KernelModeMsg.message,
1788 KernelModeMsg.wParam,
1789 KernelModeMsg.lParam,
1790 dsm->uFlags,
1791 dsm->uTimeout,
1792 &dsm->Result );
1793 }
1794
1795 if (!Window || ptiSendTo )
1796 {
1797 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1798 if (!NT_SUCCESS(Status))
1799 {
1800 EngSetLastError(ERROR_INVALID_PARAMETER);
1801 return(dsm ? 0 : -1);
1802 }
1803 }
1804
1805 return (LRESULT)Result;
1806 }
1807
1808 BOOL FASTCALL
1809 UserSendNotifyMessage( HWND hWnd,
1810 UINT Msg,
1811 WPARAM wParam,
1812 LPARAM lParam )
1813 {
1814 BOOL Ret = TRUE;
1815
1816 if (is_pointer_message(Msg))
1817 {
1818 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1819 return FALSE;
1820 }
1821
1822 // Basicly the same as IntPostOrSendMessage
1823 if (hWnd == HWND_BROADCAST) // Handle Broadcast
1824 {
1825 HWND *List;
1826 PWND DesktopWindow;
1827 ULONG i;
1828
1829 DesktopWindow = UserGetDesktopWindow();
1830 List = IntWinListChildren(DesktopWindow);
1831
1832 if (List != NULL)
1833 {
1834 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1835 for (i = 0; List[i]; i++)
1836 {
1837 PWND pwnd = UserGetWindowObject(List[i]);
1838 if (!pwnd) continue;
1839
1840 if ( pwnd->fnid == FNID_MENU ||
1841 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
1842 continue;
1843
1844 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1845 }
1846 ExFreePool(List);
1847 }
1848 }
1849 else
1850 {
1851 Ret = co_IntSendMessageNoWait( hWnd, Msg, wParam, lParam);
1852 }
1853 return Ret;
1854 }
1855
1856
1857 DWORD APIENTRY
1858 IntGetQueueStatus(DWORD Changes)
1859 {
1860 PTHREADINFO pti;
1861 DWORD Result;
1862
1863 pti = PsGetCurrentThreadWin32Thread();
1864 // wine:
1865 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1866
1867 /* High word, types of messages currently in the queue.
1868 Low word, types of messages that have been added to the queue and that
1869 are still in the queue
1870 */
1871 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
1872
1873 pti->pcti->fsChangeBits &= ~Changes;
1874
1875 return Result;
1876 }
1877
1878 BOOL APIENTRY
1879 IntInitMessagePumpHook()
1880 {
1881 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1882
1883 if (pti->pcti)
1884 {
1885 pti->pcti->dwcPumpHook++;
1886 return TRUE;
1887 }
1888 return FALSE;
1889 }
1890
1891 BOOL APIENTRY
1892 IntUninitMessagePumpHook()
1893 {
1894 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1895
1896 if (pti->pcti)
1897 {
1898 if (pti->pcti->dwcPumpHook <= 0)
1899 {
1900 return FALSE;
1901 }
1902 pti->pcti->dwcPumpHook--;
1903 return TRUE;
1904 }
1905 return FALSE;
1906 }
1907
1908 /** Functions ******************************************************************/
1909
1910 BOOL
1911 APIENTRY
1912 NtUserDragDetect(
1913 HWND hWnd,
1914 POINT pt) // Just like the User call.
1915 {
1916 MSG msg;
1917 RECT rect;
1918 ULONG wDragWidth, wDragHeight;
1919 DECLARE_RETURN(BOOL);
1920
1921 TRACE("Enter NtUserDragDetect(%p)\n", hWnd);
1922 UserEnterExclusive();
1923
1924 wDragWidth = UserGetSystemMetrics(SM_CXDRAG);
1925 wDragHeight= UserGetSystemMetrics(SM_CYDRAG);
1926
1927 rect.left = pt.x - wDragWidth;
1928 rect.right = pt.x + wDragWidth;
1929
1930 rect.top = pt.y - wDragHeight;
1931 rect.bottom = pt.y + wDragHeight;
1932
1933 co_UserSetCapture(hWnd);
1934
1935 for (;;)
1936 {
1937 while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) ||
1938 co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC, WM_QUEUESYNC, PM_REMOVE, FALSE ) ||
1939 co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE, FALSE ) )
1940 {
1941 if ( msg.message == WM_LBUTTONUP )
1942 {
1943 co_UserSetCapture(NULL);
1944 RETURN( FALSE);
1945 }
1946 if ( msg.message == WM_MOUSEMOVE )
1947 {
1948 POINT tmp;
1949 tmp.x = (short)LOWORD(msg.lParam);
1950 tmp.y = (short)HIWORD(msg.lParam);
1951 if( !RECTL_bPointInRect( &rect, tmp.x, tmp.y ) )
1952 {
1953 co_UserSetCapture(NULL);
1954 RETURN( TRUE);
1955 }
1956 }
1957 if ( msg.message == WM_KEYDOWN )
1958 {
1959 if ( msg.wParam == VK_ESCAPE )
1960 {
1961 co_UserSetCapture(NULL);
1962 RETURN( TRUE);
1963 }
1964 }
1965 if ( msg.message == WM_QUEUESYNC )
1966 {
1967 co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 );
1968 }
1969 }
1970 co_IntWaitMessage(NULL, 0, 0);
1971 }
1972 RETURN( FALSE);
1973
1974 CLEANUP:
1975 TRACE("Leave NtUserDragDetect, ret=%i\n",_ret_);
1976 UserLeave();
1977 END_CLEANUP;
1978 }
1979
1980 BOOL APIENTRY
1981 NtUserPostMessage(HWND hWnd,
1982 UINT Msg,
1983 WPARAM wParam,
1984 LPARAM lParam)
1985 {
1986 BOOL ret;
1987
1988 UserEnterExclusive();
1989
1990 ret = UserPostMessage(hWnd, Msg, wParam, lParam);
1991
1992 UserLeave();
1993
1994 return ret;
1995 }
1996
1997 BOOL APIENTRY
1998 NtUserPostThreadMessage(DWORD idThread,
1999 UINT Msg,
2000 WPARAM wParam,
2001 LPARAM lParam)
2002 {
2003 BOOL ret;
2004 PETHREAD peThread;
2005 PTHREADINFO pThread;
2006 NTSTATUS Status;
2007
2008 UserEnterExclusive();
2009
2010 Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
2011
2012 if ( Status == STATUS_SUCCESS )
2013 {
2014 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
2015 if( !pThread ||
2016 !pThread->MessageQueue ||
2017 (pThread->TIF_flags & TIF_INCLEANUP))
2018 {
2019 ObDereferenceObject( peThread );
2020 goto exit;
2021 }
2022 ret = UserPostThreadMessage( pThread, Msg, wParam, lParam);
2023 ObDereferenceObject( peThread );
2024 }
2025 else
2026 {
2027 SetLastNtError( Status );
2028 }
2029 exit:
2030 UserLeave();
2031 return ret;
2032 }
2033
2034 BOOL APIENTRY
2035 NtUserWaitMessage(VOID)
2036 {
2037 BOOL ret;
2038
2039 UserEnterExclusive();
2040 TRACE("NtUserWaitMessage Enter\n");
2041 ret = co_IntWaitMessage(NULL, 0, 0);
2042 TRACE("NtUserWaitMessage Leave\n");
2043 UserLeave();
2044
2045 return ret;
2046 }
2047
2048 BOOL APIENTRY
2049 NtUserGetMessage(PMSG pMsg,
2050 HWND hWnd,
2051 UINT MsgFilterMin,
2052 UINT MsgFilterMax )
2053 {
2054 MSG Msg;
2055 BOOL Ret;
2056
2057 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
2058 {
2059 EngSetLastError(ERROR_INVALID_PARAMETER);
2060 return FALSE;
2061 }
2062
2063 UserEnterExclusive();
2064
2065 RtlZeroMemory(&Msg, sizeof(MSG));
2066
2067 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
2068
2069 UserLeave();
2070
2071 if (Ret == TRUE)
2072 {
2073 _SEH2_TRY
2074 {
2075 ProbeForWrite(pMsg, sizeof(MSG), 1);
2076 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2077 }
2078 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2079 {
2080 SetLastNtError(_SEH2_GetExceptionCode());
2081 Ret = FALSE;
2082 }
2083 _SEH2_END;
2084 }
2085
2086 if ((INT)Ret != -1)
2087 Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE;
2088
2089 return Ret;
2090 }
2091
2092 BOOL APIENTRY
2093 NtUserPeekMessage( PMSG pMsg,
2094 HWND hWnd,
2095 UINT MsgFilterMin,
2096 UINT MsgFilterMax,
2097 UINT RemoveMsg)
2098 {
2099 MSG Msg;
2100 BOOL Ret;
2101
2102 if ( RemoveMsg & PM_BADMSGFLAGS )
2103 {
2104 EngSetLastError(ERROR_INVALID_FLAGS);
2105 return FALSE;
2106 }
2107
2108 UserEnterExclusive();
2109
2110 RtlZeroMemory(&Msg, sizeof(MSG));
2111
2112 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
2113
2114 UserLeave();
2115
2116 if (Ret)
2117 {
2118 _SEH2_TRY
2119 {
2120 ProbeForWrite(pMsg, sizeof(MSG), 1);
2121 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2122 }
2123 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2124 {
2125 SetLastNtError(_SEH2_GetExceptionCode());
2126 Ret = FALSE;
2127 }
2128 _SEH2_END;
2129 }
2130
2131 return Ret;
2132 }
2133
2134 BOOL APIENTRY
2135 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
2136 {
2137 BOOL Ret = FALSE;
2138 MSG Msg;
2139
2140 _SEH2_TRY
2141 {
2142 ProbeForRead(lpmsg, sizeof(MSG), 1);
2143 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
2144 }
2145 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2146 {
2147 _SEH2_YIELD(return FALSE);
2148 }
2149 _SEH2_END;
2150
2151 UserEnterExclusive();
2152
2153 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
2154 {
2155 Ret = TRUE;
2156 }
2157 else
2158 {
2159 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
2160 }
2161
2162 UserLeave();
2163
2164 _SEH2_TRY
2165 {
2166 ProbeForWrite(lpmsg, sizeof(MSG), 1);
2167 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
2168 }
2169 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2170 {
2171 Ret = FALSE;
2172 }
2173 _SEH2_END;
2174
2175 return Ret;
2176 }
2177
2178 LRESULT APIENTRY
2179 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
2180 {
2181 LRESULT Res = 0;
2182 MSG SafeMsg;
2183
2184 _SEH2_TRY
2185 {
2186 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
2187 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
2188 }
2189 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2190 {
2191 SetLastNtError(_SEH2_GetExceptionCode());
2192 _SEH2_YIELD(return FALSE);
2193 }
2194 _SEH2_END;
2195
2196 UserEnterExclusive();
2197
2198 Res = IntDispatchMessage(&SafeMsg);
2199
2200 UserLeave();
2201 return Res;
2202 }
2203
2204 BOOL APIENTRY
2205 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
2206 {
2207 MSG SafeMsg;
2208 BOOL Ret;
2209 PWND pWnd;
2210
2211 _SEH2_TRY
2212 {
2213 ProbeForRead(lpMsg, sizeof(MSG), 1);
2214 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
2215 }
2216 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2217 {
2218 SetLastNtError(_SEH2_GetExceptionCode());
2219 _SEH2_YIELD(return FALSE);
2220 }
2221 _SEH2_END;
2222
2223 UserEnterExclusive();
2224 pWnd = UserGetWindowObject(SafeMsg.hwnd);
2225 if (pWnd) // Must have a window!
2226 {
2227 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
2228 }
2229 else
2230 {
2231 TRACE("No Window for Translate. hwnd 0x%p Msg %u\n", SafeMsg.hwnd, SafeMsg.message);
2232 Ret = FALSE;
2233 }
2234 UserLeave();
2235
2236 return Ret;
2237 }
2238
2239 LRESULT APIENTRY ScrollBarWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam);
2240
2241 BOOL APIENTRY
2242 NtUserMessageCall( HWND hWnd,
2243 UINT Msg,
2244 WPARAM wParam,
2245 LPARAM lParam,
2246 ULONG_PTR ResultInfo,
2247 DWORD dwType, // fnID?
2248 BOOL Ansi)
2249 {
2250 LRESULT lResult = 0;
2251 BOOL Ret = FALSE;
2252 PWND Window = NULL;
2253 USER_REFERENCE_ENTRY Ref;
2254
2255 UserEnterExclusive();
2256
2257 switch(dwType)
2258 {
2259 case FNID_SCROLLBAR:
2260 {
2261 lResult = ScrollBarWndProc(hWnd, Msg, wParam, lParam);
2262 break;
2263 }
2264 case FNID_DESKTOP:
2265 {
2266 Window = UserGetWindowObject(hWnd);
2267 if (Window)
2268 {
2269 //ERR("FNID_DESKTOP IN\n");
2270 Ret = DesktopWindowProc(Window, Msg, wParam, lParam, &lResult);
2271 //ERR("FNID_DESKTOP OUT\n");
2272 }
2273 break;
2274 }
2275
2276 case FNID_MESSAGEWND:
2277 {
2278 Window = UserGetWindowObject(hWnd);
2279 if (Window)
2280 {
2281 Ret = !UserMessageWindowProc(Window, Msg, wParam, lParam,&lResult);
2282 }
2283 break;
2284 }
2285 case FNID_DEFWINDOWPROC:
2286 /* Validate input */
2287 if (hWnd)
2288 {
2289 Window = UserGetWindowObject(hWnd);
2290 if (!Window)
2291 {
2292 UserLeave();
2293 return FALSE;
2294 }
2295 UserRefObjectCo(Window, &Ref);
2296 }
2297 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2298 Ret = TRUE;
2299 if (hWnd)
2300 UserDerefObjectCo(Window);
2301 break;
2302 case FNID_SENDNOTIFYMESSAGE:
2303 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2304 break;
2305 case FNID_BROADCASTSYSTEMMESSAGE:
2306 {
2307 BROADCASTPARM parm, *retparam;
2308 DWORD_PTR RetVal = 0;
2309
2310 if (ResultInfo)
2311 {
2312 _SEH2_TRY
2313 {
2314 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
2315 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2316 }
2317 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2318 {
2319 _SEH2_YIELD(break);
2320 }
2321 _SEH2_END;
2322 }
2323 else
2324 break;
2325
2326 if ( parm.recipients & BSM_ALLDESKTOPS ||
2327 parm.recipients == BSM_ALLCOMPONENTS )
2328 {
2329 PLIST_ENTRY DesktopEntry;
2330 PDESKTOP rpdesk;
2331 HWND *List, hwndDenied = NULL;
2332 HDESK hDesk = NULL;
2333 PWND pwnd, pwndDesk;
2334 ULONG i;
2335 UINT fuFlags;
2336
2337 for (DesktopEntry = InputWindowStation->DesktopListHead.Flink;
2338 DesktopEntry != &InputWindowStation->DesktopListHead;
2339 DesktopEntry = DesktopEntry->Flink)
2340 {
2341 rpdesk = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
2342 pwndDesk = rpdesk->pDeskInfo->spwnd;
2343 List = IntWinListChildren(pwndDesk);
2344
2345 if (parm.flags & BSF_QUERY)
2346 {
2347 if (List != NULL)
2348 {
2349 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2350 {
2351 fuFlags = SMTO_ABORTIFHUNG;
2352 }
2353 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2354 {
2355 fuFlags = SMTO_NOTIMEOUTIFNOTHUNG;
2356 }
2357 else
2358 {
2359 fuFlags = SMTO_NORMAL;
2360 }
2361 co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk),
2362 Msg,
2363 wParam,
2364 lParam,
2365 fuFlags,
2366 2000,
2367 &RetVal);
2368 Ret = TRUE;
2369 for (i = 0; List[i]; i++)
2370 {
2371 pwnd = UserGetWindowObject(List[i]);
2372 if (!pwnd) continue;
2373
2374 if ( pwnd->fnid == FNID_MENU ||
2375 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2376 continue;
2377
2378 if ( parm.flags & BSF_IGNORECURRENTTASK )
2379 {
2380 if ( pwnd->head.pti == gptiCurrent )
2381 continue;
2382 }
2383 co_IntSendMessageTimeout( List[i],
2384 Msg,
2385 wParam,
2386 lParam,
2387 fuFlags,
2388 2000,
2389 &RetVal);
2390
2391 if (!RetVal && EngGetLastError() == ERROR_TIMEOUT)
2392 {
2393 if (!(parm.flags & BSF_FORCEIFHUNG))
2394 Ret = FALSE;
2395 }
2396 if (RetVal == BROADCAST_QUERY_DENY)
2397 {
2398 hwndDenied = List[i];
2399 hDesk = UserHMGetHandle(pwndDesk);
2400 Ret = FALSE;
2401 }
2402 }
2403 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2404 _SEH2_TRY
2405 {
2406 retparam = (PBROADCASTPARM) ResultInfo;
2407 retparam->hDesk = hDesk;
2408 retparam->hWnd = hwndDenied;
2409 }
2410 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2411 {
2412 _SEH2_YIELD(break);
2413 }
2414 _SEH2_END;
2415 if (!Ret) break; // Have a hit! Let everyone know!
2416 }
2417 }
2418 else if (parm.flags & BSF_POSTMESSAGE)
2419 {
2420 if (List != NULL)
2421 {
2422 UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2423
2424 for (i = 0; List[i]; i++)
2425 {
2426 pwnd = UserGetWindowObject(List[i]);
2427 if (!pwnd) continue;
2428
2429 if ( pwnd->fnid == FNID_MENU ||
2430 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2431 continue;
2432
2433 if ( parm.flags & BSF_IGNORECURRENTTASK )
2434 {
2435 if ( pwnd->head.pti == gptiCurrent )
2436 continue;
2437 }
2438 UserPostMessage(List[i], Msg, wParam, lParam);
2439 }
2440 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2441 }
2442 Ret = TRUE;
2443 }
2444 else
2445 {
2446 if (List != NULL)
2447 {
2448 UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2449
2450 for (i = 0; List[i]; i++)
2451 {
2452 pwnd = UserGetWindowObject(List[i]);
2453 if (!pwnd) continue;
2454
2455 if ( pwnd->fnid == FNID_MENU ||
2456 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2457 continue;
2458
2459 if ( parm.flags & BSF_IGNORECURRENTTASK )
2460 {
2461 if ( pwnd->head.pti == gptiCurrent )
2462 continue;
2463 }
2464 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
2465 }
2466 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2467 }
2468 Ret = TRUE;
2469 }
2470 }
2471 }
2472 else if (parm.recipients & BSM_APPLICATIONS)
2473 {
2474 HWND *List, hwndDenied = NULL;
2475 HDESK hDesk = NULL;
2476 PWND pwnd, pwndDesk;
2477 ULONG i;
2478 UINT fuFlags;
2479
2480 pwndDesk = UserGetDesktopWindow();
2481 List = IntWinListChildren(pwndDesk);
2482
2483 if (parm.flags & BSF_QUERY)
2484 {
2485 if (List != NULL)
2486 {
2487 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2488 {
2489 fuFlags = SMTO_ABORTIFHUNG;
2490 }
2491 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2492 {
2493 fuFlags = SMTO_NOTIMEOUTIFNOTHUNG;
2494 }
2495 else
2496 {
2497 fuFlags = SMTO_NORMAL;
2498 }
2499 co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk),
2500 Msg,
2501 wParam,
2502 lParam,
2503 fuFlags,
2504 2000,
2505 &RetVal);
2506 Ret = TRUE;
2507 for (i = 0; List[i]; i++)
2508 {
2509 pwnd = UserGetWindowObject(List[i]);
2510 if (!pwnd) continue;
2511
2512 if ( pwnd->fnid == FNID_MENU ||
2513 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2514 continue;
2515
2516 if ( parm.flags & BSF_IGNORECURRENTTASK )
2517 {
2518 if ( pwnd->head.pti == gptiCurrent )
2519 continue;
2520 }
2521 co_IntSendMessageTimeout( List[i],
2522 Msg,
2523 wParam,
2524 lParam,
2525 fuFlags,
2526 2000,
2527 &RetVal);
2528
2529 if (!RetVal && EngGetLastError() == ERROR_TIMEOUT)
2530 {
2531 if (!(parm.flags & BSF_FORCEIFHUNG))
2532 Ret = FALSE;
2533 }
2534 if (RetVal == BROADCAST_QUERY_DENY)
2535 {
2536 hwndDenied = List[i];
2537 hDesk = UserHMGetHandle(pwndDesk);
2538 Ret = FALSE;
2539 }
2540 }
2541 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2542 _SEH2_TRY
2543 {
2544 retparam = (PBROADCASTPARM) ResultInfo;
2545 retparam->hDesk = hDesk;
2546 retparam->hWnd = hwndDenied;
2547 }
2548 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2549 {
2550 _SEH2_YIELD(break);
2551 }
2552 _SEH2_END;
2553 }
2554 }
2555 else if (parm.flags & BSF_POSTMESSAGE)
2556 {
2557 if (List != NULL)
2558 {
2559 UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2560
2561 for (i = 0; List[i]; i++)
2562 {
2563 pwnd = UserGetWindowObject(List[i]);
2564 if (!pwnd) continue;
2565
2566 if ( pwnd->fnid == FNID_MENU ||
2567 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2568 continue;
2569
2570 if ( parm.flags & BSF_IGNORECURRENTTASK )
2571 {
2572 if ( pwnd->head.pti == gptiCurrent )
2573 continue;
2574 }
2575 UserPostMessage(List[i], Msg, wParam, lParam);
2576 }
2577 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2578 }
2579 Ret = TRUE;
2580 }
2581 else
2582 {
2583 if (List != NULL)
2584 {
2585 UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2586
2587 for (i = 0; List[i]; i++)
2588 {
2589 pwnd = UserGetWindowObject(List[i]);
2590 if (!pwnd) continue;
2591
2592 if ( pwnd->fnid == FNID_MENU ||
2593 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2594 continue;
2595
2596 if ( parm.flags & BSF_IGNORECURRENTTASK )
2597 {
2598 if ( pwnd->head.pti == gptiCurrent )
2599 continue;
2600 }
2601 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
2602 }
2603 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2604 }
2605 Ret = TRUE;
2606 }
2607 }
2608 }
2609 break;
2610 case FNID_SENDMESSAGECALLBACK:
2611 {
2612 CALL_BACK_INFO CallBackInfo;
2613 ULONG_PTR uResult;
2614
2615 _SEH2_TRY
2616 {
2617 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
2618 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
2619 }
2620 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2621 {
2622 _SEH2_YIELD(break);
2623 }
2624 _SEH2_END;
2625
2626 if (is_pointer_message(Msg))
2627 {
2628 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
2629 break;
2630 }
2631
2632 if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2633 CallBackInfo.CallBack, CallBackInfo.Context, &uResult)))
2634 {
2635 ERR("Callback failure!\n");
2636 }
2637 }
2638 break;
2639 case FNID_SENDMESSAGE:
2640 {
2641 Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
2642
2643 if (ResultInfo)
2644 {
2645 _SEH2_TRY
2646 {
2647 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
2648 RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
2649 }
2650 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2651 {
2652 Ret = FALSE;
2653 _SEH2_YIELD(break);
2654 }
2655 _SEH2_END;
2656 }
2657 break;
2658 }
2659 case FNID_SENDMESSAGEFF:
2660 case FNID_SENDMESSAGEWTOOPTION:
2661 {
2662 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
2663 if (ResultInfo)
2664 {
2665 _SEH2_TRY
2666 {
2667 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
2668 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
2669 }
2670 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2671 {
2672 _SEH2_YIELD(break);
2673 }
2674 _SEH2_END;
2675 }
2676
2677 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
2678
2679 if (pdsm)
2680 {
2681 _SEH2_TRY
2682 {
2683 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
2684 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2685 }
2686 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2687 {
2688 Ret = FALSE;
2689 _SEH2_YIELD(break);
2690 }
2691 _SEH2_END;
2692 }
2693 break;
2694 }
2695 // CallNextHook bypass.
2696 case FNID_CALLWNDPROC:
2697 case FNID_CALLWNDPROCRET:
2698 {
2699 PTHREADINFO pti;
2700 PCLIENTINFO ClientInfo;
2701 PHOOK NextObj, Hook;
2702
2703 pti = GetW32ThreadInfo();
2704
2705 Hook = pti->sphkCurrent;
2706
2707 if (!Hook) break;
2708
2709 NextObj = Hook->phkNext;
2710 ClientInfo = pti->pClientInfo;
2711 _SEH2_TRY
2712 {
2713 ClientInfo->phkCurrent = NextObj;
2714 }
2715 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2716 {
2717 ClientInfo = NULL;
2718 }
2719 _SEH2_END;
2720
2721 if (!ClientInfo || !NextObj) break;
2722
2723 NextObj->phkNext = IntGetNextHook(NextObj);
2724
2725 if ( Hook->HookId == WH_CALLWNDPROC)
2726 {
2727 CWPSTRUCT CWP;
2728 CWP.hwnd = hWnd;
2729 CWP.message = Msg;
2730 CWP.wParam = wParam;
2731 CWP.lParam = lParam;
2732 TRACE("WH_CALLWNDPROC: Hook %p NextHook %p\n", Hook, NextObj);
2733
2734 lResult = co_IntCallHookProc( Hook->HookId,
2735 HC_ACTION,
2736 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2737 (LPARAM)&CWP,
2738 Hook->Proc,
2739 Hook->ihmod,
2740 Hook->offPfn,
2741 Hook->Ansi,
2742 &Hook->ModuleName);
2743 }
2744 else
2745 {
2746 CWPRETSTRUCT CWPR;
2747 CWPR.hwnd = hWnd;
2748 CWPR.message = Msg;
2749 CWPR.wParam = wParam;
2750 CWPR.lParam = lParam;
2751 CWPR.lResult = ClientInfo->dwHookData;
2752
2753 lResult = co_IntCallHookProc( Hook->HookId,
2754 HC_ACTION,
2755 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2756 (LPARAM)&CWPR,
2757 Hook->Proc,
2758 Hook->ihmod,
2759 Hook->offPfn,
2760 Hook->Ansi,
2761 &Hook->ModuleName);
2762 }
2763 }
2764 break;
2765 }
2766
2767 switch(dwType)
2768 {
2769 case FNID_DEFWINDOWPROC:
2770 case FNID_CALLWNDPROC:
2771 case FNID_CALLWNDPROCRET:
2772 case FNID_SCROLLBAR:
2773 case FNID_DESKTOP:
2774 if (ResultInfo)
2775 {
2776 _SEH2_TRY
2777 {
2778 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2779 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2780 }
2781 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2782 {
2783 Ret = FALSE;
2784 }
2785 _SEH2_END;
2786 }
2787 break;
2788 default:
2789 break;
2790 }
2791
2792 UserLeave();
2793
2794 return Ret;
2795 }
2796
2797 #define INFINITE 0xFFFFFFFF
2798 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2799
2800 DWORD
2801 APIENTRY
2802 NtUserWaitForInputIdle( IN HANDLE hProcess,
2803 IN DWORD dwMilliseconds,
2804 IN BOOL Unknown2)
2805 {
2806 PEPROCESS Process;
2807 PPROCESSINFO W32Process;
2808 PTHREADINFO pti;
2809 NTSTATUS Status;
2810 HANDLE Handles[3];
2811 LARGE_INTEGER Timeout;
2812
2813 UserEnterExclusive();
2814
2815 Status = ObReferenceObjectByHandle(hProcess,
2816 PROCESS_QUERY_INFORMATION,
2817 PsProcessType,
2818 UserMode,
2819 (PVOID*)&Process,
2820 NULL);
2821
2822 if (!NT_SUCCESS(Status))
2823 {
2824 UserLeave();
2825 SetLastNtError(Status);
2826 return WAIT_FAILED;
2827 }
2828
2829 pti = PsGetCurrentThreadWin32Thread();
2830
2831 W32Process = (PPROCESSINFO)Process->Win32Process;
2832
2833 if ( PsGetProcessExitProcessCalled(Process) ||
2834 !W32Process ||
2835 pti->ppi == W32Process)
2836 {
2837 ObDereferenceObject(Process);
2838 UserLeave();
2839 EngSetLastError(ERROR_INVALID_PARAMETER);
2840 return WAIT_FAILED;
2841 }
2842
2843 Handles[0] = Process;
2844 Handles[1] = W32Process->InputIdleEvent;
2845 Handles[2] = pti->pEventQueueServer; // IntMsqSetWakeMask returns hEventQueueClient
2846
2847 if (!Handles[1])
2848 {
2849 ObDereferenceObject(Process);
2850 UserLeave();
2851 return STATUS_SUCCESS; /* no event to wait on */
2852 }
2853
2854 if (dwMilliseconds != INFINITE)
2855 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2856
2857 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2858 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2859 {
2860 pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2861 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2862 }
2863
2864 TRACE("WFII: ppi %p\n", W32Process);
2865 TRACE("WFII: waiting for %p\n", Handles[1] );
2866 do
2867 {
2868 UserLeave();
2869 Status = KeWaitForMultipleObjects( 3,
2870 Handles,
2871 WaitAny,
2872 UserRequest,
2873 UserMode,
2874 FALSE,
2875 dwMilliseconds == INFINITE ? NULL : &Timeout,
2876 NULL);
2877 UserEnterExclusive();
2878
2879 if (!NT_SUCCESS(Status))
2880 {
2881 SetLastNtError(Status);
2882 Status = WAIT_FAILED;
2883 goto WaitExit;
2884 }
2885
2886 switch (Status)
2887 {
2888 case STATUS_WAIT_0:
2889 goto WaitExit;
2890
2891 case STATUS_WAIT_2:
2892 {
2893 MSG Msg;
2894 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
2895 ERR("WFII: WAIT 2\n");
2896 }
2897 break;
2898
2899 case STATUS_TIMEOUT:
2900 ERR("WFII: timeout\n");
2901 case WAIT_FAILED:
2902 goto WaitExit;
2903
2904 default:
2905 ERR("WFII: finished\n");
2906 Status = STATUS_SUCCESS;
2907 goto WaitExit;
2908 }
2909 }
2910 while (TRUE);
2911
2912 WaitExit:
2913 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2914 {
2915 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
2916 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2917 }
2918 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
2919 ObDereferenceObject(Process);
2920 UserLeave();
2921 return Status;
2922 }
2923
2924 /* EOF */