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