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