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