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