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