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