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