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