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