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