xref: /reactos/win32ss/user/ntuser/message.c (revision 177ae91b)
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     PLARGE_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 = (PLARGE_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     LONG Time;
685     LRESULT retval = 0;
686     PTHREADINFO pti;
687     PWND Window = NULL;
688     BOOL DoCallBack = TRUE;
689 
690     if (pMsg->hwnd)
691     {
692         Window = UserGetWindowObject(pMsg->hwnd);
693         if (!Window) return 0;
694     }
695 
696     pti = PsGetCurrentThreadWin32Thread();
697 
698     if ( Window && Window->head.pti != pti)
699     {
700        EngSetLastError( ERROR_MESSAGE_SYNC_ONLY );
701        return 0;
702     }
703 
704     if (((pMsg->message == WM_SYSTIMER) ||
705          (pMsg->message == WM_TIMER)) &&
706          (pMsg->lParam) )
707     {
708         if (pMsg->message == WM_TIMER)
709         {
710             if (ValidateTimerCallback(pti,pMsg->lParam))
711             {
712                 Time = EngGetTickCount32();
713                 retval = co_IntCallWindowProc((WNDPROC)pMsg->lParam,
714                                               TRUE,
715                                               pMsg->hwnd,
716                                               WM_TIMER,
717                                               pMsg->wParam,
718                                               (LPARAM)Time,
719                                               -1);
720             }
721             return retval;
722         }
723         else
724         {
725             PTIMER pTimer = FindSystemTimer(pMsg);
726             if (pTimer && pTimer->pfn)
727             {
728                 Time = EngGetTickCount32();
729                 pTimer->pfn(pMsg->hwnd, WM_SYSTIMER, (UINT)pMsg->wParam, Time);
730             }
731             return 0;
732         }
733     }
734     // Need a window!
735     if ( !Window ) return 0;
736 
737     if (pMsg->message == WM_PAINT) Window->state |= WNDS_PAINTNOTPROCESSED;
738 
739     if ( Window->state & WNDS_SERVERSIDEWINDOWPROC )
740     {
741        TRACE("Dispatch: Server Side Window Procedure\n");
742        switch(Window->fnid)
743        {
744           case FNID_DESKTOP:
745             DoCallBack = !DesktopWindowProc( Window,
746                                              pMsg->message,
747                                              pMsg->wParam,
748                                              pMsg->lParam,
749                                             &retval);
750             break;
751           case FNID_MESSAGEWND:
752             DoCallBack = !UserMessageWindowProc( Window,
753                                                  pMsg->message,
754                                                  pMsg->wParam,
755                                                  pMsg->lParam,
756                                                 &retval);
757             break;
758           case FNID_MENU:
759             DoCallBack = !PopupMenuWndProc( Window,
760                                             pMsg->message,
761                                             pMsg->wParam,
762                                             pMsg->lParam,
763                                            &retval);
764             break;
765        }
766     }
767 
768     /* Since we are doing a callback on the same thread right away, there is
769        no need to copy the lparam to kernel mode and then back to usermode.
770        We just pretend it isn't a pointer */
771 
772     if (DoCallBack)
773     retval = co_IntCallWindowProc( Window->lpfnWndProc,
774                                    !Window->Unicode,
775                                    pMsg->hwnd,
776                                    pMsg->message,
777                                    pMsg->wParam,
778                                    pMsg->lParam,
779                                    -1);
780 
781     if ( pMsg->message == WM_PAINT &&
782          VerifyWnd(Window) &&
783          Window->state & WNDS_PAINTNOTPROCESSED ) // <--- Cleared, paint was already processed!
784     {
785         Window->state2 &= ~WNDS2_WMPAINTSENT;
786         /* send a WM_ERASEBKGND if the non-client area is still invalid */
787         ERR("Message WM_PAINT count %d Internal Paint Set? %s\n",Window->head.pti->cPaintsReady, Window->state & WNDS_INTERNALPAINT ? "TRUE" : "FALSE");
788         IntPaintWindow( Window );
789     }
790 
791     return retval;
792 }
793 
794 /*
795  * Internal version of PeekMessage() doing all the work
796  *
797  * MSDN:
798  *   Sent messages
799  *   Posted messages
800  *   Input (hardware) messages and system internal events
801  *   Sent messages (again)
802  *   WM_PAINT messages
803  *   WM_TIMER messages
804  */
805 BOOL APIENTRY
806 co_IntPeekMessage( PMSG Msg,
807                    PWND Window,
808                    UINT MsgFilterMin,
809                    UINT MsgFilterMax,
810                    UINT RemoveMsg,
811                    LONG_PTR *ExtraInfo,
812                    BOOL bGMSG )
813 {
814     PTHREADINFO pti;
815     BOOL RemoveMessages;
816     UINT ProcessMask;
817     BOOL Hit = FALSE;
818 
819     pti = PsGetCurrentThreadWin32Thread();
820 
821     RemoveMessages = RemoveMsg & PM_REMOVE;
822     ProcessMask = HIWORD(RemoveMsg);
823 
824  /* Hint, "If wMsgFilterMin and wMsgFilterMax are both zero, PeekMessage returns
825     all available messages (that is, no range filtering is performed)".        */
826     if (!ProcessMask) ProcessMask = (QS_ALLPOSTMESSAGE|QS_ALLINPUT);
827 
828     IdlePong();
829 
830     do
831     {
832         /* Update the last message-queue access time */
833         pti->pcti->timeLastRead = EngGetTickCount32();
834 
835         // Post mouse moves while looping through peek messages.
836         if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED)
837         {
838            IntCoalesceMouseMove(pti);
839         }
840 
841         /* Dispatch sent messages here. */
842         while ( co_MsqDispatchOneSentMessage(pti) )
843         {
844            /* if some PM_QS* flags were specified, only handle sent messages from now on */
845            if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE; // wine does this; ProcessMask = QS_SENDMESSAGE;
846         }
847         if (Hit) return FALSE;
848 
849         /* Clear changed bits so we can wait on them if we don't find a message */
850         if (ProcessMask & QS_POSTMESSAGE)
851         {
852            pti->pcti->fsChangeBits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER);
853            if (MsgFilterMin == 0 && MsgFilterMax == 0) // Wine hack does this; ~0U)
854            {
855               pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
856            }
857         }
858 
859         if (ProcessMask & QS_INPUT)
860         {
861            pti->pcti->fsChangeBits &= ~QS_INPUT;
862         }
863 
864         /* Now check for normal messages. */
865         if (( (ProcessMask & QS_POSTMESSAGE) ||
866               (ProcessMask & QS_HOTKEY) ) &&
867             MsqPeekMessage( pti,
868                             RemoveMessages,
869                             Window,
870                             MsgFilterMin,
871                             MsgFilterMax,
872                             ProcessMask,
873                             ExtraInfo,
874                             0,
875                             Msg ))
876         {
877             goto GotMessage;
878         }
879 
880         /* Only check for quit messages if not posted messages pending. */
881         if (ProcessMask & QS_POSTMESSAGE && pti->QuitPosted)
882         {
883             /* According to the PSDK, WM_QUIT messages are always returned, regardless
884                of the filter specified */
885             Msg->hwnd = NULL;
886             Msg->message = WM_QUIT;
887             Msg->wParam = pti->exitCode;
888             Msg->lParam = 0;
889             if (RemoveMessages)
890             {
891                 pti->QuitPosted = FALSE;
892                 ClearMsgBitsMask(pti, QS_POSTMESSAGE);
893                 pti->pcti->fsWakeBits &= ~QS_ALLPOSTMESSAGE;
894                 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
895             }
896             goto GotMessage;
897         }
898 
899         /* Check for hardware events. */
900         if ((ProcessMask & QS_INPUT) &&
901             co_MsqPeekHardwareMessage( pti,
902                                        RemoveMessages,
903                                        Window,
904                                        MsgFilterMin,
905                                        MsgFilterMax,
906                                        ProcessMask,
907                                        Msg))
908         {
909             goto GotMessage;
910         }
911 
912         /* Now check for System Event messages. */
913         {
914            LONG_PTR eExtraInfo;
915            MSG eMsg;
916            DWORD dwQEvent;
917            if (MsqPeekMessage( pti,
918                                TRUE,
919                                Window,
920                                0,
921                                0,
922                                QS_EVENT,
923                               &eExtraInfo,
924                               &dwQEvent,
925                               &eMsg ))
926            {
927               handle_internal_events( pti, Window, dwQEvent, eExtraInfo, &eMsg);
928               continue;
929            }
930         }
931 
932         /* Check for sent messages again. */
933         while ( co_MsqDispatchOneSentMessage(pti) )
934         {
935            if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE;
936         }
937         if (Hit) return FALSE;
938 
939         /* Check for paint messages. */
940         if ((ProcessMask & QS_PAINT) &&
941             pti->cPaintsReady &&
942             IntGetPaintMessage( Window,
943                                 MsgFilterMin,
944                                 MsgFilterMax,
945                                 pti,
946                                 Msg,
947                                 RemoveMessages))
948         {
949             goto GotMessage;
950         }
951 
952        /* This is correct, check for the current threads timers waiting to be
953           posted to this threads message queue. If any we loop again.
954         */
955         if ((ProcessMask & QS_TIMER) &&
956             PostTimerMessages(Window))
957         {
958             continue;
959         }
960 
961         return FALSE;
962     }
963     while (TRUE);
964 
965 GotMessage:
966     /* Update the last message-queue access time */
967     pti->pcti->timeLastRead = EngGetTickCount32();
968     return TRUE;
969 }
970 
971 BOOL FASTCALL
972 co_IntWaitMessage( PWND Window,
973                    UINT MsgFilterMin,
974                    UINT MsgFilterMax )
975 {
976     PTHREADINFO pti;
977     NTSTATUS Status = STATUS_SUCCESS;
978     MSG Msg;
979     LONG_PTR ExtraInfo = 0;
980 
981     pti = PsGetCurrentThreadWin32Thread();
982 
983     do
984     {
985         if ( co_IntPeekMessage( &Msg,       // Dont reenter!
986                                  Window,
987                                  MsgFilterMin,
988                                  MsgFilterMax,
989                                  MAKELONG( PM_NOREMOVE, GetWakeMask( MsgFilterMin, MsgFilterMax)),
990                                  &ExtraInfo,
991                                  TRUE ) )   // act like GetMessage.
992         {
993             return TRUE;
994         }
995 
996         /* Nothing found. Wait for new messages. */
997         Status = co_MsqWaitForNewMessages( pti,
998                                            Window,
999                                            MsgFilterMin,
1000                                            MsgFilterMax);
1001         if (!NT_SUCCESS(Status))
1002         {
1003             SetLastNtError(Status);
1004             ERR("Exit co_IntWaitMessage on error!\n");
1005             return FALSE;
1006         }
1007         if (Status == STATUS_USER_APC || Status == STATUS_TIMEOUT)
1008         {
1009            return FALSE;
1010         }
1011     }
1012     while ( TRUE );
1013 
1014     return FALSE;
1015 }
1016 
1017 BOOL APIENTRY
1018 co_IntGetPeekMessage( PMSG pMsg,
1019                       HWND hWnd,
1020                       UINT MsgFilterMin,
1021                       UINT MsgFilterMax,
1022                       UINT RemoveMsg,
1023                       BOOL bGMSG )
1024 {
1025     PWND Window;
1026     PTHREADINFO pti;
1027     BOOL Present = FALSE;
1028     NTSTATUS Status;
1029     LONG_PTR ExtraInfo = 0;
1030 
1031     if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST )
1032         hWnd = HWND_BOTTOM;
1033 
1034     /* Validate input */
1035     if (hWnd && hWnd != HWND_BOTTOM)
1036     {
1037         if (!(Window = UserGetWindowObject(hWnd)))
1038         {
1039             if (bGMSG)
1040                 return -1;
1041             else
1042                 return FALSE;
1043         }
1044     }
1045     else
1046     {
1047         Window = (PWND)hWnd;
1048     }
1049 
1050     if (MsgFilterMax < MsgFilterMin)
1051     {
1052         MsgFilterMin = 0;
1053         MsgFilterMax = 0;
1054     }
1055 
1056     if (bGMSG)
1057     {
1058        RemoveMsg |= ((GetWakeMask( MsgFilterMin, MsgFilterMax ))<< 16);
1059     }
1060 
1061     pti = PsGetCurrentThreadWin32Thread();
1062     pti->pClientInfo->cSpins++; // Bump up the spin count.
1063 
1064     do
1065     {
1066         Present = co_IntPeekMessage( pMsg,
1067                                      Window,
1068                                      MsgFilterMin,
1069                                      MsgFilterMax,
1070                                      RemoveMsg,
1071                                      &ExtraInfo,
1072                                      bGMSG );
1073         if (Present)
1074         {
1075            /* GetMessage or PostMessage must never get messages that contain pointers */
1076            ASSERT(FindMsgMemory(pMsg->message) == NULL);
1077 
1078            if ( pMsg->message >= WM_DDE_FIRST && pMsg->message <= WM_DDE_LAST )
1079            {
1080               if (!IntDdeGetMessageHook(pMsg, ExtraInfo))
1081               {
1082                  TRACE("DDE Get return ERROR\n");
1083                  continue;
1084               }
1085            }
1086 
1087            if (pMsg->message != WM_PAINT && pMsg->message != WM_QUIT)
1088            {
1089               if (!RtlEqualMemory(&pti->ptLast, &pMsg->pt, sizeof(POINT)))
1090               {
1091                  pti->TIF_flags |= TIF_MSGPOSCHANGED;
1092               }
1093               pti->timeLast = pMsg->time;
1094               pti->ptLast   = pMsg->pt;
1095            }
1096 
1097            // The WH_GETMESSAGE hook enables an application to monitor messages about to
1098            // be returned by the GetMessage or PeekMessage function.
1099 
1100            co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg);
1101 
1102            if ( bGMSG || pMsg->message == WM_PAINT) break;
1103         }
1104 
1105         if ( bGMSG )
1106         {
1107             Status = co_MsqWaitForNewMessages( pti,
1108                                                Window,
1109                                                MsgFilterMin,
1110                                                MsgFilterMax);
1111            if ( !NT_SUCCESS(Status) ||
1112                 Status == STATUS_USER_APC ||
1113                 Status == STATUS_TIMEOUT )
1114            {
1115               Present = -1;
1116               break;
1117            }
1118         }
1119         else
1120         {
1121            if (!(RemoveMsg & PM_NOYIELD))
1122            {
1123               IdlePing();
1124               // Yield this thread!
1125               UserLeave();
1126               ZwYieldExecution();
1127               UserEnterExclusive();
1128               // Fall through to exit.
1129               IdlePong();
1130            }
1131            break;
1132         }
1133     }
1134     while( bGMSG && !Present );
1135 
1136     // Been spinning, time to swap vinyl...
1137     if (pti->pClientInfo->cSpins >= 100)
1138     {
1139        // Clear the spin cycle to fix the mix.
1140        pti->pClientInfo->cSpins = 0;
1141        //if (!(pti->TIF_flags & TIF_SPINNING)) // FIXME: Need to swap vinyl...
1142     }
1143     return Present;
1144 }
1145 
1146 BOOL FASTCALL
1147 UserPostThreadMessage( PTHREADINFO pti,
1148                        UINT Msg,
1149                        WPARAM wParam,
1150                        LPARAM lParam )
1151 {
1152     MSG Message;
1153 
1154     if (is_pointer_message(Msg))
1155     {
1156         EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1157         return FALSE;
1158     }
1159     Message.hwnd = NULL;
1160     Message.message = Msg;
1161     Message.wParam = wParam;
1162     Message.lParam = lParam;
1163     Message.pt = gpsi->ptCursor;
1164     Message.time = EngGetTickCount32();
1165     MsqPostMessage(pti, &Message, FALSE, QS_POSTMESSAGE, 0, 0);
1166     return TRUE;
1167 }
1168 
1169 PTHREADINFO FASTCALL
1170 IntSendTo(PWND Window, PTHREADINFO ptiCur, UINT Msg)
1171 {
1172    if ( ptiCur )
1173    {
1174       if (!Window ||
1175            Window->head.pti == ptiCur )
1176       {
1177          return NULL;
1178       }
1179    }
1180    return Window ? Window->head.pti : NULL;
1181 }
1182 
1183 BOOL FASTCALL
1184 UserPostMessage( HWND Wnd,
1185                  UINT Msg,
1186                  WPARAM wParam,
1187                  LPARAM lParam )
1188 {
1189     PTHREADINFO pti;
1190     MSG Message;
1191     LONG_PTR ExtraInfo = 0;
1192 
1193     Message.hwnd = Wnd;
1194     Message.message = Msg;
1195     Message.wParam = wParam;
1196     Message.lParam = lParam;
1197     Message.pt = gpsi->ptCursor;
1198     Message.time = EngGetTickCount32();
1199 
1200     if (is_pointer_message(Message.message))
1201     {
1202         EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1203         return FALSE;
1204     }
1205 
1206     if (Wnd == HWND_BROADCAST || Wnd == HWND_TOPMOST)
1207     {
1208         HWND *List;
1209         PWND DesktopWindow;
1210         ULONG i;
1211 
1212         if (!is_message_broadcastable(Msg)) return TRUE;
1213 
1214         DesktopWindow = UserGetDesktopWindow();
1215         List = IntWinListChildren(DesktopWindow);
1216 
1217         if (List != NULL)
1218         {
1219             UserPostMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1220             for (i = 0; List[i]; i++)
1221             {
1222                 PWND pwnd = UserGetWindowObject(List[i]);
1223                 if (!pwnd) continue;
1224 
1225                 if ( pwnd->fnid == FNID_MENU || // Also need pwnd->pcls->atomClassName == gaOleMainThreadWndClass
1226                      pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
1227                    continue;
1228 
1229                 UserPostMessage(List[i], Msg, wParam, lParam);
1230             }
1231             ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1232         }
1233     }
1234     else
1235     {
1236         PWND Window;
1237 
1238         if (!Wnd)
1239         {
1240            return UserPostThreadMessage( gptiCurrent,
1241                                          Msg,
1242                                          wParam,
1243                                          lParam);
1244         }
1245 
1246         Window = UserGetWindowObject(Wnd);
1247         if ( !Window )
1248         {
1249             ERR("UserPostMessage: Invalid handle 0x%p Msg 0x%x!\n", Wnd, Msg);
1250             return FALSE;
1251         }
1252 
1253         pti = Window->head.pti;
1254 
1255         if ( pti->TIF_flags & TIF_INCLEANUP )
1256         {
1257             ERR("Attempted to post message to window %p when the thread is in cleanup!\n", Wnd);
1258             return FALSE;
1259         }
1260 
1261         if ( Window->state & WNDS_DESTROYED )
1262         {
1263             ERR("Attempted to post message to window %p that is being destroyed!\n", Wnd);
1264             /* FIXME: Last error code? */
1265             return FALSE;
1266         }
1267 
1268         if ( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST )
1269         {
1270            if (!IntDdePostMessageHook(Window, Msg, wParam, &lParam, &ExtraInfo))
1271            {
1272               TRACE("Posting Exit DDE 0x%x\n",Msg);
1273               return FALSE;
1274            }
1275            Message.lParam = lParam;
1276         }
1277 
1278         MsqPostMessage(pti, &Message, FALSE, QS_POSTMESSAGE, 0, ExtraInfo);
1279     }
1280     return TRUE;
1281 }
1282 
1283 LRESULT FASTCALL
1284 co_IntSendMessage( HWND hWnd,
1285                    UINT Msg,
1286                    WPARAM wParam,
1287                    LPARAM lParam )
1288 {
1289     ULONG_PTR Result = 0;
1290 
1291     if (co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1292     {
1293         return (LRESULT)Result;
1294     }
1295     return 0;
1296 }
1297 
1298 static LRESULT FASTCALL
1299 co_IntSendMessageTimeoutSingle( HWND hWnd,
1300                                 UINT Msg,
1301                                 WPARAM wParam,
1302                                 LPARAM lParam,
1303                                 UINT uFlags,
1304                                 UINT uTimeout,
1305                                 ULONG_PTR *uResult )
1306 {
1307     NTSTATUS Status = STATUS_SUCCESS;
1308     PWND Window = NULL;
1309     PMSGMEMORY MsgMemoryEntry;
1310     INT lParamBufferSize;
1311     LPARAM lParamPacked;
1312     PTHREADINFO Win32Thread, ptiSendTo = NULL;
1313     ULONG_PTR Result = 0;
1314     DECLARE_RETURN(LRESULT);
1315     USER_REFERENCE_ENTRY Ref;
1316     BOOL DoCallBack = TRUE;
1317 
1318     if (!(Window = UserGetWindowObject(hWnd)))
1319     {
1320         TRACE("SendMessageTimeoutSingle: Invalid handle 0x%p!\n",hWnd);
1321         RETURN( FALSE);
1322     }
1323 
1324     UserRefObjectCo(Window, &Ref);
1325 
1326     Win32Thread = PsGetCurrentThreadWin32Thread();
1327 
1328     ptiSendTo = IntSendTo(Window, Win32Thread, Msg);
1329 
1330     if ( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST )
1331     {
1332        if (!IntDdeSendMessageHook(Window, Msg, wParam, lParam))
1333        {
1334           ERR("Sending Exit DDE 0x%x\n",Msg);
1335           RETURN( FALSE);
1336        }
1337     }
1338 
1339     if ( !ptiSendTo )
1340     {
1341         if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1342         {
1343             /* Never send messages to exiting threads */
1344             RETURN( FALSE);
1345         }
1346 
1347         if (Msg & 0x80000000)
1348         {
1349            TRACE("SMTS: Internal Message!\n");
1350            Result = (ULONG_PTR)handle_internal_message( Window, Msg, wParam, lParam );
1351            if (uResult) *uResult = Result;
1352            RETURN( TRUE);
1353         }
1354 
1355         // Only happens when calling the client!
1356         IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1357 
1358         if ( Window->state & WNDS_SERVERSIDEWINDOWPROC )
1359         {
1360            TRACE("SMT: Server Side Window Procedure\n");
1361            // Handle it here. Safeguard against excessive recursions.
1362            if (IoGetRemainingStackSize() < PAGE_SIZE)
1363            {
1364               ERR("Server Callback Exceeded Stack!\n");
1365               RETURN( FALSE);
1366            }
1367            /* Return after server side call, IntCallWndProcRet will not be called. */
1368            switch(Window->fnid)
1369            {
1370               case FNID_DESKTOP:
1371                 DoCallBack = !DesktopWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result);
1372                 break;
1373               case FNID_MESSAGEWND:
1374                 DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result);
1375                 break;
1376               case FNID_MENU:
1377                 DoCallBack = !PopupMenuWndProc( Window, Msg, wParam, lParam,(LRESULT*)&Result);
1378                 break;
1379            }
1380            if (!DoCallBack)
1381            {
1382               if (uResult) *uResult = Result;
1383               RETURN( TRUE);
1384            }
1385         }
1386         /* See if this message type is present in the table */
1387         MsgMemoryEntry = FindMsgMemory(Msg);
1388         if (NULL == MsgMemoryEntry)
1389         {
1390            lParamBufferSize = -1;
1391         }
1392         else
1393         {
1394            lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1395            // If zero, do not allow callback on client side to allocate a buffer!!!!! See CORE-7695.
1396            if (!lParamBufferSize) lParamBufferSize = -1;
1397         }
1398 
1399         if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
1400         {
1401            ERR("Failed to pack message parameters\n");
1402            RETURN( FALSE);
1403         }
1404 
1405         Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1406                                                   !Window->Unicode,
1407                                                   hWnd,
1408                                                   Msg,
1409                                                   wParam,
1410                                                   lParamPacked,
1411                                                   lParamBufferSize );
1412         if (uResult)
1413         {
1414             *uResult = Result;
1415         }
1416 
1417         if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1418         {
1419             ERR("Failed to unpack message parameters\n");
1420             RETURN( TRUE);
1421         }
1422 
1423         // Only happens when calling the client!
1424         IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1425 
1426         RETURN( TRUE);
1427     }
1428 
1429     if (Window->state & WNDS_DESTROYED)
1430     {
1431         /* FIXME: Last error? */
1432         ERR("Attempted to send message to window %p that is being destroyed!\n", hWnd);
1433         RETURN( FALSE);
1434     }
1435 
1436     if ((uFlags & SMTO_ABORTIFHUNG) && MsqIsHung(ptiSendTo, 4 * MSQ_HUNG))
1437     {
1438         // FIXME: Set window hung and add to a list.
1439         /* FIXME: Set a LastError? */
1440         ERR("Window %p (%p) (pti %p) is hung!\n", hWnd, Window, ptiSendTo);
1441         RETURN( FALSE);
1442     }
1443 
1444     do
1445     {
1446         Status = co_MsqSendMessage( ptiSendTo,
1447                                     hWnd,
1448                                     Msg,
1449                                     wParam,
1450                                     lParam,
1451                                     uTimeout,
1452                                     (uFlags & SMTO_BLOCK),
1453                                     MSQ_NORMAL,
1454                                     uResult );
1455     }
1456     while ((Status == STATUS_TIMEOUT) &&
1457            (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1458            !MsqIsHung(ptiSendTo, MSQ_HUNG)); // FIXME: Set window hung and add to a list.
1459 
1460     if (Status == STATUS_TIMEOUT)
1461     {
1462         if (0 && MsqIsHung(ptiSendTo, MSQ_HUNG))
1463         {
1464             TRACE("Let's go Ghost!\n");
1465             IntMakeHungWindowGhosted(hWnd);
1466         }
1467 /*
1468  *  MSDN says:
1469  *  Microsoft Windows 2000: If GetLastError returns zero, then the function
1470  *  timed out.
1471  *  XP+ : If the function fails or times out, the return value is zero.
1472  *  To get extended error information, call GetLastError. If GetLastError
1473  *  returns ERROR_TIMEOUT, then the function timed out.
1474  */
1475         EngSetLastError(ERROR_TIMEOUT);
1476         RETURN( FALSE);
1477     }
1478     else if (!NT_SUCCESS(Status))
1479     {
1480         SetLastNtError(Status);
1481         RETURN( FALSE);
1482     }
1483 
1484     RETURN( TRUE);
1485 
1486 CLEANUP:
1487     if (Window) UserDerefObjectCo(Window);
1488     END_CLEANUP;
1489 }
1490 
1491 LRESULT FASTCALL
1492 co_IntSendMessageTimeout( HWND hWnd,
1493                           UINT Msg,
1494                           WPARAM wParam,
1495                           LPARAM lParam,
1496                           UINT uFlags,
1497                           UINT uTimeout,
1498                           ULONG_PTR *uResult )
1499 {
1500     PWND DesktopWindow;
1501     HWND *Children;
1502     HWND *Child;
1503 
1504     if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST)
1505     {
1506         return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1507     }
1508 
1509     if (!is_message_broadcastable(Msg)) return TRUE;
1510 
1511     DesktopWindow = UserGetDesktopWindow();
1512     if (NULL == DesktopWindow)
1513     {
1514        EngSetLastError(ERROR_INTERNAL_ERROR);
1515        return 0;
1516     }
1517 
1518     if (hWnd != HWND_TOPMOST)
1519     {
1520        /* Send message to the desktop window too! */
1521        co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1522     }
1523 
1524     Children = IntWinListChildren(DesktopWindow);
1525     if (NULL == Children)
1526     {
1527         return 0;
1528     }
1529 
1530     for (Child = Children; NULL != *Child; Child++)
1531     {
1532         PWND pwnd = UserGetWindowObject(*Child);
1533         if (!pwnd) continue;
1534 
1535         if ( pwnd->fnid == FNID_MENU ||
1536              pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
1537            continue;
1538 
1539         co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1540     }
1541 
1542     ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
1543 
1544     return (LRESULT) TRUE;
1545 }
1546 
1547 LRESULT FASTCALL
1548 co_IntSendMessageNoWait(HWND hWnd,
1549                         UINT Msg,
1550                         WPARAM wParam,
1551                         LPARAM lParam)
1552 {
1553     ULONG_PTR Result = 0;
1554     return co_IntSendMessageWithCallBack( hWnd,
1555                                           Msg,
1556                                           wParam,
1557                                           lParam,
1558                                           NULL,
1559                                           0,
1560                                          &Result);
1561 }
1562 /* MSDN:
1563    If you send a message in the range below WM_USER to the asynchronous message
1564    functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its
1565    message parameters cannot include pointers. Otherwise, the operation will fail.
1566    The functions will return before the receiving thread has had a chance to
1567    process the message and the sender will free the memory before it is used.
1568 */
1569 LRESULT FASTCALL
1570 co_IntSendMessageWithCallBack( HWND hWnd,
1571                               UINT Msg,
1572                               WPARAM wParam,
1573                               LPARAM lParam,
1574                               SENDASYNCPROC CompletionCallback,
1575                               ULONG_PTR CompletionCallbackContext,
1576                               ULONG_PTR *uResult)
1577 {
1578     ULONG_PTR Result;
1579     PWND Window = NULL;
1580     PMSGMEMORY MsgMemoryEntry;
1581     INT lParamBufferSize;
1582     LPARAM lParamPacked;
1583     PTHREADINFO Win32Thread, ptiSendTo = NULL;
1584     DECLARE_RETURN(LRESULT);
1585     USER_REFERENCE_ENTRY Ref;
1586     PUSER_SENT_MESSAGE Message;
1587     BOOL DoCallBack = TRUE;
1588 
1589     if (!(Window = UserGetWindowObject(hWnd)))
1590     {
1591         TRACE("SendMessageWithCallBack: Invalid handle 0x%p!\n",hWnd);
1592         RETURN(FALSE);
1593     }
1594 
1595     UserRefObjectCo(Window, &Ref);
1596 
1597     if (Window->state & WNDS_DESTROYED)
1598     {
1599         /* FIXME: last error? */
1600         ERR("Attempted to send message to window %p that is being destroyed!\n", hWnd);
1601         RETURN(FALSE);
1602     }
1603 
1604     Win32Thread = PsGetCurrentThreadWin32Thread();
1605 
1606     if (Win32Thread == NULL ||
1607         Win32Thread->TIF_flags & TIF_INCLEANUP)
1608     {
1609         RETURN(FALSE);
1610     }
1611 
1612     ptiSendTo = IntSendTo(Window, Win32Thread, Msg);
1613 
1614     if (Msg & 0x80000000 &&
1615         !ptiSendTo)
1616     {
1617        if (Win32Thread->TIF_flags & TIF_INCLEANUP) RETURN( FALSE);
1618 
1619        TRACE("SMWCB: Internal Message!\n");
1620        Result = (ULONG_PTR)handle_internal_message( Window, Msg, wParam, lParam );
1621        if (uResult) *uResult = Result;
1622        RETURN( TRUE);
1623     }
1624 
1625     /* See if this message type is present in the table */
1626     MsgMemoryEntry = FindMsgMemory(Msg);
1627     if (NULL == MsgMemoryEntry)
1628     {
1629         lParamBufferSize = -1;
1630     }
1631     else
1632     {
1633         lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1634         if (!lParamBufferSize) lParamBufferSize = -1;
1635     }
1636 
1637     if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, !!ptiSendTo)))
1638     {
1639         ERR("Failed to pack message parameters\n");
1640         RETURN( FALSE);
1641     }
1642 
1643     /* If it can be sent now, then send it. */
1644     if ( !ptiSendTo )
1645     {
1646         if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1647         {
1648             UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE);
1649             /* Never send messages to exiting threads */
1650             RETURN(FALSE);
1651         }
1652 
1653         IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1654 
1655         if ( Window->state & WNDS_SERVERSIDEWINDOWPROC )
1656         {
1657            TRACE("SMWCB: Server Side Window Procedure\n");
1658            switch(Window->fnid)
1659            {
1660               case FNID_DESKTOP:
1661                 DoCallBack = !DesktopWindowProc(Window, Msg, wParam, lParamPacked, (LRESULT*)&Result);
1662                 break;
1663               case FNID_MESSAGEWND:
1664                 DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result);
1665                 break;
1666               case FNID_MENU:
1667                 DoCallBack = !PopupMenuWndProc( Window, Msg, wParam, lParam,(LRESULT*)&Result);
1668                 break;
1669            }
1670         }
1671 
1672         if (DoCallBack)
1673         Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1674                                                   !Window->Unicode,
1675                                                   hWnd,
1676                                                   Msg,
1677                                                   wParam,
1678                                                   lParamPacked,
1679                                                   lParamBufferSize );
1680         if(uResult)
1681         {
1682             *uResult = Result;
1683         }
1684 
1685         IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1686 
1687         if (CompletionCallback)
1688         {
1689             co_IntCallSentMessageCallback(CompletionCallback,
1690                                           hWnd,
1691                                           Msg,
1692                                           CompletionCallbackContext,
1693                                           Result);
1694         }
1695     }
1696 
1697     if ( !ptiSendTo)
1698     {
1699         if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1700         {
1701             ERR("Failed to unpack message parameters\n");
1702         }
1703         RETURN(TRUE);
1704     }
1705 
1706     if(!(Message = AllocateUserMessage(FALSE)))
1707     {
1708         ERR("MsqSendMessage(): Not enough memory to allocate a message");
1709         RETURN( FALSE);
1710     }
1711 
1712     Message->Msg.hwnd = hWnd;
1713     Message->Msg.message = Msg;
1714     Message->Msg.wParam = wParam;
1715     Message->Msg.lParam = lParamPacked;
1716     Message->pkCompletionEvent = NULL; // No event needed.
1717     Message->lResult = 0;
1718     Message->QS_Flags = 0;
1719     Message->ptiReceiver = ptiSendTo;
1720     Message->ptiSender = NULL; // mjmartin, you are right! This is null.
1721     Message->ptiCallBackSender = Win32Thread;
1722     Message->CompletionCallback = CompletionCallback;
1723     Message->CompletionCallbackContext = CompletionCallbackContext;
1724     Message->HookMessage = MSQ_NORMAL;
1725     Message->HasPackedLParam = (lParamBufferSize > 0);
1726     Message->QS_Flags = QS_SENDMESSAGE;
1727     Message->flags = SMF_RECEIVERFREE;
1728 
1729     if (Msg & 0x80000000) // Higher priority event message!
1730        InsertHeadList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry);
1731     else
1732        InsertTailList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry);
1733     MsqWakeQueue(ptiSendTo, QS_SENDMESSAGE, TRUE);
1734 
1735     RETURN(TRUE);
1736 
1737 CLEANUP:
1738     if (Window) UserDerefObjectCo(Window);
1739     END_CLEANUP;
1740 }
1741 
1742 #if 0
1743 /*
1744   This HACK function posts a message if the destination's message queue belongs to
1745   another thread, otherwise it sends the message. It does not support broadcast
1746   messages!
1747 */
1748 LRESULT FASTCALL
1749 co_IntPostOrSendMessage( HWND hWnd,
1750                          UINT Msg,
1751                          WPARAM wParam,
1752                          LPARAM lParam )
1753 {
1754     ULONG_PTR Result;
1755     PTHREADINFO pti;
1756     PWND Window;
1757 
1758     if ( hWnd == HWND_BROADCAST )
1759     {
1760         return 0;
1761     }
1762 
1763     if(!(Window = UserGetWindowObject(hWnd)))
1764     {
1765         TRACE("PostOrSendMessage: Invalid handle 0x%p!\n",hWnd);
1766         return 0;
1767     }
1768 
1769     pti = PsGetCurrentThreadWin32Thread();
1770 
1771     if ( IntSendTo(Window, pti, Msg) &&
1772          FindMsgMemory(Msg) == 0 )
1773     {
1774         Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1775     }
1776     else
1777     {
1778         if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1779         {
1780             Result = 0;
1781         }
1782     }
1783 
1784     return (LRESULT)Result;
1785 }
1786 #endif
1787 
1788 static LRESULT FASTCALL
1789 co_IntDoSendMessage( HWND hWnd,
1790                      UINT Msg,
1791                      WPARAM wParam,
1792                      LPARAM lParam,
1793                      PDOSENDMESSAGE dsm)
1794 {
1795     LRESULT Result = TRUE;
1796     NTSTATUS Status;
1797     PWND Window = NULL;
1798     MSG UserModeMsg, KernelModeMsg;
1799     PMSGMEMORY MsgMemoryEntry;
1800     PTHREADINFO ptiSendTo;
1801 
1802     if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST)
1803     {
1804         Window = UserGetWindowObject(hWnd);
1805         if ( !Window )
1806         {
1807             return 0;
1808         }
1809     }
1810 
1811     /* Check for an exiting window. */
1812     if (Window && Window->state & WNDS_DESTROYED)
1813     {
1814         ERR("co_IntDoSendMessage Window Exiting!\n");
1815     }
1816 
1817     /* See if the current thread can handle this message */
1818     ptiSendTo = IntSendTo(Window, gptiCurrent, Msg);
1819 
1820     // If broadcasting or sending to another thread, save the users data.
1821     if (!Window || ptiSendTo )
1822     {
1823        UserModeMsg.hwnd    = hWnd;
1824        UserModeMsg.message = Msg;
1825        UserModeMsg.wParam  = wParam;
1826        UserModeMsg.lParam  = lParam;
1827        MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1828        Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1829        if (!NT_SUCCESS(Status))
1830        {
1831           EngSetLastError(ERROR_INVALID_PARAMETER);
1832           return (dsm ? 0 : -1);
1833        }
1834     }
1835     else
1836     {
1837        KernelModeMsg.hwnd    = hWnd;
1838        KernelModeMsg.message = Msg;
1839        KernelModeMsg.wParam  = wParam;
1840        KernelModeMsg.lParam  = lParam;
1841     }
1842 
1843     if (!dsm)
1844     {
1845        Result = co_IntSendMessage( KernelModeMsg.hwnd,
1846                                    KernelModeMsg.message,
1847                                    KernelModeMsg.wParam,
1848                                    KernelModeMsg.lParam );
1849     }
1850     else
1851     {
1852        Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1853                                           KernelModeMsg.message,
1854                                           KernelModeMsg.wParam,
1855                                           KernelModeMsg.lParam,
1856                                           dsm->uFlags,
1857                                           dsm->uTimeout,
1858                                          &dsm->Result );
1859     }
1860 
1861     if (!Window || ptiSendTo )
1862     {
1863        Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1864        if (!NT_SUCCESS(Status))
1865        {
1866           EngSetLastError(ERROR_INVALID_PARAMETER);
1867           return(dsm ? 0 : -1);
1868        }
1869     }
1870 
1871     return (LRESULT)Result;
1872 }
1873 
1874 BOOL FASTCALL
1875 UserSendNotifyMessage( HWND hWnd,
1876                        UINT Msg,
1877                        WPARAM wParam,
1878                        LPARAM lParam )
1879 {
1880     BOOL Ret = TRUE;
1881 
1882     if (is_pointer_message(Msg))
1883     {
1884         EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1885         return FALSE;
1886     }
1887 
1888     // Basicly the same as IntPostOrSendMessage
1889     if (hWnd == HWND_BROADCAST) // Handle Broadcast
1890     {
1891         HWND *List;
1892         PWND DesktopWindow;
1893         ULONG i;
1894 
1895         DesktopWindow = UserGetDesktopWindow();
1896         List = IntWinListChildren(DesktopWindow);
1897 
1898         if (List != NULL)
1899         {
1900             UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1901             for (i = 0; List[i]; i++)
1902             {
1903                PWND pwnd = UserGetWindowObject(List[i]);
1904                if (!pwnd) continue;
1905 
1906                if ( pwnd->fnid == FNID_MENU ||
1907                     pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
1908                   continue;
1909 
1910                Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1911             }
1912             ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1913         }
1914     }
1915     else
1916     {
1917         Ret = co_IntSendMessageNoWait( hWnd, Msg, wParam, lParam);
1918     }
1919     return Ret;
1920 }
1921 
1922 
1923 DWORD APIENTRY
1924 IntGetQueueStatus(DWORD Changes)
1925 {
1926     PTHREADINFO pti;
1927     DWORD Result;
1928 
1929     pti = PsGetCurrentThreadWin32Thread();
1930 // wine:
1931     Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1932 
1933     /* High word, types of messages currently in the queue.
1934        Low  word, types of messages that have been added to the queue and that
1935                   are still in the queue
1936      */
1937     Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
1938 
1939     pti->pcti->fsChangeBits &= ~Changes;
1940 
1941     return Result;
1942 }
1943 
1944 BOOL APIENTRY
1945 IntInitMessagePumpHook(VOID)
1946 {
1947     PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1948 
1949     if (pti->pcti)
1950     {
1951         pti->pcti->dwcPumpHook++;
1952         return TRUE;
1953     }
1954     return FALSE;
1955 }
1956 
1957 BOOL APIENTRY
1958 IntUninitMessagePumpHook(VOID)
1959 {
1960     PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1961 
1962     if (pti->pcti)
1963     {
1964         if (pti->pcti->dwcPumpHook <= 0)
1965         {
1966             return FALSE;
1967         }
1968         pti->pcti->dwcPumpHook--;
1969         return TRUE;
1970     }
1971     return FALSE;
1972 }
1973 
1974 BOOL FASTCALL
1975 IntCallMsgFilter( LPMSG lpmsg, INT code)
1976 {
1977     BOOL Ret = FALSE;
1978 
1979     if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)lpmsg))
1980     {
1981         Ret = TRUE;
1982     }
1983     else
1984     {
1985         Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)lpmsg);
1986     }
1987     return Ret;
1988 }
1989 
1990 /** Functions ******************************************************************/
1991 
1992 BOOL
1993 APIENTRY
1994 NtUserDragDetect(
1995    HWND hWnd,
1996    POINT pt) // Just like the User call.
1997 {
1998     MSG msg;
1999     RECT rect;
2000     ULONG wDragWidth, wDragHeight;
2001     DECLARE_RETURN(BOOL);
2002 
2003     TRACE("Enter NtUserDragDetect(%p)\n", hWnd);
2004     UserEnterExclusive();
2005 
2006     wDragWidth = UserGetSystemMetrics(SM_CXDRAG);
2007     wDragHeight= UserGetSystemMetrics(SM_CYDRAG);
2008 
2009     rect.left = pt.x - wDragWidth;
2010     rect.right = pt.x + wDragWidth;
2011 
2012     rect.top = pt.y - wDragHeight;
2013     rect.bottom = pt.y + wDragHeight;
2014 
2015     co_UserSetCapture(hWnd);
2016 
2017     for (;;)
2018     {
2019         while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) ||
2020                co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC,  WM_QUEUESYNC, PM_REMOVE, FALSE ) ||
2021                co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST,   WM_KEYLAST,   PM_REMOVE, FALSE ) )
2022         {
2023             if ( msg.message == WM_LBUTTONUP )
2024             {
2025                 co_UserSetCapture(NULL);
2026                 RETURN( FALSE);
2027             }
2028             if ( msg.message == WM_MOUSEMOVE )
2029             {
2030                 POINT tmp;
2031                 tmp.x = (short)LOWORD(msg.lParam);
2032                 tmp.y = (short)HIWORD(msg.lParam);
2033                 if( !RECTL_bPointInRect( &rect, tmp.x, tmp.y ) )
2034                 {
2035                     co_UserSetCapture(NULL);
2036                     RETURN( TRUE);
2037                 }
2038             }
2039             if ( msg.message == WM_KEYDOWN )
2040             {
2041                 if ( msg.wParam == VK_ESCAPE )
2042                 {
2043                    co_UserSetCapture(NULL);
2044                    RETURN( TRUE);
2045                 }
2046             }
2047             if ( msg.message == WM_QUEUESYNC )
2048             {
2049                 co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 );
2050             }
2051         }
2052         co_IntWaitMessage(NULL, 0, 0);
2053     }
2054     RETURN( FALSE);
2055 
2056 CLEANUP:
2057    TRACE("Leave NtUserDragDetect, ret=%i\n",_ret_);
2058    UserLeave();
2059    END_CLEANUP;
2060 }
2061 
2062 BOOL APIENTRY
2063 NtUserPostMessage(HWND hWnd,
2064                   UINT Msg,
2065                   WPARAM wParam,
2066                   LPARAM lParam)
2067 {
2068     BOOL ret;
2069 
2070     UserEnterExclusive();
2071 
2072     ret = UserPostMessage(hWnd, Msg, wParam, lParam);
2073 
2074     UserLeave();
2075 
2076     return ret;
2077 }
2078 
2079 BOOL APIENTRY
2080 NtUserPostThreadMessage(DWORD idThread,
2081                         UINT Msg,
2082                         WPARAM wParam,
2083                         LPARAM lParam)
2084 {
2085     BOOL ret = FALSE;
2086     PETHREAD peThread;
2087     PTHREADINFO pThread;
2088     NTSTATUS Status;
2089 
2090     UserEnterExclusive();
2091 
2092     Status = PsLookupThreadByThreadId(UlongToHandle(idThread), &peThread);
2093 
2094     if ( Status == STATUS_SUCCESS )
2095     {
2096         pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
2097         if( !pThread ||
2098             !pThread->MessageQueue ||
2099             (pThread->TIF_flags & TIF_INCLEANUP))
2100         {
2101             ObDereferenceObject( peThread );
2102             goto exit;
2103         }
2104         ret = UserPostThreadMessage( pThread, Msg, wParam, lParam);
2105         ObDereferenceObject( peThread );
2106     }
2107     else
2108     {
2109         SetLastNtError( Status );
2110     }
2111 exit:
2112     UserLeave();
2113     return ret;
2114 }
2115 
2116 BOOL APIENTRY
2117 NtUserWaitMessage(VOID)
2118 {
2119     BOOL ret;
2120 
2121     UserEnterExclusive();
2122     TRACE("NtUserWaitMessage Enter\n");
2123     ret = co_IntWaitMessage(NULL, 0, 0);
2124     TRACE("NtUserWaitMessage Leave\n");
2125     UserLeave();
2126 
2127     return ret;
2128 }
2129 
2130 BOOL APIENTRY
2131 NtUserGetMessage(PMSG pMsg,
2132                   HWND hWnd,
2133                   UINT MsgFilterMin,
2134                   UINT MsgFilterMax )
2135 {
2136     MSG Msg;
2137     BOOL Ret;
2138 
2139     if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
2140     {
2141         EngSetLastError(ERROR_INVALID_PARAMETER);
2142         return FALSE;
2143     }
2144 
2145     UserEnterExclusive();
2146 
2147     RtlZeroMemory(&Msg, sizeof(MSG));
2148 
2149     Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
2150 
2151     UserLeave();
2152 
2153     if (Ret)
2154     {
2155         _SEH2_TRY
2156         {
2157             ProbeForWrite(pMsg, sizeof(MSG), 1);
2158             RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2159         }
2160         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2161         {
2162             SetLastNtError(_SEH2_GetExceptionCode());
2163             Ret = FALSE;
2164         }
2165         _SEH2_END;
2166     }
2167 
2168     if ((INT)Ret != -1)
2169        Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE;
2170 
2171     return Ret;
2172 }
2173 
2174 BOOL APIENTRY
2175 NtUserPeekMessage( PMSG pMsg,
2176                   HWND hWnd,
2177                   UINT MsgFilterMin,
2178                   UINT MsgFilterMax,
2179                   UINT RemoveMsg)
2180 {
2181     MSG Msg;
2182     BOOL Ret;
2183 
2184     if ( RemoveMsg & PM_BADMSGFLAGS )
2185     {
2186         EngSetLastError(ERROR_INVALID_FLAGS);
2187         return FALSE;
2188     }
2189 
2190     UserEnterExclusive();
2191 
2192     RtlZeroMemory(&Msg, sizeof(MSG));
2193 
2194     Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
2195 
2196     UserLeave();
2197 
2198     if (Ret)
2199     {
2200         _SEH2_TRY
2201         {
2202             ProbeForWrite(pMsg, sizeof(MSG), 1);
2203             RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2204         }
2205         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2206         {
2207             SetLastNtError(_SEH2_GetExceptionCode());
2208             Ret = FALSE;
2209         }
2210         _SEH2_END;
2211     }
2212 
2213     return Ret;
2214 }
2215 
2216 BOOL APIENTRY
2217 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
2218 {
2219     BOOL Ret = FALSE;
2220     MSG Msg;
2221 
2222     _SEH2_TRY
2223     {
2224         ProbeForRead(lpmsg, sizeof(MSG), 1);
2225         RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
2226     }
2227     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2228     {
2229         _SEH2_YIELD(return FALSE);
2230     }
2231     _SEH2_END;
2232 
2233     UserEnterExclusive();
2234 
2235     if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
2236     {
2237         Ret = TRUE;
2238     }
2239     else
2240     {
2241         Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
2242     }
2243 
2244     UserLeave();
2245 
2246     _SEH2_TRY
2247     {
2248         ProbeForWrite(lpmsg, sizeof(MSG), 1);
2249         RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
2250     }
2251     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2252     {
2253         Ret = FALSE;
2254     }
2255     _SEH2_END;
2256 
2257     return Ret;
2258 }
2259 
2260 LRESULT APIENTRY
2261 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
2262 {
2263     LRESULT Res = 0;
2264     MSG SafeMsg;
2265 
2266     _SEH2_TRY
2267     {
2268         ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
2269         RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
2270     }
2271     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2272     {
2273         SetLastNtError(_SEH2_GetExceptionCode());
2274         _SEH2_YIELD(return FALSE);
2275     }
2276     _SEH2_END;
2277 
2278     UserEnterExclusive();
2279 
2280     Res = IntDispatchMessage(&SafeMsg);
2281 
2282     UserLeave();
2283     return Res;
2284 }
2285 
2286 BOOL APIENTRY
2287 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
2288 {
2289     MSG SafeMsg;
2290     BOOL Ret;
2291     PWND pWnd;
2292 
2293     _SEH2_TRY
2294     {
2295         ProbeForRead(lpMsg, sizeof(MSG), 1);
2296         RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
2297     }
2298     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2299     {
2300         SetLastNtError(_SEH2_GetExceptionCode());
2301         _SEH2_YIELD(return FALSE);
2302     }
2303     _SEH2_END;
2304 
2305     UserEnterExclusive();
2306     pWnd = UserGetWindowObject(SafeMsg.hwnd);
2307     if (pWnd) // Must have a window!
2308     {
2309        Ret = IntTranslateKbdMessage(&SafeMsg, flags);
2310     }
2311     else
2312     {
2313         TRACE("No Window for Translate. hwnd 0x%p Msg %u\n", SafeMsg.hwnd, SafeMsg.message);
2314         Ret = FALSE;
2315     }
2316     UserLeave();
2317 
2318     return Ret;
2319 }
2320 
2321 LRESULT APIENTRY ScrollBarWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam);
2322 
2323 BOOL APIENTRY
2324 NtUserMessageCall( HWND hWnd,
2325                    UINT Msg,
2326                    WPARAM wParam,
2327                    LPARAM lParam,
2328                    ULONG_PTR ResultInfo,
2329                    DWORD dwType, // fnID?
2330                    BOOL Ansi)
2331 {
2332     LRESULT lResult = 0;
2333     BOOL Ret = FALSE;
2334     PWND Window = NULL;
2335     USER_REFERENCE_ENTRY Ref;
2336 
2337     UserEnterExclusive();
2338 
2339     switch(dwType)
2340     {
2341     case FNID_SCROLLBAR:
2342         {
2343            lResult = ScrollBarWndProc(hWnd, Msg, wParam, lParam);
2344            break;
2345         }
2346     case FNID_DESKTOP:
2347         {
2348            Window = UserGetWindowObject(hWnd);
2349            if (Window)
2350            {
2351               //ERR("FNID_DESKTOP IN\n");
2352               Ret = DesktopWindowProc(Window, Msg, wParam, lParam, &lResult);
2353               //ERR("FNID_DESKTOP OUT\n");
2354            }
2355            break;
2356         }
2357    case FNID_MENU:
2358        {
2359           Window = UserGetWindowObject(hWnd);
2360           if (Window)
2361           {
2362               Ret = PopupMenuWndProc( Window, Msg, wParam, lParam, &lResult);
2363           }
2364           break;
2365        }
2366    case FNID_MESSAGEWND:
2367        {
2368            Window = UserGetWindowObject(hWnd);
2369            if (Window)
2370            {
2371                 Ret = !UserMessageWindowProc(Window, Msg, wParam, lParam, &lResult);
2372            }
2373            break;
2374        }
2375     case FNID_DEFWINDOWPROC:
2376         /* Validate input */
2377         if (hWnd)
2378         {
2379            Window = UserGetWindowObject(hWnd);
2380            if (!Window)
2381            {
2382                UserLeave();
2383                return FALSE;
2384            }
2385            UserRefObjectCo(Window, &Ref);
2386         }
2387         lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2388         Ret = TRUE;
2389         if (hWnd)
2390             UserDerefObjectCo(Window);
2391         break;
2392     case FNID_SENDNOTIFYMESSAGE:
2393         Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2394         break;
2395     case FNID_BROADCASTSYSTEMMESSAGE:
2396         {
2397             BROADCASTPARM parm, *retparam;
2398             DWORD_PTR RetVal = 0;
2399 
2400             if (ResultInfo)
2401             {
2402                 _SEH2_TRY
2403                 {
2404                     ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
2405                     RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2406                 }
2407                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2408                 {
2409                     _SEH2_YIELD(break);
2410                 }
2411                 _SEH2_END;
2412             }
2413             else
2414                 break;
2415 
2416             if ( parm.recipients & BSM_ALLDESKTOPS ||
2417                  parm.recipients == BSM_ALLCOMPONENTS )
2418             {
2419                PLIST_ENTRY DesktopEntry;
2420                PDESKTOP rpdesk;
2421                HWND *List, hwndDenied = NULL;
2422                HDESK hDesk = NULL;
2423                PWND pwnd, pwndDesk;
2424                ULONG i;
2425                UINT fuFlags;
2426 
2427                for (DesktopEntry = InputWindowStation->DesktopListHead.Flink;
2428                     DesktopEntry != &InputWindowStation->DesktopListHead;
2429                     DesktopEntry = DesktopEntry->Flink)
2430                {
2431                   rpdesk = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
2432                   pwndDesk = rpdesk->pDeskInfo->spwnd;
2433                   List = IntWinListChildren(pwndDesk);
2434 
2435                   if (parm.flags & BSF_QUERY)
2436                   {
2437                      if (List != NULL)
2438                      {
2439                         if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2440                         {
2441                            fuFlags = SMTO_ABORTIFHUNG;
2442                         }
2443                         else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2444                         {
2445                            fuFlags = SMTO_NOTIMEOUTIFNOTHUNG;
2446                         }
2447                         else
2448                         {
2449                            fuFlags = SMTO_NORMAL;
2450                         }
2451                         co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk),
2452                                                   Msg,
2453                                                   wParam,
2454                                                   lParam,
2455                                                   fuFlags,
2456                                                   2000,
2457                                                  &RetVal);
2458                         Ret = TRUE;
2459                         for (i = 0; List[i]; i++)
2460                         {
2461                            pwnd = UserGetWindowObject(List[i]);
2462                            if (!pwnd) continue;
2463 
2464                            if ( pwnd->fnid == FNID_MENU ||
2465                                 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2466                               continue;
2467 
2468                            if ( parm.flags & BSF_IGNORECURRENTTASK )
2469                            {
2470                               if ( pwnd->head.pti == gptiCurrent )
2471                                  continue;
2472                            }
2473                            co_IntSendMessageTimeout( List[i],
2474                                                      Msg,
2475                                                      wParam,
2476                                                      lParam,
2477                                                      fuFlags,
2478                                                      2000,
2479                                                     &RetVal);
2480 
2481                            if (!RetVal && EngGetLastError() == ERROR_TIMEOUT)
2482                            {
2483                               if (!(parm.flags & BSF_FORCEIFHUNG))
2484                                  Ret = FALSE;
2485                            }
2486                            if (RetVal == BROADCAST_QUERY_DENY)
2487                            {
2488                               hwndDenied = List[i];
2489                               hDesk = UserHMGetHandle(pwndDesk);
2490                               Ret = FALSE;
2491                            }
2492                         }
2493                         ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2494                         _SEH2_TRY
2495                         {
2496                            retparam = (PBROADCASTPARM) ResultInfo;
2497                            retparam->hDesk = hDesk;
2498                            retparam->hWnd = hwndDenied;
2499                         }
2500                         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2501                         {
2502                            _SEH2_YIELD(break);
2503                         }
2504                         _SEH2_END;
2505                         if (!Ret) break; // Have a hit! Let everyone know!
2506                      }
2507                   }
2508                   else if (parm.flags & BSF_POSTMESSAGE)
2509                   {
2510                      if (List != NULL)
2511                      {
2512                         UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2513 
2514                         for (i = 0; List[i]; i++)
2515                         {
2516                            pwnd = UserGetWindowObject(List[i]);
2517                            if (!pwnd) continue;
2518 
2519                            if ( pwnd->fnid == FNID_MENU ||
2520                                 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2521                               continue;
2522 
2523                            if ( parm.flags & BSF_IGNORECURRENTTASK )
2524                            {
2525                               if ( pwnd->head.pti == gptiCurrent )
2526                                  continue;
2527                            }
2528                            UserPostMessage(List[i], Msg, wParam, lParam);
2529                         }
2530                         ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2531                      }
2532                      Ret = TRUE;
2533                   }
2534                   else
2535                   {
2536                      if (List != NULL)
2537                      {
2538                         UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2539 
2540                         for (i = 0; List[i]; i++)
2541                         {
2542                            pwnd = UserGetWindowObject(List[i]);
2543                            if (!pwnd) continue;
2544 
2545                            if ( pwnd->fnid == FNID_MENU ||
2546                                 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2547                               continue;
2548 
2549                            if ( parm.flags & BSF_IGNORECURRENTTASK )
2550                            {
2551                               if ( pwnd->head.pti == gptiCurrent )
2552                                  continue;
2553                            }
2554                            UserSendNotifyMessage(List[i], Msg, wParam, lParam);
2555                         }
2556                         ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2557                      }
2558                      Ret = TRUE;
2559                   }
2560                }
2561             }
2562             else if (parm.recipients & BSM_APPLICATIONS)
2563             {
2564                HWND *List, hwndDenied = NULL;
2565                HDESK hDesk = NULL;
2566                PWND pwnd, pwndDesk;
2567                ULONG i;
2568                UINT fuFlags;
2569 
2570                pwndDesk = UserGetDesktopWindow();
2571                List = IntWinListChildren(pwndDesk);
2572 
2573                if (parm.flags & BSF_QUERY)
2574                {
2575                   if (List != NULL)
2576                   {
2577                      if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2578                      {
2579                         fuFlags = SMTO_ABORTIFHUNG;
2580                      }
2581                      else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2582                      {
2583                         fuFlags = SMTO_NOTIMEOUTIFNOTHUNG;
2584                      }
2585                      else
2586                      {
2587                         fuFlags = SMTO_NORMAL;
2588                      }
2589                      co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk),
2590                                                Msg,
2591                                                wParam,
2592                                                lParam,
2593                                                fuFlags,
2594                                                2000,
2595                                               &RetVal);
2596                      Ret = TRUE;
2597                      for (i = 0; List[i]; i++)
2598                      {
2599                         pwnd = UserGetWindowObject(List[i]);
2600                         if (!pwnd) continue;
2601 
2602                         if ( pwnd->fnid == FNID_MENU ||
2603                              pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2604                            continue;
2605 
2606                         if ( parm.flags & BSF_IGNORECURRENTTASK )
2607                         {
2608                            if ( pwnd->head.pti == gptiCurrent )
2609                               continue;
2610                         }
2611                         co_IntSendMessageTimeout( List[i],
2612                                                   Msg,
2613                                                   wParam,
2614                                                   lParam,
2615                                                   fuFlags,
2616                                                   2000,
2617                                                  &RetVal);
2618 
2619                         if (!RetVal && EngGetLastError() == ERROR_TIMEOUT)
2620                         {
2621                            if (!(parm.flags & BSF_FORCEIFHUNG))
2622                               Ret = FALSE;
2623                         }
2624                         if (RetVal == BROADCAST_QUERY_DENY)
2625                         {
2626                            hwndDenied = List[i];
2627                            hDesk = UserHMGetHandle(pwndDesk);
2628                            Ret = FALSE;
2629                         }
2630                      }
2631                      ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2632                      _SEH2_TRY
2633                      {
2634                         retparam = (PBROADCASTPARM) ResultInfo;
2635                         retparam->hDesk = hDesk;
2636                         retparam->hWnd = hwndDenied;
2637                      }
2638                      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2639                      {
2640                         _SEH2_YIELD(break);
2641                      }
2642                      _SEH2_END;
2643                   }
2644                }
2645                else if (parm.flags & BSF_POSTMESSAGE)
2646                {
2647                   if (List != NULL)
2648                   {
2649                      UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2650 
2651                      for (i = 0; List[i]; i++)
2652                      {
2653                         pwnd = UserGetWindowObject(List[i]);
2654                         if (!pwnd) continue;
2655 
2656                         if ( pwnd->fnid == FNID_MENU ||
2657                              pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2658                            continue;
2659 
2660                         if ( parm.flags & BSF_IGNORECURRENTTASK )
2661                         {
2662                            if ( pwnd->head.pti == gptiCurrent )
2663                               continue;
2664                         }
2665                         UserPostMessage(List[i], Msg, wParam, lParam);
2666                      }
2667                      ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2668                   }
2669                   Ret = TRUE;
2670                }
2671                else
2672                {
2673                   if (List != NULL)
2674                   {
2675                      UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2676 
2677                      for (i = 0; List[i]; i++)
2678                      {
2679                         pwnd = UserGetWindowObject(List[i]);
2680                         if (!pwnd) continue;
2681 
2682                         if ( pwnd->fnid == FNID_MENU ||
2683                              pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2684                            continue;
2685 
2686                         if ( parm.flags & BSF_IGNORECURRENTTASK )
2687                         {
2688                            if ( pwnd->head.pti == gptiCurrent )
2689                               continue;
2690                         }
2691                         UserSendNotifyMessage(List[i], Msg, wParam, lParam);
2692                      }
2693                      ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2694                   }
2695                   Ret = TRUE;
2696                }
2697             }
2698         }
2699         break;
2700     case FNID_SENDMESSAGECALLBACK:
2701         {
2702             CALL_BACK_INFO CallBackInfo;
2703             ULONG_PTR uResult;
2704 
2705             _SEH2_TRY
2706             {
2707                 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
2708                 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
2709             }
2710             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2711             {
2712                 _SEH2_YIELD(break);
2713             }
2714             _SEH2_END;
2715 
2716             if (is_pointer_message(Msg))
2717             {
2718                EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
2719                break;
2720             }
2721 
2722             if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2723                         CallBackInfo.CallBack, CallBackInfo.Context, &uResult)))
2724             {
2725                 ERR("Callback failure!\n");
2726             }
2727         }
2728         break;
2729     case FNID_SENDMESSAGE:
2730         {
2731             lResult = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
2732             Ret = TRUE;
2733 
2734             if (ResultInfo)
2735             {
2736                 _SEH2_TRY
2737                 {
2738                     ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
2739                     RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(ULONG_PTR));
2740                 }
2741                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2742                 {
2743                     Ret = FALSE;
2744                     _SEH2_YIELD(break);
2745                 }
2746                 _SEH2_END;
2747             }
2748             break;
2749         }
2750     case FNID_SENDMESSAGEFF:
2751     case FNID_SENDMESSAGEWTOOPTION:
2752         {
2753             DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
2754             if (ResultInfo)
2755             {
2756                 _SEH2_TRY
2757                 {
2758                     ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
2759                     RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
2760                 }
2761                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2762                 {
2763                     _SEH2_YIELD(break);
2764                 }
2765                 _SEH2_END;
2766             }
2767 
2768             Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, pdsm ? &dsm : NULL );
2769 
2770             if (pdsm)
2771             {
2772                 _SEH2_TRY
2773                 {
2774                     ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
2775                     RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2776                 }
2777                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2778                 {
2779                     Ret = FALSE;
2780                     _SEH2_YIELD(break);
2781                 }
2782                 _SEH2_END;
2783             }
2784             break;
2785         }
2786         // CallNextHook bypass.
2787     case FNID_CALLWNDPROC:
2788     case FNID_CALLWNDPROCRET:
2789         {
2790             PTHREADINFO pti;
2791             PCLIENTINFO ClientInfo;
2792             PHOOK NextObj, Hook;
2793 
2794             pti = GetW32ThreadInfo();
2795 
2796             Hook = pti->sphkCurrent;
2797 
2798             if (!Hook) break;
2799 
2800             NextObj = Hook->phkNext;
2801             ClientInfo = pti->pClientInfo;
2802             _SEH2_TRY
2803             {
2804                 ClientInfo->phkCurrent = NextObj;
2805             }
2806             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2807             {
2808                 ClientInfo = NULL;
2809             }
2810             _SEH2_END;
2811 
2812             if (!ClientInfo || !NextObj) break;
2813 
2814             NextObj->phkNext = IntGetNextHook(NextObj);
2815 
2816             if ( Hook->HookId == WH_CALLWNDPROC)
2817             {
2818                 CWPSTRUCT CWP;
2819                 CWP.hwnd    = hWnd;
2820                 CWP.message = Msg;
2821                 CWP.wParam  = wParam;
2822                 CWP.lParam  = lParam;
2823                 TRACE("WH_CALLWNDPROC: Hook %p NextHook %p\n", Hook, NextObj);
2824 
2825                 lResult = co_IntCallHookProc( Hook->HookId,
2826                                               HC_ACTION,
2827                                               ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2828                                               (LPARAM)&CWP,
2829                                               Hook->Proc,
2830                                               Hook->ihmod,
2831                                               Hook->offPfn,
2832                                               Hook->Ansi,
2833                                               &Hook->ModuleName);
2834             }
2835             else
2836             {
2837                 CWPRETSTRUCT CWPR;
2838                 CWPR.hwnd    = hWnd;
2839                 CWPR.message = Msg;
2840                 CWPR.wParam  = wParam;
2841                 CWPR.lParam  = lParam;
2842                 CWPR.lResult = ClientInfo->dwHookData;
2843 
2844                 lResult = co_IntCallHookProc( Hook->HookId,
2845                                               HC_ACTION,
2846                                               ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2847                                               (LPARAM)&CWPR,
2848                                               Hook->Proc,
2849                                               Hook->ihmod,
2850                                               Hook->offPfn,
2851                                               Hook->Ansi,
2852                                               &Hook->ModuleName);
2853             }
2854         }
2855         break;
2856     }
2857 
2858     switch(dwType)
2859     {
2860     case FNID_DEFWINDOWPROC:
2861     case FNID_CALLWNDPROC:
2862     case FNID_CALLWNDPROCRET:
2863     case FNID_SCROLLBAR:
2864     case FNID_DESKTOP:
2865     case FNID_MENU:
2866         if (ResultInfo)
2867         {
2868             _SEH2_TRY
2869             {
2870                 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2871                 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2872             }
2873             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2874             {
2875                 Ret = FALSE;
2876             }
2877             _SEH2_END;
2878         }
2879         break;
2880     default:
2881         break;
2882     }
2883 
2884     UserLeave();
2885 
2886     return Ret;
2887 }
2888 
2889 #define INFINITE 0xFFFFFFFF
2890 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2891 
2892 DWORD
2893 APIENTRY
2894 NtUserWaitForInputIdle( IN HANDLE hProcess,
2895                         IN DWORD dwMilliseconds,
2896                         IN BOOL Unknown2)
2897 {
2898     PEPROCESS Process;
2899     PPROCESSINFO W32Process;
2900     PTHREADINFO pti;
2901     NTSTATUS Status;
2902     HANDLE Handles[3];
2903     LARGE_INTEGER Timeout;
2904     KAPC_STATE ApcState;
2905 
2906     UserEnterExclusive();
2907 
2908     Status = ObReferenceObjectByHandle(hProcess,
2909                                        PROCESS_QUERY_INFORMATION,
2910                                        *PsProcessType,
2911                                        UserMode,
2912                                        (PVOID*)&Process,
2913                                        NULL);
2914 
2915     if (!NT_SUCCESS(Status))
2916     {
2917         UserLeave();
2918         SetLastNtError(Status);
2919         return WAIT_FAILED;
2920     }
2921 
2922     pti = PsGetCurrentThreadWin32Thread();
2923 
2924     W32Process = (PPROCESSINFO)Process->Win32Process;
2925 
2926     if ( PsGetProcessExitProcessCalled(Process) ||
2927          !W32Process ||
2928          pti->ppi == W32Process)
2929     {
2930         ObDereferenceObject(Process);
2931         UserLeave();
2932         EngSetLastError(ERROR_INVALID_PARAMETER);
2933         return WAIT_FAILED;
2934     }
2935 
2936     Handles[0] = Process;
2937     Handles[1] = W32Process->InputIdleEvent;
2938     Handles[2] = pti->pEventQueueServer; // IntMsqSetWakeMask returns hEventQueueClient
2939 
2940     if (!Handles[1])
2941     {
2942         ObDereferenceObject(Process);
2943         UserLeave();
2944         return STATUS_SUCCESS;  /* no event to wait on */
2945     }
2946 
2947     if (dwMilliseconds != INFINITE)
2948        Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2949 
2950     KeStackAttachProcess(&Process->Pcb, &ApcState);
2951 
2952     W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2953     for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2954     {
2955        pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2956        pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2957     }
2958 
2959     KeUnstackDetachProcess(&ApcState);
2960 
2961     TRACE("WFII: ppi %p\n", W32Process);
2962     TRACE("WFII: waiting for %p\n", Handles[1] );
2963 
2964     /*
2965      * We must add a refcount to our current PROCESSINFO,
2966      * because anything could happen (including process death) we're leaving win32k
2967      */
2968     IntReferenceProcessInfo(W32Process);
2969 
2970     do
2971     {
2972         UserLeave();
2973         Status = KeWaitForMultipleObjects( 3,
2974                                            Handles,
2975                                            WaitAny,
2976                                            UserRequest,
2977                                            UserMode,
2978                                            FALSE,
2979                                            dwMilliseconds == INFINITE ? NULL : &Timeout,
2980                                            NULL);
2981         UserEnterExclusive();
2982 
2983         if (!NT_SUCCESS(Status))
2984         {
2985             SetLastNtError(Status);
2986             Status = WAIT_FAILED;
2987             goto WaitExit;
2988         }
2989 
2990         switch (Status)
2991         {
2992         case STATUS_WAIT_0:
2993             goto WaitExit;
2994 
2995         case STATUS_WAIT_2:
2996             {
2997                MSG Msg;
2998                co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
2999                ERR("WFII: WAIT 2\n");
3000             }
3001             break;
3002 
3003         case STATUS_TIMEOUT:
3004             ERR("WFII: timeout\n");
3005         case WAIT_FAILED:
3006             goto WaitExit;
3007 
3008         default:
3009             ERR("WFII: finished\n");
3010             Status = STATUS_SUCCESS;
3011             goto WaitExit;
3012         }
3013     }
3014     while (TRUE);
3015 
3016 WaitExit:
3017     for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
3018     {
3019        pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
3020        pti->pClientInfo->dwTIFlags = pti->TIF_flags;
3021     }
3022     W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
3023     IntDereferenceProcessInfo(W32Process);
3024     ObDereferenceObject(Process);
3025     UserLeave();
3026     return Status;
3027 }
3028 
3029 /* EOF */
3030