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