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