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