[CMAKE] Zap builddir.h.cmake and instead define macros globally
[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 PUNICODE_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 = (PUNICODE_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 (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(ptiSendTo))
1437 {
1438 // FIXME: Set window hung and add to a list.
1439 /* FIXME: Set a LastError? */
1440 RETURN( FALSE);
1441 }
1442
1443 if (Window->state & WNDS_DESTROYED)
1444 {
1445 /* FIXME: Last error? */
1446 ERR("Attempted to send message to window %p that is being destroyed!\n", hWnd);
1447 RETURN( FALSE);
1448 }
1449
1450 do
1451 {
1452 Status = co_MsqSendMessage( ptiSendTo,
1453 hWnd,
1454 Msg,
1455 wParam,
1456 lParam,
1457 uTimeout,
1458 (uFlags & SMTO_BLOCK),
1459 MSQ_NORMAL,
1460 uResult );
1461 }
1462 while ((STATUS_TIMEOUT == Status) &&
1463 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1464 !MsqIsHung(ptiSendTo)); // FIXME: Set window hung and add to a list.
1465
1466 if (Status == STATUS_TIMEOUT)
1467 {
1468 /*
1469 * MSDN says:
1470 * Microsoft Windows 2000: If GetLastError returns zero, then the function
1471 * timed out.
1472 * XP+ : If the function fails or times out, the return value is zero.
1473 * To get extended error information, call GetLastError. If GetLastError
1474 * returns ERROR_TIMEOUT, then the function timed out.
1475 */
1476 EngSetLastError(ERROR_TIMEOUT);
1477 RETURN( FALSE);
1478 }
1479 else if (!NT_SUCCESS(Status))
1480 {
1481 SetLastNtError(Status);
1482 RETURN( FALSE);
1483 }
1484
1485 RETURN( TRUE);
1486
1487 CLEANUP:
1488 if (Window) UserDerefObjectCo(Window);
1489 END_CLEANUP;
1490 }
1491
1492 LRESULT FASTCALL
1493 co_IntSendMessageTimeout( HWND hWnd,
1494 UINT Msg,
1495 WPARAM wParam,
1496 LPARAM lParam,
1497 UINT uFlags,
1498 UINT uTimeout,
1499 ULONG_PTR *uResult )
1500 {
1501 PWND DesktopWindow;
1502 HWND *Children;
1503 HWND *Child;
1504
1505 if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST)
1506 {
1507 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1508 }
1509
1510 if (!is_message_broadcastable(Msg)) return TRUE;
1511
1512 DesktopWindow = UserGetDesktopWindow();
1513 if (NULL == DesktopWindow)
1514 {
1515 EngSetLastError(ERROR_INTERNAL_ERROR);
1516 return 0;
1517 }
1518
1519 if (hWnd != HWND_TOPMOST)
1520 {
1521 /* Send message to the desktop window too! */
1522 co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1523 }
1524
1525 Children = IntWinListChildren(DesktopWindow);
1526 if (NULL == Children)
1527 {
1528 return 0;
1529 }
1530
1531 for (Child = Children; NULL != *Child; Child++)
1532 {
1533 PWND pwnd = UserGetWindowObject(*Child);
1534 if (!pwnd) continue;
1535
1536 if ( pwnd->fnid == FNID_MENU ||
1537 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
1538 continue;
1539
1540 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1541 }
1542
1543 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
1544
1545 return (LRESULT) TRUE;
1546 }
1547
1548 LRESULT FASTCALL
1549 co_IntSendMessageNoWait(HWND hWnd,
1550 UINT Msg,
1551 WPARAM wParam,
1552 LPARAM lParam)
1553 {
1554 ULONG_PTR Result = 0;
1555 return co_IntSendMessageWithCallBack( hWnd,
1556 Msg,
1557 wParam,
1558 lParam,
1559 NULL,
1560 0,
1561 &Result);
1562 }
1563 /* MSDN:
1564 If you send a message in the range below WM_USER to the asynchronous message
1565 functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its
1566 message parameters cannot include pointers. Otherwise, the operation will fail.
1567 The functions will return before the receiving thread has had a chance to
1568 process the message and the sender will free the memory before it is used.
1569 */
1570 LRESULT FASTCALL
1571 co_IntSendMessageWithCallBack( HWND hWnd,
1572 UINT Msg,
1573 WPARAM wParam,
1574 LPARAM lParam,
1575 SENDASYNCPROC CompletionCallback,
1576 ULONG_PTR CompletionCallbackContext,
1577 ULONG_PTR *uResult)
1578 {
1579 ULONG_PTR Result;
1580 PWND Window = NULL;
1581 PMSGMEMORY MsgMemoryEntry;
1582 INT lParamBufferSize;
1583 LPARAM lParamPacked;
1584 PTHREADINFO Win32Thread, ptiSendTo = NULL;
1585 DECLARE_RETURN(LRESULT);
1586 USER_REFERENCE_ENTRY Ref;
1587 PUSER_SENT_MESSAGE Message;
1588 BOOL DoCallBack = TRUE;
1589
1590 if (!(Window = UserGetWindowObject(hWnd)))
1591 {
1592 TRACE("SendMessageWithCallBack: Invalid handle 0x%p!\n",hWnd);
1593 RETURN(FALSE);
1594 }
1595
1596 UserRefObjectCo(Window, &Ref);
1597
1598 if (Window->state & WNDS_DESTROYED)
1599 {
1600 /* FIXME: last error? */
1601 ERR("Attempted to send message to window %p that is being destroyed!\n", hWnd);
1602 RETURN(FALSE);
1603 }
1604
1605 Win32Thread = PsGetCurrentThreadWin32Thread();
1606
1607 if (Win32Thread == NULL ||
1608 Win32Thread->TIF_flags & TIF_INCLEANUP)
1609 {
1610 RETURN(FALSE);
1611 }
1612
1613 ptiSendTo = IntSendTo(Window, Win32Thread, Msg);
1614
1615 if (Msg & 0x80000000 &&
1616 !ptiSendTo)
1617 {
1618 if (Win32Thread->TIF_flags & TIF_INCLEANUP) RETURN( FALSE);
1619
1620 TRACE("SMWCB: Internal Message!\n");
1621 Result = (ULONG_PTR)handle_internal_message( Window, Msg, wParam, lParam );
1622 if (uResult) *uResult = Result;
1623 RETURN( TRUE);
1624 }
1625
1626 /* See if this message type is present in the table */
1627 MsgMemoryEntry = FindMsgMemory(Msg);
1628 if (NULL == MsgMemoryEntry)
1629 {
1630 lParamBufferSize = -1;
1631 }
1632 else
1633 {
1634 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1635 if (!lParamBufferSize) lParamBufferSize = -1;
1636 }
1637
1638 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, !!ptiSendTo)))
1639 {
1640 ERR("Failed to pack message parameters\n");
1641 RETURN( FALSE);
1642 }
1643
1644 /* If it can be sent now, then send it. */
1645 if ( !ptiSendTo )
1646 {
1647 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1648 {
1649 UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE);
1650 /* Never send messages to exiting threads */
1651 RETURN(FALSE);
1652 }
1653
1654 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1655
1656 if ( Window->state & WNDS_SERVERSIDEWINDOWPROC )
1657 {
1658 TRACE("SMWCB: Server Side Window Procedure\n");
1659 switch(Window->fnid)
1660 {
1661 case FNID_DESKTOP:
1662 DoCallBack = !DesktopWindowProc(Window, Msg, wParam, lParamPacked, (LRESULT*)&Result);
1663 break;
1664 case FNID_MESSAGEWND:
1665 DoCallBack = !UserMessageWindowProc(Window, Msg, wParam, lParam,(LRESULT*)&Result);
1666 break;
1667 case FNID_MENU:
1668 DoCallBack = !PopupMenuWndProc( Window, Msg, wParam, lParam,(LRESULT*)&Result);
1669 break;
1670 }
1671 }
1672
1673 if (DoCallBack)
1674 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1675 !Window->Unicode,
1676 hWnd,
1677 Msg,
1678 wParam,
1679 lParamPacked,
1680 lParamBufferSize );
1681 if(uResult)
1682 {
1683 *uResult = Result;
1684 }
1685
1686 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1687
1688 if (CompletionCallback)
1689 {
1690 co_IntCallSentMessageCallback(CompletionCallback,
1691 hWnd,
1692 Msg,
1693 CompletionCallbackContext,
1694 Result);
1695 }
1696 }
1697
1698 if ( !ptiSendTo)
1699 {
1700 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1701 {
1702 ERR("Failed to unpack message parameters\n");
1703 }
1704 RETURN(TRUE);
1705 }
1706
1707 if(!(Message = AllocateUserMessage(FALSE)))
1708 {
1709 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1710 RETURN( FALSE);
1711 }
1712
1713 Message->Msg.hwnd = hWnd;
1714 Message->Msg.message = Msg;
1715 Message->Msg.wParam = wParam;
1716 Message->Msg.lParam = lParamPacked;
1717 Message->pkCompletionEvent = NULL; // No event needed.
1718 Message->lResult = 0;
1719 Message->QS_Flags = 0;
1720 Message->ptiReceiver = ptiSendTo;
1721 Message->ptiSender = NULL; // mjmartin, you are right! This is null.
1722 Message->ptiCallBackSender = Win32Thread;
1723 Message->CompletionCallback = CompletionCallback;
1724 Message->CompletionCallbackContext = CompletionCallbackContext;
1725 Message->HookMessage = MSQ_NORMAL;
1726 Message->HasPackedLParam = (lParamBufferSize > 0);
1727 Message->QS_Flags = QS_SENDMESSAGE;
1728 Message->flags = SMF_RECEIVERFREE;
1729
1730 if (Msg & 0x80000000) // Higher priority event message!
1731 InsertHeadList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry);
1732 else
1733 InsertTailList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry);
1734 MsqWakeQueue(ptiSendTo, QS_SENDMESSAGE, TRUE);
1735
1736 RETURN(TRUE);
1737
1738 CLEANUP:
1739 if (Window) UserDerefObjectCo(Window);
1740 END_CLEANUP;
1741 }
1742
1743 #if 0
1744 /*
1745 This HACK function posts a message if the destination's message queue belongs to
1746 another thread, otherwise it sends the message. It does not support broadcast
1747 messages!
1748 */
1749 LRESULT FASTCALL
1750 co_IntPostOrSendMessage( HWND hWnd,
1751 UINT Msg,
1752 WPARAM wParam,
1753 LPARAM lParam )
1754 {
1755 ULONG_PTR Result;
1756 PTHREADINFO pti;
1757 PWND Window;
1758
1759 if ( hWnd == HWND_BROADCAST )
1760 {
1761 return 0;
1762 }
1763
1764 if(!(Window = UserGetWindowObject(hWnd)))
1765 {
1766 TRACE("PostOrSendMessage: Invalid handle 0x%p!\n",hWnd);
1767 return 0;
1768 }
1769
1770 pti = PsGetCurrentThreadWin32Thread();
1771
1772 if ( IntSendTo(Window, pti, Msg) &&
1773 FindMsgMemory(Msg) == 0 )
1774 {
1775 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1776 }
1777 else
1778 {
1779 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1780 {
1781 Result = 0;
1782 }
1783 }
1784
1785 return (LRESULT)Result;
1786 }
1787 #endif
1788
1789 static LRESULT FASTCALL
1790 co_IntDoSendMessage( HWND hWnd,
1791 UINT Msg,
1792 WPARAM wParam,
1793 LPARAM lParam,
1794 PDOSENDMESSAGE dsm)
1795 {
1796 LRESULT Result = TRUE;
1797 NTSTATUS Status;
1798 PWND Window = NULL;
1799 MSG UserModeMsg, KernelModeMsg;
1800 PMSGMEMORY MsgMemoryEntry;
1801 PTHREADINFO ptiSendTo;
1802
1803 if (hWnd != HWND_BROADCAST && hWnd != HWND_TOPMOST)
1804 {
1805 Window = UserGetWindowObject(hWnd);
1806 if ( !Window )
1807 {
1808 return 0;
1809 }
1810 }
1811
1812 /* Check for an exiting window. */
1813 if (Window && Window->state & WNDS_DESTROYED)
1814 {
1815 ERR("co_IntDoSendMessage Window Exiting!\n");
1816 }
1817
1818 /* See if the current thread can handle this message */
1819 ptiSendTo = IntSendTo(Window, gptiCurrent, Msg);
1820
1821 // If broadcasting or sending to another thread, save the users data.
1822 if (!Window || ptiSendTo )
1823 {
1824 UserModeMsg.hwnd = hWnd;
1825 UserModeMsg.message = Msg;
1826 UserModeMsg.wParam = wParam;
1827 UserModeMsg.lParam = lParam;
1828 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1829 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1830 if (!NT_SUCCESS(Status))
1831 {
1832 EngSetLastError(ERROR_INVALID_PARAMETER);
1833 return (dsm ? 0 : -1);
1834 }
1835 }
1836 else
1837 {
1838 KernelModeMsg.hwnd = hWnd;
1839 KernelModeMsg.message = Msg;
1840 KernelModeMsg.wParam = wParam;
1841 KernelModeMsg.lParam = lParam;
1842 }
1843
1844 if (!dsm)
1845 {
1846 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1847 KernelModeMsg.message,
1848 KernelModeMsg.wParam,
1849 KernelModeMsg.lParam );
1850 }
1851 else
1852 {
1853 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1854 KernelModeMsg.message,
1855 KernelModeMsg.wParam,
1856 KernelModeMsg.lParam,
1857 dsm->uFlags,
1858 dsm->uTimeout,
1859 &dsm->Result );
1860 }
1861
1862 if (!Window || ptiSendTo )
1863 {
1864 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1865 if (!NT_SUCCESS(Status))
1866 {
1867 EngSetLastError(ERROR_INVALID_PARAMETER);
1868 return(dsm ? 0 : -1);
1869 }
1870 }
1871
1872 return (LRESULT)Result;
1873 }
1874
1875 BOOL FASTCALL
1876 UserSendNotifyMessage( HWND hWnd,
1877 UINT Msg,
1878 WPARAM wParam,
1879 LPARAM lParam )
1880 {
1881 BOOL Ret = TRUE;
1882
1883 if (is_pointer_message(Msg))
1884 {
1885 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1886 return FALSE;
1887 }
1888
1889 // Basicly the same as IntPostOrSendMessage
1890 if (hWnd == HWND_BROADCAST) // Handle Broadcast
1891 {
1892 HWND *List;
1893 PWND DesktopWindow;
1894 ULONG i;
1895
1896 DesktopWindow = UserGetDesktopWindow();
1897 List = IntWinListChildren(DesktopWindow);
1898
1899 if (List != NULL)
1900 {
1901 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1902 for (i = 0; List[i]; i++)
1903 {
1904 PWND pwnd = UserGetWindowObject(List[i]);
1905 if (!pwnd) continue;
1906
1907 if ( pwnd->fnid == FNID_MENU ||
1908 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
1909 continue;
1910
1911 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1912 }
1913 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1914 }
1915 }
1916 else
1917 {
1918 Ret = co_IntSendMessageNoWait( hWnd, Msg, wParam, lParam);
1919 }
1920 return Ret;
1921 }
1922
1923
1924 DWORD APIENTRY
1925 IntGetQueueStatus(DWORD Changes)
1926 {
1927 PTHREADINFO pti;
1928 DWORD Result;
1929
1930 pti = PsGetCurrentThreadWin32Thread();
1931 // wine:
1932 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1933
1934 /* High word, types of messages currently in the queue.
1935 Low word, types of messages that have been added to the queue and that
1936 are still in the queue
1937 */
1938 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
1939
1940 pti->pcti->fsChangeBits &= ~Changes;
1941
1942 return Result;
1943 }
1944
1945 BOOL APIENTRY
1946 IntInitMessagePumpHook(VOID)
1947 {
1948 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1949
1950 if (pti->pcti)
1951 {
1952 pti->pcti->dwcPumpHook++;
1953 return TRUE;
1954 }
1955 return FALSE;
1956 }
1957
1958 BOOL APIENTRY
1959 IntUninitMessagePumpHook(VOID)
1960 {
1961 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1962
1963 if (pti->pcti)
1964 {
1965 if (pti->pcti->dwcPumpHook <= 0)
1966 {
1967 return FALSE;
1968 }
1969 pti->pcti->dwcPumpHook--;
1970 return TRUE;
1971 }
1972 return FALSE;
1973 }
1974
1975 BOOL FASTCALL
1976 IntCallMsgFilter( LPMSG lpmsg, INT code)
1977 {
1978 BOOL Ret = FALSE;
1979
1980 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)lpmsg))
1981 {
1982 Ret = TRUE;
1983 }
1984 else
1985 {
1986 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)lpmsg);
1987 }
1988 return Ret;
1989 }
1990
1991 /** Functions ******************************************************************/
1992
1993 BOOL
1994 APIENTRY
1995 NtUserDragDetect(
1996 HWND hWnd,
1997 POINT pt) // Just like the User call.
1998 {
1999 MSG msg;
2000 RECT rect;
2001 ULONG wDragWidth, wDragHeight;
2002 DECLARE_RETURN(BOOL);
2003
2004 TRACE("Enter NtUserDragDetect(%p)\n", hWnd);
2005 UserEnterExclusive();
2006
2007 wDragWidth = UserGetSystemMetrics(SM_CXDRAG);
2008 wDragHeight= UserGetSystemMetrics(SM_CYDRAG);
2009
2010 rect.left = pt.x - wDragWidth;
2011 rect.right = pt.x + wDragWidth;
2012
2013 rect.top = pt.y - wDragHeight;
2014 rect.bottom = pt.y + wDragHeight;
2015
2016 co_UserSetCapture(hWnd);
2017
2018 for (;;)
2019 {
2020 while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) ||
2021 co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC, WM_QUEUESYNC, PM_REMOVE, FALSE ) ||
2022 co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE, FALSE ) )
2023 {
2024 if ( msg.message == WM_LBUTTONUP )
2025 {
2026 co_UserSetCapture(NULL);
2027 RETURN( FALSE);
2028 }
2029 if ( msg.message == WM_MOUSEMOVE )
2030 {
2031 POINT tmp;
2032 tmp.x = (short)LOWORD(msg.lParam);
2033 tmp.y = (short)HIWORD(msg.lParam);
2034 if( !RECTL_bPointInRect( &rect, tmp.x, tmp.y ) )
2035 {
2036 co_UserSetCapture(NULL);
2037 RETURN( TRUE);
2038 }
2039 }
2040 if ( msg.message == WM_KEYDOWN )
2041 {
2042 if ( msg.wParam == VK_ESCAPE )
2043 {
2044 co_UserSetCapture(NULL);
2045 RETURN( TRUE);
2046 }
2047 }
2048 if ( msg.message == WM_QUEUESYNC )
2049 {
2050 co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 );
2051 }
2052 }
2053 co_IntWaitMessage(NULL, 0, 0);
2054 }
2055 RETURN( FALSE);
2056
2057 CLEANUP:
2058 TRACE("Leave NtUserDragDetect, ret=%i\n",_ret_);
2059 UserLeave();
2060 END_CLEANUP;
2061 }
2062
2063 BOOL APIENTRY
2064 NtUserPostMessage(HWND hWnd,
2065 UINT Msg,
2066 WPARAM wParam,
2067 LPARAM lParam)
2068 {
2069 BOOL ret;
2070
2071 UserEnterExclusive();
2072
2073 ret = UserPostMessage(hWnd, Msg, wParam, lParam);
2074
2075 UserLeave();
2076
2077 return ret;
2078 }
2079
2080 BOOL APIENTRY
2081 NtUserPostThreadMessage(DWORD idThread,
2082 UINT Msg,
2083 WPARAM wParam,
2084 LPARAM lParam)
2085 {
2086 BOOL ret = FALSE;
2087 PETHREAD peThread;
2088 PTHREADINFO pThread;
2089 NTSTATUS Status;
2090
2091 UserEnterExclusive();
2092
2093 Status = PsLookupThreadByThreadId(UlongToHandle(idThread), &peThread);
2094
2095 if ( Status == STATUS_SUCCESS )
2096 {
2097 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
2098 if( !pThread ||
2099 !pThread->MessageQueue ||
2100 (pThread->TIF_flags & TIF_INCLEANUP))
2101 {
2102 ObDereferenceObject( peThread );
2103 goto exit;
2104 }
2105 ret = UserPostThreadMessage( pThread, Msg, wParam, lParam);
2106 ObDereferenceObject( peThread );
2107 }
2108 else
2109 {
2110 SetLastNtError( Status );
2111 }
2112 exit:
2113 UserLeave();
2114 return ret;
2115 }
2116
2117 BOOL APIENTRY
2118 NtUserWaitMessage(VOID)
2119 {
2120 BOOL ret;
2121
2122 UserEnterExclusive();
2123 TRACE("NtUserWaitMessage Enter\n");
2124 ret = co_IntWaitMessage(NULL, 0, 0);
2125 TRACE("NtUserWaitMessage Leave\n");
2126 UserLeave();
2127
2128 return ret;
2129 }
2130
2131 BOOL APIENTRY
2132 NtUserGetMessage(PMSG pMsg,
2133 HWND hWnd,
2134 UINT MsgFilterMin,
2135 UINT MsgFilterMax )
2136 {
2137 MSG Msg;
2138 BOOL Ret;
2139
2140 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
2141 {
2142 EngSetLastError(ERROR_INVALID_PARAMETER);
2143 return FALSE;
2144 }
2145
2146 UserEnterExclusive();
2147
2148 RtlZeroMemory(&Msg, sizeof(MSG));
2149
2150 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
2151
2152 UserLeave();
2153
2154 if (Ret)
2155 {
2156 _SEH2_TRY
2157 {
2158 ProbeForWrite(pMsg, sizeof(MSG), 1);
2159 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2160 }
2161 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2162 {
2163 SetLastNtError(_SEH2_GetExceptionCode());
2164 Ret = FALSE;
2165 }
2166 _SEH2_END;
2167 }
2168
2169 if ((INT)Ret != -1)
2170 Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE;
2171
2172 return Ret;
2173 }
2174
2175 BOOL APIENTRY
2176 NtUserPeekMessage( PMSG pMsg,
2177 HWND hWnd,
2178 UINT MsgFilterMin,
2179 UINT MsgFilterMax,
2180 UINT RemoveMsg)
2181 {
2182 MSG Msg;
2183 BOOL Ret;
2184
2185 if ( RemoveMsg & PM_BADMSGFLAGS )
2186 {
2187 EngSetLastError(ERROR_INVALID_FLAGS);
2188 return FALSE;
2189 }
2190
2191 UserEnterExclusive();
2192
2193 RtlZeroMemory(&Msg, sizeof(MSG));
2194
2195 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
2196
2197 UserLeave();
2198
2199 if (Ret)
2200 {
2201 _SEH2_TRY
2202 {
2203 ProbeForWrite(pMsg, sizeof(MSG), 1);
2204 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
2205 }
2206 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2207 {
2208 SetLastNtError(_SEH2_GetExceptionCode());
2209 Ret = FALSE;
2210 }
2211 _SEH2_END;
2212 }
2213
2214 return Ret;
2215 }
2216
2217 BOOL APIENTRY
2218 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
2219 {
2220 BOOL Ret = FALSE;
2221 MSG Msg;
2222
2223 _SEH2_TRY
2224 {
2225 ProbeForRead(lpmsg, sizeof(MSG), 1);
2226 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
2227 }
2228 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2229 {
2230 _SEH2_YIELD(return FALSE);
2231 }
2232 _SEH2_END;
2233
2234 UserEnterExclusive();
2235
2236 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
2237 {
2238 Ret = TRUE;
2239 }
2240 else
2241 {
2242 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
2243 }
2244
2245 UserLeave();
2246
2247 _SEH2_TRY
2248 {
2249 ProbeForWrite(lpmsg, sizeof(MSG), 1);
2250 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
2251 }
2252 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2253 {
2254 Ret = FALSE;
2255 }
2256 _SEH2_END;
2257
2258 return Ret;
2259 }
2260
2261 LRESULT APIENTRY
2262 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
2263 {
2264 LRESULT Res = 0;
2265 MSG SafeMsg;
2266
2267 _SEH2_TRY
2268 {
2269 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
2270 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
2271 }
2272 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2273 {
2274 SetLastNtError(_SEH2_GetExceptionCode());
2275 _SEH2_YIELD(return FALSE);
2276 }
2277 _SEH2_END;
2278
2279 UserEnterExclusive();
2280
2281 Res = IntDispatchMessage(&SafeMsg);
2282
2283 UserLeave();
2284 return Res;
2285 }
2286
2287 BOOL APIENTRY
2288 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
2289 {
2290 MSG SafeMsg;
2291 BOOL Ret;
2292 PWND pWnd;
2293
2294 _SEH2_TRY
2295 {
2296 ProbeForRead(lpMsg, sizeof(MSG), 1);
2297 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
2298 }
2299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2300 {
2301 SetLastNtError(_SEH2_GetExceptionCode());
2302 _SEH2_YIELD(return FALSE);
2303 }
2304 _SEH2_END;
2305
2306 UserEnterExclusive();
2307 pWnd = UserGetWindowObject(SafeMsg.hwnd);
2308 if (pWnd) // Must have a window!
2309 {
2310 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
2311 }
2312 else
2313 {
2314 TRACE("No Window for Translate. hwnd 0x%p Msg %u\n", SafeMsg.hwnd, SafeMsg.message);
2315 Ret = FALSE;
2316 }
2317 UserLeave();
2318
2319 return Ret;
2320 }
2321
2322 LRESULT APIENTRY ScrollBarWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam);
2323
2324 BOOL APIENTRY
2325 NtUserMessageCall( HWND hWnd,
2326 UINT Msg,
2327 WPARAM wParam,
2328 LPARAM lParam,
2329 ULONG_PTR ResultInfo,
2330 DWORD dwType, // fnID?
2331 BOOL Ansi)
2332 {
2333 LRESULT lResult = 0;
2334 BOOL Ret = FALSE;
2335 PWND Window = NULL;
2336 USER_REFERENCE_ENTRY Ref;
2337
2338 UserEnterExclusive();
2339
2340 switch(dwType)
2341 {
2342 case FNID_SCROLLBAR:
2343 {
2344 lResult = ScrollBarWndProc(hWnd, Msg, wParam, lParam);
2345 break;
2346 }
2347 case FNID_DESKTOP:
2348 {
2349 Window = UserGetWindowObject(hWnd);
2350 if (Window)
2351 {
2352 //ERR("FNID_DESKTOP IN\n");
2353 Ret = DesktopWindowProc(Window, Msg, wParam, lParam, &lResult);
2354 //ERR("FNID_DESKTOP OUT\n");
2355 }
2356 break;
2357 }
2358 case FNID_MENU:
2359 {
2360 Window = UserGetWindowObject(hWnd);
2361 if (Window)
2362 {
2363 Ret = PopupMenuWndProc( Window, Msg, wParam, lParam, &lResult);
2364 }
2365 break;
2366 }
2367 case FNID_MESSAGEWND:
2368 {
2369 Window = UserGetWindowObject(hWnd);
2370 if (Window)
2371 {
2372 Ret = !UserMessageWindowProc(Window, Msg, wParam, lParam, &lResult);
2373 }
2374 break;
2375 }
2376 case FNID_DEFWINDOWPROC:
2377 /* Validate input */
2378 if (hWnd)
2379 {
2380 Window = UserGetWindowObject(hWnd);
2381 if (!Window)
2382 {
2383 UserLeave();
2384 return FALSE;
2385 }
2386 UserRefObjectCo(Window, &Ref);
2387 }
2388 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2389 Ret = TRUE;
2390 if (hWnd)
2391 UserDerefObjectCo(Window);
2392 break;
2393 case FNID_SENDNOTIFYMESSAGE:
2394 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2395 break;
2396 case FNID_BROADCASTSYSTEMMESSAGE:
2397 {
2398 BROADCASTPARM parm, *retparam;
2399 DWORD_PTR RetVal = 0;
2400
2401 if (ResultInfo)
2402 {
2403 _SEH2_TRY
2404 {
2405 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
2406 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2407 }
2408 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2409 {
2410 _SEH2_YIELD(break);
2411 }
2412 _SEH2_END;
2413 }
2414 else
2415 break;
2416
2417 if ( parm.recipients & BSM_ALLDESKTOPS ||
2418 parm.recipients == BSM_ALLCOMPONENTS )
2419 {
2420 PLIST_ENTRY DesktopEntry;
2421 PDESKTOP rpdesk;
2422 HWND *List, hwndDenied = NULL;
2423 HDESK hDesk = NULL;
2424 PWND pwnd, pwndDesk;
2425 ULONG i;
2426 UINT fuFlags;
2427
2428 for (DesktopEntry = InputWindowStation->DesktopListHead.Flink;
2429 DesktopEntry != &InputWindowStation->DesktopListHead;
2430 DesktopEntry = DesktopEntry->Flink)
2431 {
2432 rpdesk = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
2433 pwndDesk = rpdesk->pDeskInfo->spwnd;
2434 List = IntWinListChildren(pwndDesk);
2435
2436 if (parm.flags & BSF_QUERY)
2437 {
2438 if (List != NULL)
2439 {
2440 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2441 {
2442 fuFlags = SMTO_ABORTIFHUNG;
2443 }
2444 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2445 {
2446 fuFlags = SMTO_NOTIMEOUTIFNOTHUNG;
2447 }
2448 else
2449 {
2450 fuFlags = SMTO_NORMAL;
2451 }
2452 co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk),
2453 Msg,
2454 wParam,
2455 lParam,
2456 fuFlags,
2457 2000,
2458 &RetVal);
2459 Ret = TRUE;
2460 for (i = 0; List[i]; i++)
2461 {
2462 pwnd = UserGetWindowObject(List[i]);
2463 if (!pwnd) continue;
2464
2465 if ( pwnd->fnid == FNID_MENU ||
2466 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2467 continue;
2468
2469 if ( parm.flags & BSF_IGNORECURRENTTASK )
2470 {
2471 if ( pwnd->head.pti == gptiCurrent )
2472 continue;
2473 }
2474 co_IntSendMessageTimeout( List[i],
2475 Msg,
2476 wParam,
2477 lParam,
2478 fuFlags,
2479 2000,
2480 &RetVal);
2481
2482 if (!RetVal && EngGetLastError() == ERROR_TIMEOUT)
2483 {
2484 if (!(parm.flags & BSF_FORCEIFHUNG))
2485 Ret = FALSE;
2486 }
2487 if (RetVal == BROADCAST_QUERY_DENY)
2488 {
2489 hwndDenied = List[i];
2490 hDesk = UserHMGetHandle(pwndDesk);
2491 Ret = FALSE;
2492 }
2493 }
2494 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2495 _SEH2_TRY
2496 {
2497 retparam = (PBROADCASTPARM) ResultInfo;
2498 retparam->hDesk = hDesk;
2499 retparam->hWnd = hwndDenied;
2500 }
2501 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2502 {
2503 _SEH2_YIELD(break);
2504 }
2505 _SEH2_END;
2506 if (!Ret) break; // Have a hit! Let everyone know!
2507 }
2508 }
2509 else if (parm.flags & BSF_POSTMESSAGE)
2510 {
2511 if (List != NULL)
2512 {
2513 UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2514
2515 for (i = 0; List[i]; i++)
2516 {
2517 pwnd = UserGetWindowObject(List[i]);
2518 if (!pwnd) continue;
2519
2520 if ( pwnd->fnid == FNID_MENU ||
2521 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2522 continue;
2523
2524 if ( parm.flags & BSF_IGNORECURRENTTASK )
2525 {
2526 if ( pwnd->head.pti == gptiCurrent )
2527 continue;
2528 }
2529 UserPostMessage(List[i], Msg, wParam, lParam);
2530 }
2531 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2532 }
2533 Ret = TRUE;
2534 }
2535 else
2536 {
2537 if (List != NULL)
2538 {
2539 UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2540
2541 for (i = 0; List[i]; i++)
2542 {
2543 pwnd = UserGetWindowObject(List[i]);
2544 if (!pwnd) continue;
2545
2546 if ( pwnd->fnid == FNID_MENU ||
2547 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2548 continue;
2549
2550 if ( parm.flags & BSF_IGNORECURRENTTASK )
2551 {
2552 if ( pwnd->head.pti == gptiCurrent )
2553 continue;
2554 }
2555 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
2556 }
2557 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2558 }
2559 Ret = TRUE;
2560 }
2561 }
2562 }
2563 else if (parm.recipients & BSM_APPLICATIONS)
2564 {
2565 HWND *List, hwndDenied = NULL;
2566 HDESK hDesk = NULL;
2567 PWND pwnd, pwndDesk;
2568 ULONG i;
2569 UINT fuFlags;
2570
2571 pwndDesk = UserGetDesktopWindow();
2572 List = IntWinListChildren(pwndDesk);
2573
2574 if (parm.flags & BSF_QUERY)
2575 {
2576 if (List != NULL)
2577 {
2578 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2579 {
2580 fuFlags = SMTO_ABORTIFHUNG;
2581 }
2582 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2583 {
2584 fuFlags = SMTO_NOTIMEOUTIFNOTHUNG;
2585 }
2586 else
2587 {
2588 fuFlags = SMTO_NORMAL;
2589 }
2590 co_IntSendMessageTimeout( UserHMGetHandle(pwndDesk),
2591 Msg,
2592 wParam,
2593 lParam,
2594 fuFlags,
2595 2000,
2596 &RetVal);
2597 Ret = TRUE;
2598 for (i = 0; List[i]; i++)
2599 {
2600 pwnd = UserGetWindowObject(List[i]);
2601 if (!pwnd) continue;
2602
2603 if ( pwnd->fnid == FNID_MENU ||
2604 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2605 continue;
2606
2607 if ( parm.flags & BSF_IGNORECURRENTTASK )
2608 {
2609 if ( pwnd->head.pti == gptiCurrent )
2610 continue;
2611 }
2612 co_IntSendMessageTimeout( List[i],
2613 Msg,
2614 wParam,
2615 lParam,
2616 fuFlags,
2617 2000,
2618 &RetVal);
2619
2620 if (!RetVal && EngGetLastError() == ERROR_TIMEOUT)
2621 {
2622 if (!(parm.flags & BSF_FORCEIFHUNG))
2623 Ret = FALSE;
2624 }
2625 if (RetVal == BROADCAST_QUERY_DENY)
2626 {
2627 hwndDenied = List[i];
2628 hDesk = UserHMGetHandle(pwndDesk);
2629 Ret = FALSE;
2630 }
2631 }
2632 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2633 _SEH2_TRY
2634 {
2635 retparam = (PBROADCASTPARM) ResultInfo;
2636 retparam->hDesk = hDesk;
2637 retparam->hWnd = hwndDenied;
2638 }
2639 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2640 {
2641 _SEH2_YIELD(break);
2642 }
2643 _SEH2_END;
2644 }
2645 }
2646 else if (parm.flags & BSF_POSTMESSAGE)
2647 {
2648 if (List != NULL)
2649 {
2650 UserPostMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2651
2652 for (i = 0; List[i]; i++)
2653 {
2654 pwnd = UserGetWindowObject(List[i]);
2655 if (!pwnd) continue;
2656
2657 if ( pwnd->fnid == FNID_MENU ||
2658 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2659 continue;
2660
2661 if ( parm.flags & BSF_IGNORECURRENTTASK )
2662 {
2663 if ( pwnd->head.pti == gptiCurrent )
2664 continue;
2665 }
2666 UserPostMessage(List[i], Msg, wParam, lParam);
2667 }
2668 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2669 }
2670 Ret = TRUE;
2671 }
2672 else
2673 {
2674 if (List != NULL)
2675 {
2676 UserSendNotifyMessage(UserHMGetHandle(pwndDesk), Msg, wParam, lParam);
2677
2678 for (i = 0; List[i]; i++)
2679 {
2680 pwnd = UserGetWindowObject(List[i]);
2681 if (!pwnd) continue;
2682
2683 if ( pwnd->fnid == FNID_MENU ||
2684 pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_SWITCH] )
2685 continue;
2686
2687 if ( parm.flags & BSF_IGNORECURRENTTASK )
2688 {
2689 if ( pwnd->head.pti == gptiCurrent )
2690 continue;
2691 }
2692 UserSendNotifyMessage(List[i], Msg, wParam, lParam);
2693 }
2694 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2695 }
2696 Ret = TRUE;
2697 }
2698 }
2699 }
2700 break;
2701 case FNID_SENDMESSAGECALLBACK:
2702 {
2703 CALL_BACK_INFO CallBackInfo;
2704 ULONG_PTR uResult;
2705
2706 _SEH2_TRY
2707 {
2708 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
2709 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
2710 }
2711 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2712 {
2713 _SEH2_YIELD(break);
2714 }
2715 _SEH2_END;
2716
2717 if (is_pointer_message(Msg))
2718 {
2719 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
2720 break;
2721 }
2722
2723 if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2724 CallBackInfo.CallBack, CallBackInfo.Context, &uResult)))
2725 {
2726 ERR("Callback failure!\n");
2727 }
2728 }
2729 break;
2730 case FNID_SENDMESSAGE:
2731 {
2732 lResult = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
2733 Ret = TRUE;
2734
2735 if (ResultInfo)
2736 {
2737 _SEH2_TRY
2738 {
2739 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
2740 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(ULONG_PTR));
2741 }
2742 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2743 {
2744 Ret = FALSE;
2745 _SEH2_YIELD(break);
2746 }
2747 _SEH2_END;
2748 }
2749 break;
2750 }
2751 case FNID_SENDMESSAGEFF:
2752 case FNID_SENDMESSAGEWTOOPTION:
2753 {
2754 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
2755 if (ResultInfo)
2756 {
2757 _SEH2_TRY
2758 {
2759 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
2760 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
2761 }
2762 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2763 {
2764 _SEH2_YIELD(break);
2765 }
2766 _SEH2_END;
2767 }
2768
2769 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, pdsm ? &dsm : NULL );
2770
2771 if (pdsm)
2772 {
2773 _SEH2_TRY
2774 {
2775 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
2776 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2777 }
2778 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2779 {
2780 Ret = FALSE;
2781 _SEH2_YIELD(break);
2782 }
2783 _SEH2_END;
2784 }
2785 break;
2786 }
2787 // CallNextHook bypass.
2788 case FNID_CALLWNDPROC:
2789 case FNID_CALLWNDPROCRET:
2790 {
2791 PTHREADINFO pti;
2792 PCLIENTINFO ClientInfo;
2793 PHOOK NextObj, Hook;
2794
2795 pti = GetW32ThreadInfo();
2796
2797 Hook = pti->sphkCurrent;
2798
2799 if (!Hook) break;
2800
2801 NextObj = Hook->phkNext;
2802 ClientInfo = pti->pClientInfo;
2803 _SEH2_TRY
2804 {
2805 ClientInfo->phkCurrent = NextObj;
2806 }
2807 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2808 {
2809 ClientInfo = NULL;
2810 }
2811 _SEH2_END;
2812
2813 if (!ClientInfo || !NextObj) break;
2814
2815 NextObj->phkNext = IntGetNextHook(NextObj);
2816
2817 if ( Hook->HookId == WH_CALLWNDPROC)
2818 {
2819 CWPSTRUCT CWP;
2820 CWP.hwnd = hWnd;
2821 CWP.message = Msg;
2822 CWP.wParam = wParam;
2823 CWP.lParam = lParam;
2824 TRACE("WH_CALLWNDPROC: Hook %p NextHook %p\n", Hook, NextObj);
2825
2826 lResult = co_IntCallHookProc( Hook->HookId,
2827 HC_ACTION,
2828 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2829 (LPARAM)&CWP,
2830 Hook->Proc,
2831 Hook->ihmod,
2832 Hook->offPfn,
2833 Hook->Ansi,
2834 &Hook->ModuleName);
2835 }
2836 else
2837 {
2838 CWPRETSTRUCT CWPR;
2839 CWPR.hwnd = hWnd;
2840 CWPR.message = Msg;
2841 CWPR.wParam = wParam;
2842 CWPR.lParam = lParam;
2843 CWPR.lResult = ClientInfo->dwHookData;
2844
2845 lResult = co_IntCallHookProc( Hook->HookId,
2846 HC_ACTION,
2847 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2848 (LPARAM)&CWPR,
2849 Hook->Proc,
2850 Hook->ihmod,
2851 Hook->offPfn,
2852 Hook->Ansi,
2853 &Hook->ModuleName);
2854 }
2855 }
2856 break;
2857 }
2858
2859 switch(dwType)
2860 {
2861 case FNID_DEFWINDOWPROC:
2862 case FNID_CALLWNDPROC:
2863 case FNID_CALLWNDPROCRET:
2864 case FNID_SCROLLBAR:
2865 case FNID_DESKTOP:
2866 case FNID_MENU:
2867 if (ResultInfo)
2868 {
2869 _SEH2_TRY
2870 {
2871 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2872 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2873 }
2874 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2875 {
2876 Ret = FALSE;
2877 }
2878 _SEH2_END;
2879 }
2880 break;
2881 default:
2882 break;
2883 }
2884
2885 UserLeave();
2886
2887 return Ret;
2888 }
2889
2890 #define INFINITE 0xFFFFFFFF
2891 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2892
2893 DWORD
2894 APIENTRY
2895 NtUserWaitForInputIdle( IN HANDLE hProcess,
2896 IN DWORD dwMilliseconds,
2897 IN BOOL Unknown2)
2898 {
2899 PEPROCESS Process;
2900 PPROCESSINFO W32Process;
2901 PTHREADINFO pti;
2902 NTSTATUS Status;
2903 HANDLE Handles[3];
2904 LARGE_INTEGER Timeout;
2905 KAPC_STATE ApcState;
2906
2907 UserEnterExclusive();
2908
2909 Status = ObReferenceObjectByHandle(hProcess,
2910 PROCESS_QUERY_INFORMATION,
2911 *PsProcessType,
2912 UserMode,
2913 (PVOID*)&Process,
2914 NULL);
2915
2916 if (!NT_SUCCESS(Status))
2917 {
2918 UserLeave();
2919 SetLastNtError(Status);
2920 return WAIT_FAILED;
2921 }
2922
2923 pti = PsGetCurrentThreadWin32Thread();
2924
2925 W32Process = (PPROCESSINFO)Process->Win32Process;
2926
2927 if ( PsGetProcessExitProcessCalled(Process) ||
2928 !W32Process ||
2929 pti->ppi == W32Process)
2930 {
2931 ObDereferenceObject(Process);
2932 UserLeave();
2933 EngSetLastError(ERROR_INVALID_PARAMETER);
2934 return WAIT_FAILED;
2935 }
2936
2937 Handles[0] = Process;
2938 Handles[1] = W32Process->InputIdleEvent;
2939 Handles[2] = pti->pEventQueueServer; // IntMsqSetWakeMask returns hEventQueueClient
2940
2941 if (!Handles[1])
2942 {
2943 ObDereferenceObject(Process);
2944 UserLeave();
2945 return STATUS_SUCCESS; /* no event to wait on */
2946 }
2947
2948 if (dwMilliseconds != INFINITE)
2949 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2950
2951 KeStackAttachProcess(&Process->Pcb, &ApcState);
2952
2953 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2954 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2955 {
2956 pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2957 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2958 }
2959
2960 KeUnstackDetachProcess(&ApcState);
2961
2962 TRACE("WFII: ppi %p\n", W32Process);
2963 TRACE("WFII: waiting for %p\n", Handles[1] );
2964
2965 /*
2966 * We must add a refcount to our current PROCESSINFO,
2967 * because anything could happen (including process death) we're leaving win32k
2968 */
2969 IntReferenceProcessInfo(W32Process);
2970
2971 do
2972 {
2973 UserLeave();
2974 Status = KeWaitForMultipleObjects( 3,
2975 Handles,
2976 WaitAny,
2977 UserRequest,
2978 UserMode,
2979 FALSE,
2980 dwMilliseconds == INFINITE ? NULL : &Timeout,
2981 NULL);
2982 UserEnterExclusive();
2983
2984 if (!NT_SUCCESS(Status))
2985 {
2986 SetLastNtError(Status);
2987 Status = WAIT_FAILED;
2988 goto WaitExit;
2989 }
2990
2991 switch (Status)
2992 {
2993 case STATUS_WAIT_0:
2994 goto WaitExit;
2995
2996 case STATUS_WAIT_2:
2997 {
2998 MSG Msg;
2999 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
3000 ERR("WFII: WAIT 2\n");
3001 }
3002 break;
3003
3004 case STATUS_TIMEOUT:
3005 ERR("WFII: timeout\n");
3006 case WAIT_FAILED:
3007 goto WaitExit;
3008
3009 default:
3010 ERR("WFII: finished\n");
3011 Status = STATUS_SUCCESS;
3012 goto WaitExit;
3013 }
3014 }
3015 while (TRUE);
3016
3017 WaitExit:
3018 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
3019 {
3020 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
3021 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
3022 }
3023 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
3024 IntDereferenceProcessInfo(W32Process);
3025 ObDereferenceObject(Process);
3026 UserLeave();
3027 return Status;
3028 }
3029
3030 /* EOF */