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