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