[SETUPAPI]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / message.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Messages
5 * FILE: subsystems/win32/win32k/ntuser/message.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <win32k.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 BOOLEAN NTAPI PsGetProcessExitProcessCalled(PEPROCESS Process);
19
20 #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
21
22 /* FUNCTIONS *****************************************************************/
23
24 NTSTATUS FASTCALL
25 IntInitMessageImpl(VOID)
26 {
27 return STATUS_SUCCESS;
28 }
29
30 NTSTATUS FASTCALL
31 IntCleanupMessageImpl(VOID)
32 {
33 return STATUS_SUCCESS;
34 }
35
36 /* From wine: */
37 /* flag for messages that contain pointers */
38 /* 32 messages per entry, messages 0..31 map to bits 0..31 */
39
40 #define SET(msg) (1 << ((msg) & 31))
41
42 static const unsigned int message_pointer_flags[] =
43 {
44 /* 0x00 - 0x1f */
45 SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
46 SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
47 /* 0x20 - 0x3f */
48 SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
49 SET(WM_COMPAREITEM),
50 /* 0x40 - 0x5f */
51 SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
52 SET(WM_COPYGLOBALDATA) | SET(WM_NOTIFY) | SET(WM_HELP),
53 /* 0x60 - 0x7f */
54 SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
55 /* 0x80 - 0x9f */
56 SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
57 /* 0xa0 - 0xbf */
58 SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
59 /* 0xc0 - 0xdf */
60 SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
61 /* 0xe0 - 0xff */
62 SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO),
63 /* 0x100 - 0x11f */
64 0,
65 /* 0x120 - 0x13f */
66 0,
67 /* 0x140 - 0x15f */
68 SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
69 SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
70 SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
71 /* 0x160 - 0x17f */
72 0,
73 /* 0x180 - 0x19f */
74 SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
75 SET(LB_DIR) | SET(LB_FINDSTRING) |
76 SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
77 /* 0x1a0 - 0x1bf */
78 SET(LB_FINDSTRINGEXACT),
79 /* 0x1c0 - 0x1df */
80 0,
81 /* 0x1e0 - 0x1ff */
82 0,
83 /* 0x200 - 0x21f */
84 SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
85 /* 0x220 - 0x23f */
86 SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
87 SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
88 /* 0x240 - 0x25f */
89 0,
90 /* 0x260 - 0x27f */
91 0,
92 /* 0x280 - 0x29f */
93 0,
94 /* 0x2a0 - 0x2bf */
95 0,
96 /* 0x2c0 - 0x2df */
97 0,
98 /* 0x2e0 - 0x2ff */
99 0,
100 /* 0x300 - 0x31f */
101 SET(WM_ASKCBFORMATNAME)
102 };
103
104 /* check whether a given message type includes pointers */
105 static inline int is_pointer_message( UINT message )
106 {
107 if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
108 return (message_pointer_flags[message / 32] & SET(message)) != 0;
109 }
110
111 #define MMS_SIZE_WPARAM -1
112 #define MMS_SIZE_WPARAMWCHAR -2
113 #define MMS_SIZE_LPARAMSZ -3
114 #define MMS_SIZE_SPECIAL -4
115 #define MMS_FLAG_READ 0x01
116 #define MMS_FLAG_WRITE 0x02
117 #define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
118 typedef struct tagMSGMEMORY
119 {
120 UINT Message;
121 UINT Size;
122 INT Flags;
123 }
124 MSGMEMORY, *PMSGMEMORY;
125
126 static MSGMEMORY MsgMemory[] =
127 {
128 { WM_CREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
129 { WM_DDE_ACK, sizeof(KMDDELPARAM), MMS_FLAG_READ },
130 { WM_DDE_EXECUTE, MMS_SIZE_WPARAM, MMS_FLAG_READ },
131 { WM_GETMINMAXINFO, sizeof(MINMAXINFO), MMS_FLAG_READWRITE },
132 { WM_GETTEXT, MMS_SIZE_WPARAMWCHAR, MMS_FLAG_WRITE },
133 { WM_NCCALCSIZE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
134 { WM_NCCREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
135 { WM_SETTEXT, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ },
136 { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ },
137 { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE },
138 { WM_COPYDATA, MMS_SIZE_SPECIAL, MMS_FLAG_READ },
139 { WM_COPYGLOBALDATA, MMS_SIZE_WPARAM, MMS_FLAG_READ },
140 { WM_WINDOWPOSCHANGED, sizeof(WINDOWPOS), MMS_FLAG_READ },
141 { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
142 };
143
144 static PMSGMEMORY FASTCALL
145 FindMsgMemory(UINT Msg)
146 {
147 PMSGMEMORY MsgMemoryEntry;
148
149 /* See if this message type is present in the table */
150 for (MsgMemoryEntry = MsgMemory;
151 MsgMemoryEntry < MsgMemory + sizeof(MsgMemory) / sizeof(MSGMEMORY);
152 MsgMemoryEntry++)
153 {
154 if (Msg == MsgMemoryEntry->Message)
155 {
156 return MsgMemoryEntry;
157 }
158 }
159
160 return NULL;
161 }
162
163 static UINT FASTCALL
164 MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
165 {
166 CREATESTRUCTW *Cs;
167 PUNICODE_STRING WindowName;
168 PUNICODE_STRING ClassName;
169 UINT Size = 0;
170
171 _SEH2_TRY
172 {
173 if (MMS_SIZE_WPARAM == MsgMemoryEntry->Size)
174 {
175 Size = (UINT)wParam;
176 }
177 else if (MMS_SIZE_WPARAMWCHAR == MsgMemoryEntry->Size)
178 {
179 Size = (UINT) (wParam * sizeof(WCHAR));
180 }
181 else if (MMS_SIZE_LPARAMSZ == MsgMemoryEntry->Size)
182 {
183 Size = (UINT) ((wcslen((PWSTR) lParam) + 1) * sizeof(WCHAR));
184 }
185 else if (MMS_SIZE_SPECIAL == MsgMemoryEntry->Size)
186 {
187 switch(MsgMemoryEntry->Message)
188 {
189 case WM_CREATE:
190 case WM_NCCREATE:
191 Cs = (CREATESTRUCTW *) lParam;
192 WindowName = (PUNICODE_STRING) Cs->lpszName;
193 ClassName = (PUNICODE_STRING) Cs->lpszClass;
194 Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
195 if (IS_ATOM(ClassName->Buffer))
196 {
197 Size += sizeof(WCHAR) + sizeof(ATOM);
198 }
199 else
200 {
201 Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
202 }
203 break;
204
205 case WM_NCCALCSIZE:
206 Size = wParam ? sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) : sizeof(RECT);
207 break;
208
209 case WM_COPYDATA:
210 Size = sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
211 break;
212
213 default:
214 ASSERT(FALSE);
215 Size = 0;
216 break;
217 }
218 }
219 else
220 {
221 Size = MsgMemoryEntry->Size;
222 }
223 }
224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
225 {
226 DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
227 Size = 0;
228 }
229 _SEH2_END;
230 return Size;
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 DPRINT1("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 DPRINT1("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
323 MsgMemoryEntry = FindMsgMemory(Msg);
324
325 if ((!MsgMemoryEntry) || (MsgMemoryEntry->Size < 0))
326 {
327 /* Keep previous behavior */
328 return STATUS_SUCCESS;
329 }
330 PackedData = ExAllocatePoolWithTag(NonPagedPool, MsgMemorySize(MsgMemoryEntry, wParam, lParam), TAG_MSG);
331 RtlCopyMemory(PackedData, (PVOID)lParam, MsgMemorySize(MsgMemoryEntry, wParam, lParam));
332 *lParamPacked = (LPARAM)PackedData;
333 }
334
335 return STATUS_SUCCESS;
336 }
337
338 static NTSTATUS
339 UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolUsed)
340 {
341 NCCALCSIZE_PARAMS *UnpackedParams;
342 NCCALCSIZE_PARAMS *PackedParams;
343 PWINDOWPOS UnpackedWindowPos;
344
345 if (lParamPacked == lParam)
346 {
347 return STATUS_SUCCESS;
348 }
349
350 if (WM_NCCALCSIZE == Msg && wParam)
351 {
352 PackedParams = (NCCALCSIZE_PARAMS *) lParamPacked;
353 UnpackedParams = (NCCALCSIZE_PARAMS *) lParam;
354 UnpackedWindowPos = UnpackedParams->lppos;
355 RtlCopyMemory(UnpackedParams, PackedParams, sizeof(NCCALCSIZE_PARAMS));
356 UnpackedParams->lppos = UnpackedWindowPos;
357 RtlCopyMemory(UnpackedWindowPos, PackedParams + 1, sizeof(WINDOWPOS));
358 ExFreePool((PVOID) lParamPacked);
359
360 return STATUS_SUCCESS;
361 }
362 else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
363 {
364 ExFreePool((PVOID) lParamPacked);
365
366 return STATUS_SUCCESS;
367 }
368 else if (NonPagedPoolUsed)
369 {
370 PMSGMEMORY MsgMemoryEntry;
371 MsgMemoryEntry = FindMsgMemory(Msg);
372 if (MsgMemoryEntry->Size < 0)
373 {
374 /* Keep previous behavior */
375 return STATUS_INVALID_PARAMETER;
376 }
377
378 if (MsgMemory->Flags == MMS_FLAG_READWRITE)
379 {
380 //RtlCopyMemory((PVOID)lParam, (PVOID)lParamPacked, MsgMemory->Size);
381 }
382 ExFreePool((PVOID) lParamPacked);
383 return STATUS_SUCCESS;
384 }
385
386 ASSERT(FALSE);
387
388 return STATUS_INVALID_PARAMETER;
389 }
390
391 static NTSTATUS FASTCALL
392 CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
393 {
394 NTSTATUS Status;
395
396 PVOID KernelMem;
397 UINT Size;
398
399 *KernelModeMsg = *UserModeMsg;
400
401 /* See if this message type is present in the table */
402 if (NULL == MsgMemoryEntry)
403 {
404 /* Not present, no copying needed */
405 return STATUS_SUCCESS;
406 }
407
408 /* Determine required size */
409 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
410
411 if (0 != Size)
412 {
413 /* Allocate kernel mem */
414 KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
415 if (NULL == KernelMem)
416 {
417 DPRINT1("Not enough memory to copy message to kernel mem\n");
418 return STATUS_NO_MEMORY;
419 }
420 KernelModeMsg->lParam = (LPARAM) KernelMem;
421
422 /* Copy data if required */
423 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
424 {
425 Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
426 if (! NT_SUCCESS(Status))
427 {
428 DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
429 ExFreePoolWithTag(KernelMem, TAG_MSG);
430 return Status;
431 }
432 }
433 else
434 {
435 /* Make sure we don't pass any secrets to usermode */
436 RtlZeroMemory(KernelMem, Size);
437 }
438 }
439 else
440 {
441 KernelModeMsg->lParam = 0;
442 }
443
444 return STATUS_SUCCESS;
445 }
446
447 static NTSTATUS FASTCALL
448 CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
449 {
450 NTSTATUS Status;
451 PMSGMEMORY MsgMemoryEntry;
452 UINT Size;
453
454 /* See if this message type is present in the table */
455 MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
456 if (NULL == MsgMemoryEntry)
457 {
458 /* Not present, no copying needed */
459 return STATUS_SUCCESS;
460 }
461
462 /* Determine required size */
463 Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
464
465 if (0 != Size)
466 {
467 /* Copy data if required */
468 if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
469 {
470 Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
471 if (! NT_SUCCESS(Status))
472 {
473 DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
474 ExFreePool((PVOID) KernelModeMsg->lParam);
475 return Status;
476 }
477 }
478
479 ExFreePool((PVOID) KernelModeMsg->lParam);
480 }
481
482 return STATUS_SUCCESS;
483 }
484
485 //
486 // Wakeup any thread/process waiting on idle input.
487 //
488 VOID FASTCALL
489 IdlePing(VOID)
490 {
491 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
492 PUSER_MESSAGE_QUEUE ForegroundQueue;
493 PTHREADINFO pti, ptiForeground = NULL;
494
495 ForegroundQueue = IntGetFocusMessageQueue();
496
497 if (ForegroundQueue)
498 ptiForeground = ForegroundQueue->Thread->Tcb.Win32Thread;
499
500 pti = PsGetCurrentThreadWin32Thread();
501
502 if ( pti )
503 {
504 pti->pClientInfo->cSpins = 0; // Reset spins.
505
506 if ( pti->pDeskInfo && pti == ptiForeground )
507 {
508 if ( pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) ||
509 pti->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE) )
510 {
511 co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0);
512 }
513 }
514 }
515
516 DPRINT("IdlePing ppi 0x%x\n",ppi);
517 if ( ppi && ppi->InputIdleEvent )
518 {
519 DPRINT("InputIdleEvent\n");
520 KeSetEvent( ppi->InputIdleEvent, IO_NO_INCREMENT, FALSE);
521 }
522 }
523
524 VOID FASTCALL
525 IdlePong(VOID)
526 {
527 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
528
529 DPRINT("IdlePong ppi 0x%x\n",ppi);
530 if ( ppi && ppi->InputIdleEvent )
531 {
532 KeClearEvent(ppi->InputIdleEvent);
533 }
534 }
535
536 UINT FASTCALL
537 GetWakeMask(UINT first, UINT last )
538 {
539 UINT mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
540
541 if (first || last)
542 {
543 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
544 if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
545 ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
546 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
547 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
548 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
549 }
550 else mask = QS_ALLINPUT;
551
552 return mask;
553 }
554
555 static VOID FASTCALL
556 IntCallWndProc( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
557 {
558 BOOL SameThread = FALSE;
559 CWPSTRUCT CWP;
560
561 if (Window->head.pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
562 SameThread = TRUE;
563
564 CWP.hwnd = hWnd;
565 CWP.message = Msg;
566 CWP.wParam = wParam;
567 CWP.lParam = lParam;
568 co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP );
569 }
570
571 static VOID FASTCALL
572 IntCallWndProcRet ( PWND Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *uResult)
573 {
574 BOOL SameThread = FALSE;
575 CWPRETSTRUCT CWPR;
576
577 if (Window->head.pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
578 SameThread = TRUE;
579
580 CWPR.hwnd = hWnd;
581 CWPR.message = Msg;
582 CWPR.wParam = wParam;
583 CWPR.lParam = lParam;
584 CWPR.lResult = *uResult;
585 co_HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, SameThread, (LPARAM)&CWPR );
586 }
587
588 LRESULT FASTCALL
589 IntDispatchMessage(PMSG pMsg)
590 {
591 LARGE_INTEGER TickCount;
592 LONG Time;
593 LRESULT retval = 0;
594 PTHREADINFO pti;
595 PWND Window = NULL;
596
597 if (pMsg->hwnd)
598 {
599 Window = UserGetWindowObject(pMsg->hwnd);
600 if (!Window) return 0;
601 }
602
603 pti = PsGetCurrentThreadWin32Thread();
604
605 if ( Window->head.pti != pti)
606 {
607 EngSetLastError( ERROR_MESSAGE_SYNC_ONLY );
608 return 0;
609 }
610
611 if (((pMsg->message == WM_SYSTIMER) ||
612 (pMsg->message == WM_TIMER)) &&
613 (pMsg->lParam) )
614 {
615 if (pMsg->message == WM_TIMER)
616 {
617 if (ValidateTimerCallback(pti,pMsg->lParam))
618 {
619 KeQueryTickCount(&TickCount);
620 Time = MsqCalculateMessageTime(&TickCount);
621 retval = co_IntCallWindowProc((WNDPROC)pMsg->lParam,
622 TRUE,
623 pMsg->hwnd,
624 WM_TIMER,
625 pMsg->wParam,
626 (LPARAM)Time,
627 0);
628 }
629 return retval;
630 }
631 else
632 {
633 PTIMER pTimer = FindSystemTimer(pMsg);
634 if (pTimer && pTimer->pfn)
635 {
636 KeQueryTickCount(&TickCount);
637 Time = MsqCalculateMessageTime(&TickCount);
638 pTimer->pfn(pMsg->hwnd, WM_SYSTIMER, (UINT)pMsg->wParam, Time);
639 }
640 return 0;
641 }
642 }
643 // Need a window!
644 if ( !Window ) return 0;
645
646 /* Since we are doing a callback on the same thread right away, there is
647 no need to copy the lparam to kernel mode and then back to usermode.
648 We just pretend it isn't a pointer */
649
650 retval = co_IntCallWindowProc( Window->lpfnWndProc,
651 !Window->Unicode,
652 pMsg->hwnd,
653 pMsg->message,
654 pMsg->wParam,
655 pMsg->lParam,
656 0);
657
658 if (pMsg->message == WM_PAINT)
659 {
660 /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
661 HRGN hrgn = IntSysCreateRectRgn( 0, 0, 0, 0 );
662 co_UserGetUpdateRgn( Window, hrgn, TRUE );
663 REGION_FreeRgnByHandle( hrgn );
664 }
665
666 return retval;
667 }
668
669 /*
670 * Internal version of PeekMessage() doing all the work
671 */
672 BOOL FASTCALL
673 co_IntPeekMessage( PMSG Msg,
674 PWND Window,
675 UINT MsgFilterMin,
676 UINT MsgFilterMax,
677 UINT RemoveMsg,
678 BOOL bGMSG )
679 {
680 PTHREADINFO pti;
681 PCLIENTINFO pci;
682 LARGE_INTEGER LargeTickCount;
683 PUSER_MESSAGE_QUEUE ThreadQueue;
684 BOOL RemoveMessages;
685 UINT ProcessMask;
686 BOOL Hit = FALSE;
687
688 pti = PsGetCurrentThreadWin32Thread();
689 ThreadQueue = pti->MessageQueue;
690 pci = pti->pClientInfo;
691
692 RemoveMessages = RemoveMsg & PM_REMOVE;
693 ProcessMask = HIWORD(RemoveMsg);
694
695 /* Hint, "If wMsgFilterMin and wMsgFilterMax are both zero, PeekMessage returns
696 all available messages (that is, no range filtering is performed)". */
697 if (!ProcessMask) ProcessMask = (QS_ALLPOSTMESSAGE|QS_ALLINPUT);
698
699 IdlePong();
700
701 do
702 {
703 KeQueryTickCount(&LargeTickCount);
704 ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
705 pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart;
706
707 /* Dispatch sent messages here. */
708 while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
709 {
710 /* if some PM_QS* flags were specified, only handle sent messages from now on */
711 if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE; // wine does this; ProcessMask = QS_SENDMESSAGE;
712 }
713 if (Hit) return FALSE;
714
715 /* Clear changed bits so we can wait on them if we don't find a message */
716 if (ProcessMask & QS_POSTMESSAGE)
717 {
718 pti->pcti->fsChangeBits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER);
719 if (MsgFilterMin == 0 && MsgFilterMax == 0) // wine hack does this; ~0U)
720 {
721 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
722 }
723 }
724
725 if (ProcessMask & QS_INPUT)
726 {
727 pti->pcti->fsChangeBits &= ~QS_INPUT;
728 }
729
730 /* Now check for normal messages. */
731 if ((ProcessMask & QS_POSTMESSAGE) &&
732 MsqPeekMessage( ThreadQueue,
733 RemoveMessages,
734 Window,
735 MsgFilterMin,
736 MsgFilterMax,
737 ProcessMask,
738 Msg ))
739 {
740 return TRUE;
741 }
742
743 /* Now look for a quit message. */
744 if (ThreadQueue->QuitPosted)
745 {
746 /* According to the PSDK, WM_QUIT messages are always returned, regardless
747 of the filter specified */
748 Msg->hwnd = NULL;
749 Msg->message = WM_QUIT;
750 Msg->wParam = ThreadQueue->QuitExitCode;
751 Msg->lParam = 0;
752 if (RemoveMessages)
753 {
754 ThreadQueue->QuitPosted = FALSE;
755 ClearMsgBitsMask(ThreadQueue, QS_POSTMESSAGE);
756 pti->pcti->fsWakeBits &= ~QS_ALLPOSTMESSAGE;
757 pti->pcti->fsChangeBits &= ~QS_ALLPOSTMESSAGE;
758 }
759 return TRUE;
760 }
761
762 /* Check for hardware events. */
763 if ((ProcessMask & QS_MOUSE) &&
764 co_MsqPeekMouseMove( ThreadQueue,
765 RemoveMessages,
766 Window,
767 MsgFilterMin,
768 MsgFilterMax,
769 Msg ))
770 {
771 return TRUE;
772 }
773
774 if ((ProcessMask & QS_INPUT) &&
775 co_MsqPeekHardwareMessage( ThreadQueue,
776 RemoveMessages,
777 Window,
778 MsgFilterMin,
779 MsgFilterMax,
780 ProcessMask,
781 Msg))
782 {
783 return TRUE;
784 }
785
786 /* Check for sent messages again. */
787 while ( co_MsqDispatchOneSentMessage(ThreadQueue) )
788 {
789 if (HIWORD(RemoveMsg) && !bGMSG) Hit = TRUE;
790 }
791 if (Hit) return FALSE;
792
793 /* Check for paint messages. */
794 if ((ProcessMask & QS_PAINT) &&
795 pti->cPaintsReady &&
796 IntGetPaintMessage( Window,
797 MsgFilterMin,
798 MsgFilterMax,
799 pti,
800 Msg,
801 RemoveMessages))
802 {
803 return TRUE;
804 }
805
806 /* This is correct, check for the current threads timers waiting to be
807 posted to this threads message queue. If any we loop again.
808 */
809 if ((ProcessMask & QS_TIMER) &&
810 PostTimerMessages(Window))
811 {
812 continue;
813 }
814
815 return FALSE;
816 }
817 while (TRUE);
818
819 return TRUE;
820 }
821
822 static BOOL FASTCALL
823 co_IntWaitMessage( PWND Window,
824 UINT MsgFilterMin,
825 UINT MsgFilterMax )
826 {
827 PTHREADINFO pti;
828 PUSER_MESSAGE_QUEUE ThreadQueue;
829 NTSTATUS Status = STATUS_SUCCESS;
830 MSG Msg;
831
832 pti = PsGetCurrentThreadWin32Thread();
833 ThreadQueue = pti->MessageQueue;
834
835 do
836 {
837 if ( co_IntPeekMessage( &Msg, // Dont reenter!
838 Window,
839 MsgFilterMin,
840 MsgFilterMax,
841 MAKELONG( PM_NOREMOVE, GetWakeMask( MsgFilterMin, MsgFilterMax)),
842 TRUE ) ) // act like GetMessage.
843 {
844 return TRUE;
845 }
846
847 /* Nothing found. Wait for new messages. */
848 Status = co_MsqWaitForNewMessages( ThreadQueue,
849 Window,
850 MsgFilterMin,
851 MsgFilterMax);
852 }
853 while ( (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) ||
854 STATUS_TIMEOUT == Status );
855
856 if (!NT_SUCCESS(Status))
857 {
858 SetLastNtError(Status);
859 DPRINT1("Exit co_IntWaitMessage on error!\n");
860 }
861
862 return FALSE;
863 }
864
865 BOOL FASTCALL
866 co_IntGetPeekMessage( PMSG pMsg,
867 HWND hWnd,
868 UINT MsgFilterMin,
869 UINT MsgFilterMax,
870 UINT RemoveMsg,
871 BOOL bGMSG )
872 {
873 PWND Window;
874 PTHREADINFO pti;
875 BOOL Present = FALSE;
876
877 if ( hWnd == HWND_TOPMOST || hWnd == HWND_BROADCAST )
878 hWnd = HWND_BOTTOM;
879
880 /* Validate input */
881 if (hWnd && hWnd != HWND_BOTTOM)
882 {
883 if (!(Window = UserGetWindowObject(hWnd)))
884 {
885 if (bGMSG)
886 return -1;
887 else
888 return FALSE;
889 }
890 }
891 else
892 {
893 Window = (PWND)hWnd;
894 }
895
896 if (MsgFilterMax < MsgFilterMin)
897 {
898 MsgFilterMin = 0;
899 MsgFilterMax = 0;
900 }
901
902 if (bGMSG)
903 {
904 RemoveMsg |= ((GetWakeMask( MsgFilterMin, MsgFilterMax ))<< 16);
905 }
906
907 pti = PsGetCurrentThreadWin32Thread();
908 pti->pClientInfo->cSpins++; // Bump up the spin count.
909
910 do
911 {
912 Present = co_IntPeekMessage( pMsg,
913 Window,
914 MsgFilterMin,
915 MsgFilterMax,
916 RemoveMsg,
917 bGMSG );
918 if (Present)
919 {
920 /* GetMessage or PostMessage must never get messages that contain pointers */
921 ASSERT(FindMsgMemory(pMsg->message) == NULL);
922
923 if (pMsg->message != WM_PAINT && pMsg->message != WM_QUIT)
924 {
925 pti->timeLast = pMsg->time;
926 pti->ptLast = pMsg->pt;
927 }
928
929 // The WH_GETMESSAGE hook enables an application to monitor messages about to
930 // be returned by the GetMessage or PeekMessage function.
931
932 co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)pMsg);
933
934 if ( bGMSG )
935 {
936 Present = (WM_QUIT != pMsg->message);
937 break;
938 }
939 }
940
941 if ( bGMSG )
942 {
943 if ( !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) )
944 {
945 Present = -1;
946 break;
947 }
948 }
949 else
950 {
951 if (!(RemoveMsg & PM_NOYIELD))
952 {
953 IdlePing();
954 // Yield this thread!
955 UserLeave();
956 ZwYieldExecution();
957 UserEnterExclusive();
958 // Fall through to exit.
959 IdlePong();
960 }
961 break;
962 }
963 }
964 while( bGMSG && !Present );
965
966 // Been spinning, time to swap vinyl...
967 if (pti->pClientInfo->cSpins >= 100)
968 {
969 // Clear the spin cycle to fix the mix.
970 pti->pClientInfo->cSpins = 0;
971 //if (!(pti->TIF_flags & TIF_SPINNING)) FIXME need to swap vinyl..
972 }
973 return Present;
974 }
975
976 BOOL FASTCALL
977 UserPostThreadMessage( DWORD idThread,
978 UINT Msg,
979 WPARAM wParam,
980 LPARAM lParam )
981 {
982 MSG Message;
983 PETHREAD peThread;
984 PTHREADINFO pThread;
985 LARGE_INTEGER LargeTickCount;
986 NTSTATUS Status;
987
988 if (is_pointer_message(Msg))
989 {
990 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
991 return FALSE;
992 }
993
994 Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
995
996 if( Status == STATUS_SUCCESS )
997 {
998 pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
999 if( !pThread ||
1000 !pThread->MessageQueue ||
1001 (pThread->TIF_flags & TIF_INCLEANUP))
1002 {
1003 ObDereferenceObject( peThread );
1004 return FALSE;
1005 }
1006
1007 Message.hwnd = NULL;
1008 Message.message = Msg;
1009 Message.wParam = wParam;
1010 Message.lParam = lParam;
1011 Message.pt = gpsi->ptCursor;
1012
1013 KeQueryTickCount(&LargeTickCount);
1014 Message.time = MsqCalculateMessageTime(&LargeTickCount);
1015 MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1016 ObDereferenceObject( peThread );
1017 return TRUE;
1018 }
1019 else
1020 {
1021 SetLastNtError( Status );
1022 }
1023 return FALSE;
1024 }
1025
1026 BOOL FASTCALL
1027 UserPostMessage( HWND Wnd,
1028 UINT Msg,
1029 WPARAM wParam,
1030 LPARAM lParam )
1031 {
1032 PTHREADINFO pti;
1033 MSG Message, KernelModeMsg;
1034 LARGE_INTEGER LargeTickCount;
1035 PMSGMEMORY MsgMemoryEntry;
1036
1037 Message.hwnd = Wnd;
1038 Message.message = Msg;
1039 Message.wParam = wParam;
1040 Message.lParam = lParam;
1041 Message.pt = gpsi->ptCursor;
1042 KeQueryTickCount(&LargeTickCount);
1043 Message.time = MsqCalculateMessageTime(&LargeTickCount);
1044
1045 MsgMemoryEntry = FindMsgMemory(Message.message);
1046
1047 if( Msg >= WM_DDE_FIRST && Msg <= WM_DDE_LAST )
1048 {
1049 NTSTATUS Status;
1050
1051 Status = CopyMsgToKernelMem(&KernelModeMsg, &Message, MsgMemoryEntry);
1052 if (! NT_SUCCESS(Status))
1053 {
1054 EngSetLastError(ERROR_INVALID_PARAMETER);
1055 return FALSE;
1056 }
1057 co_IntSendMessageNoWait(KernelModeMsg.hwnd,
1058 KernelModeMsg.message,
1059 KernelModeMsg.wParam,
1060 KernelModeMsg.lParam);
1061
1062 if (MsgMemoryEntry && KernelModeMsg.lParam)
1063 ExFreePool((PVOID) KernelModeMsg.lParam);
1064
1065 return TRUE;
1066 }
1067
1068 if (is_pointer_message(Message.message))
1069 {
1070 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1071 return FALSE;
1072 }
1073
1074 if (!Wnd)
1075 {
1076 return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
1077 Msg,
1078 wParam,
1079 lParam);
1080 }
1081 if (Wnd == HWND_BROADCAST)
1082 {
1083 HWND *List;
1084 PWND DesktopWindow;
1085 ULONG i;
1086
1087 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1088 List = IntWinListChildren(DesktopWindow);
1089
1090 if (List != NULL)
1091 {
1092 UserPostMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1093 for (i = 0; List[i]; i++)
1094 {
1095 UserPostMessage(List[i], Msg, wParam, lParam);
1096 }
1097 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1098 }
1099 }
1100 else
1101 {
1102 PWND Window;
1103
1104 Window = UserGetWindowObject(Wnd);
1105 if ( !Window )
1106 {
1107 return FALSE;
1108 }
1109
1110 pti = Window->head.pti;
1111 if ( pti->TIF_flags & TIF_INCLEANUP )
1112 {
1113 DPRINT1("Attempted to post message to window 0x%x when the thread is in cleanup!\n", Wnd);
1114 return FALSE;
1115 }
1116
1117 if ( Window->state & WNDS_DESTROYED )
1118 {
1119 DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
1120 /* FIXME - last error code? */
1121 return FALSE;
1122 }
1123
1124 if (WM_QUIT == Msg)
1125 {
1126 MsqPostQuitMessage(Window->head.pti->MessageQueue, wParam);
1127 }
1128 else
1129 {
1130 MsqPostMessage(Window->head.pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
1131 }
1132 }
1133 return TRUE;
1134 }
1135
1136
1137 LRESULT FASTCALL
1138 co_IntSendMessage( HWND hWnd,
1139 UINT Msg,
1140 WPARAM wParam,
1141 LPARAM lParam )
1142 {
1143 ULONG_PTR Result = 0;
1144 if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
1145 {
1146 return (LRESULT)Result;
1147 }
1148 return 0;
1149 }
1150
1151 static LRESULT FASTCALL
1152 co_IntSendMessageTimeoutSingle( HWND hWnd,
1153 UINT Msg,
1154 WPARAM wParam,
1155 LPARAM lParam,
1156 UINT uFlags,
1157 UINT uTimeout,
1158 ULONG_PTR *uResult )
1159 {
1160 NTSTATUS Status;
1161 PWND Window = NULL;
1162 PMSGMEMORY MsgMemoryEntry;
1163 INT lParamBufferSize;
1164 LPARAM lParamPacked;
1165 PTHREADINFO Win32Thread;
1166 ULONG_PTR Result = 0;
1167 DECLARE_RETURN(LRESULT);
1168 USER_REFERENCE_ENTRY Ref;
1169
1170 if (!(Window = UserGetWindowObject(hWnd)))
1171 {
1172 RETURN( FALSE);
1173 }
1174
1175 UserRefObjectCo(Window, &Ref);
1176
1177 Win32Thread = PsGetCurrentThreadWin32Thread();
1178
1179 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1180
1181 if ( NULL != Win32Thread &&
1182 Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
1183 {
1184 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1185 {
1186 /* Never send messages to exiting threads */
1187 RETURN( FALSE);
1188 }
1189
1190 /* See if this message type is present in the table */
1191 MsgMemoryEntry = FindMsgMemory(Msg);
1192 if (NULL == MsgMemoryEntry)
1193 {
1194 lParamBufferSize = -1;
1195 }
1196 else
1197 {
1198 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1199 }
1200
1201 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
1202 {
1203 DPRINT1("Failed to pack message parameters\n");
1204 RETURN( FALSE);
1205 }
1206
1207 ObReferenceObject(Win32Thread->pEThread);
1208 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1209 !Window->Unicode,
1210 hWnd,
1211 Msg,
1212 wParam,
1213 lParamPacked,
1214 lParamBufferSize );
1215 if(uResult)
1216 {
1217 *uResult = Result;
1218 }
1219
1220 ObDereferenceObject(Win32Thread->pEThread);
1221
1222 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1223
1224 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1225 {
1226 DPRINT1("Failed to unpack message parameters\n");
1227 RETURN( TRUE);
1228 }
1229
1230 RETURN( TRUE);
1231 }
1232
1233 if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->head.pti->MessageQueue))
1234 {
1235 /* FIXME - Set a LastError? */
1236 RETURN( FALSE);
1237 }
1238
1239 if (Window->state & WNDS_DESTROYED)
1240 {
1241 /* FIXME - last error? */
1242 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1243 RETURN( FALSE);
1244 }
1245
1246 do
1247 {
1248 Status = co_MsqSendMessage( Window->head.pti->MessageQueue,
1249 hWnd,
1250 Msg,
1251 wParam,
1252 lParam,
1253 uTimeout,
1254 (uFlags & SMTO_BLOCK),
1255 MSQ_NORMAL,
1256 uResult );
1257 }
1258 while ((STATUS_TIMEOUT == Status) &&
1259 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1260 !MsqIsHung(Window->head.pti->MessageQueue));
1261
1262 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1263
1264 if (STATUS_TIMEOUT == Status)
1265 {
1266 /*
1267 MSDN says:
1268 Microsoft Windows 2000: If GetLastError returns zero, then the function
1269 timed out.
1270 XP+ : If the function fails or times out, the return value is zero.
1271 To get extended error information, call GetLastError. If GetLastError
1272 returns ERROR_TIMEOUT, then the function timed out.
1273 */
1274 EngSetLastError(ERROR_TIMEOUT);
1275 RETURN( FALSE);
1276 }
1277 else if (! NT_SUCCESS(Status))
1278 {
1279 SetLastNtError(Status);
1280 RETURN( FALSE);
1281 }
1282
1283 RETURN( TRUE);
1284
1285 CLEANUP:
1286 if (Window) UserDerefObjectCo(Window);
1287 END_CLEANUP;
1288 }
1289
1290 LRESULT FASTCALL
1291 co_IntSendMessageTimeout( HWND hWnd,
1292 UINT Msg,
1293 WPARAM wParam,
1294 LPARAM lParam,
1295 UINT uFlags,
1296 UINT uTimeout,
1297 ULONG_PTR *uResult )
1298 {
1299 PWND DesktopWindow;
1300 HWND *Children;
1301 HWND *Child;
1302
1303 if (HWND_BROADCAST != hWnd)
1304 {
1305 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1306 }
1307
1308 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1309 if (NULL == DesktopWindow)
1310 {
1311 EngSetLastError(ERROR_INTERNAL_ERROR);
1312 return 0;
1313 }
1314
1315 /* Send message to the desktop window too! */
1316 co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1317
1318 Children = IntWinListChildren(DesktopWindow);
1319 if (NULL == Children)
1320 {
1321 return 0;
1322 }
1323
1324 for (Child = Children; NULL != *Child; Child++)
1325 {
1326 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1327 }
1328
1329 ExFreePool(Children);
1330
1331 return (LRESULT) TRUE;
1332 }
1333
1334 LRESULT FASTCALL
1335 co_IntSendMessageNoWait(HWND hWnd,
1336 UINT Msg,
1337 WPARAM wParam,
1338 LPARAM lParam)
1339 {
1340 ULONG_PTR Result = 0;
1341 co_IntSendMessageWithCallBack(hWnd,
1342 Msg,
1343 wParam,
1344 lParam,
1345 NULL,
1346 0,
1347 &Result);
1348 return Result;
1349 }
1350
1351 LRESULT FASTCALL
1352 co_IntSendMessageWithCallBack( HWND hWnd,
1353 UINT Msg,
1354 WPARAM wParam,
1355 LPARAM lParam,
1356 SENDASYNCPROC CompletionCallback,
1357 ULONG_PTR CompletionCallbackContext,
1358 ULONG_PTR *uResult)
1359 {
1360 ULONG_PTR Result;
1361 PWND Window = NULL;
1362 PMSGMEMORY MsgMemoryEntry;
1363 INT lParamBufferSize;
1364 LPARAM lParamPacked;
1365 PTHREADINFO Win32Thread;
1366 DECLARE_RETURN(LRESULT);
1367 USER_REFERENCE_ENTRY Ref;
1368 PUSER_SENT_MESSAGE Message;
1369
1370 if (!(Window = UserGetWindowObject(hWnd)))
1371 {
1372 RETURN(FALSE);
1373 }
1374
1375 UserRefObjectCo(Window, &Ref);
1376
1377 if (Window->state & WNDS_DESTROYED)
1378 {
1379 /* FIXME - last error? */
1380 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1381 RETURN(FALSE);
1382 }
1383
1384 Win32Thread = PsGetCurrentThreadWin32Thread();
1385
1386 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1387
1388 if (Win32Thread == NULL)
1389 {
1390 ASSERT(FALSE);
1391 RETURN(FALSE);
1392 }
1393
1394 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1395 {
1396 /* Never send messages to exiting threads */
1397 RETURN(FALSE);
1398 }
1399
1400 /* See if this message type is present in the table */
1401 MsgMemoryEntry = FindMsgMemory(Msg);
1402 if (NULL == MsgMemoryEntry)
1403 {
1404 lParamBufferSize = -1;
1405 }
1406 else
1407 {
1408 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1409 }
1410
1411 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, Window->head.pti->MessageQueue != Win32Thread->MessageQueue)))
1412 {
1413 DPRINT1("Failed to pack message parameters\n");
1414 RETURN( FALSE);
1415 }
1416
1417 /* If this is not a callback and it can be sent now, then send it. */
1418 if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
1419 {
1420 ObReferenceObject(Win32Thread->pEThread);
1421 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1422 !Window->Unicode,
1423 hWnd,
1424 Msg,
1425 wParam,
1426 lParamPacked,
1427 lParamBufferSize );
1428 if(uResult)
1429 {
1430 *uResult = Result;
1431 }
1432 ObDereferenceObject(Win32Thread->pEThread);
1433 }
1434
1435 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1436
1437 if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
1438 {
1439 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1440 {
1441 DPRINT1("Failed to unpack message parameters\n");
1442 }
1443 RETURN(TRUE);
1444 }
1445
1446 if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
1447 {
1448 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1449 return STATUS_INSUFFICIENT_RESOURCES;
1450 }
1451
1452 Message->Msg.hwnd = hWnd;
1453 Message->Msg.message = Msg;
1454 Message->Msg.wParam = wParam;
1455 Message->Msg.lParam = lParamPacked;
1456 Message->CompletionEvent = NULL;
1457 Message->Result = 0;
1458 Message->lResult = 0;
1459 Message->QS_Flags = 0;
1460 Message->SenderQueue = NULL; // mjmartin, you are right! This is null.
1461 Message->CallBackSenderQueue = Win32Thread->MessageQueue;
1462
1463 IntReferenceMessageQueue(Window->head.pti->MessageQueue);
1464 Message->CompletionCallback = CompletionCallback;
1465 Message->CompletionCallbackContext = CompletionCallbackContext;
1466 Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT;
1467 Message->HasPackedLParam = (lParamBufferSize > 0);
1468
1469 Message->QS_Flags = QS_SENDMESSAGE;
1470 MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, FALSE);
1471
1472 InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
1473 IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
1474
1475 RETURN(TRUE);
1476
1477 CLEANUP:
1478 if (Window) UserDerefObjectCo(Window);
1479 END_CLEANUP;
1480 }
1481
1482 /* This function posts a message if the destination's message queue belongs to
1483 another thread, otherwise it sends the message. It does not support broadcast
1484 messages! */
1485 LRESULT FASTCALL
1486 co_IntPostOrSendMessage( HWND hWnd,
1487 UINT Msg,
1488 WPARAM wParam,
1489 LPARAM lParam )
1490 {
1491 ULONG_PTR Result;
1492 PTHREADINFO pti;
1493 PWND Window;
1494
1495 if ( hWnd == HWND_BROADCAST )
1496 {
1497 return 0;
1498 }
1499
1500 if(!(Window = UserGetWindowObject(hWnd)))
1501 {
1502 return 0;
1503 }
1504
1505 pti = PsGetCurrentThreadWin32Thread();
1506
1507 if ( Window->head.pti->MessageQueue != pti->MessageQueue &&
1508 FindMsgMemory(Msg) == 0 )
1509 {
1510 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1511 }
1512 else
1513 {
1514 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1515 {
1516 Result = 0;
1517 }
1518 }
1519
1520 return (LRESULT)Result;
1521 }
1522
1523 LRESULT FASTCALL
1524 co_IntDoSendMessage( HWND hWnd,
1525 UINT Msg,
1526 WPARAM wParam,
1527 LPARAM lParam,
1528 PDOSENDMESSAGE dsm)
1529 {
1530 PTHREADINFO pti;
1531 LRESULT Result = TRUE;
1532 NTSTATUS Status;
1533 PWND Window = NULL;
1534 MSG UserModeMsg;
1535 MSG KernelModeMsg;
1536 PMSGMEMORY MsgMemoryEntry;
1537
1538 if (HWND_BROADCAST != hWnd)
1539 {
1540 Window = UserGetWindowObject(hWnd);
1541 if ( !Window )
1542 {
1543 return 0;
1544 }
1545 }
1546
1547 /* Check for an exiting window. */
1548 if (Window && Window->state & WNDS_DESTROYED)
1549 {
1550 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1551 }
1552
1553 /* See if the current thread can handle the message */
1554 pti = PsGetCurrentThreadWin32Thread();
1555
1556 UserModeMsg.hwnd = hWnd;
1557 UserModeMsg.message = Msg;
1558 UserModeMsg.wParam = wParam;
1559 UserModeMsg.lParam = lParam;
1560 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1561
1562 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1563 if (! NT_SUCCESS(Status))
1564 {
1565 EngSetLastError(ERROR_INVALID_PARAMETER);
1566 return (dsm ? 0 : -1);
1567 }
1568
1569 if (!dsm)
1570 {
1571 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1572 KernelModeMsg.message,
1573 KernelModeMsg.wParam,
1574 KernelModeMsg.lParam );
1575 }
1576 else
1577 {
1578 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1579 KernelModeMsg.message,
1580 KernelModeMsg.wParam,
1581 KernelModeMsg.lParam,
1582 dsm->uFlags,
1583 dsm->uTimeout,
1584 &dsm->Result );
1585 }
1586
1587 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1588 if (! NT_SUCCESS(Status))
1589 {
1590 EngSetLastError(ERROR_INVALID_PARAMETER);
1591 return(dsm ? 0 : -1);
1592 }
1593
1594 return (LRESULT)Result;
1595 }
1596
1597 BOOL FASTCALL
1598 UserSendNotifyMessage( HWND hWnd,
1599 UINT Msg,
1600 WPARAM wParam,
1601 LPARAM lParam )
1602 {
1603 BOOL Ret = TRUE;
1604
1605 if (is_pointer_message(Msg))
1606 {
1607 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1608 return FALSE;
1609 }
1610
1611 // Basicly the same as IntPostOrSendMessage
1612 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1613 {
1614 HWND *List;
1615 PWND DesktopWindow;
1616 ULONG i;
1617
1618 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1619 List = IntWinListChildren(DesktopWindow);
1620
1621 if (List != NULL)
1622 {
1623 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1624 for (i = 0; List[i]; i++)
1625 {
1626 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1627 }
1628 ExFreePool(List);
1629 }
1630 }
1631 else
1632 {
1633 ULONG_PTR lResult = 0;
1634 Ret = co_IntSendMessageWithCallBack( hWnd,
1635 Msg,
1636 wParam,
1637 lParam,
1638 NULL,
1639 0,
1640 &lResult);
1641 }
1642 return Ret;
1643 }
1644
1645
1646 DWORD APIENTRY
1647 IntGetQueueStatus(DWORD Changes)
1648 {
1649 PTHREADINFO pti;
1650 PUSER_MESSAGE_QUEUE Queue;
1651 DWORD Result;
1652
1653 pti = PsGetCurrentThreadWin32Thread();
1654 Queue = pti->MessageQueue;
1655 // wine:
1656 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1657
1658 /* High word, types of messages currently in the queue.
1659 Low word, types of messages that have been added to the queue and that
1660 are still in the queue
1661 */
1662 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
1663
1664 pti->pcti->fsChangeBits &= ~Changes;
1665
1666 return Result;
1667 }
1668
1669 BOOL APIENTRY
1670 IntInitMessagePumpHook()
1671 {
1672 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1673
1674 if (pti->pcti)
1675 {
1676 pti->pcti->dwcPumpHook++;
1677 return TRUE;
1678 }
1679 return FALSE;
1680 }
1681
1682 BOOL APIENTRY
1683 IntUninitMessagePumpHook()
1684 {
1685 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1686
1687 if (pti->pcti)
1688 {
1689 if (pti->pcti->dwcPumpHook <= 0)
1690 {
1691 return FALSE;
1692 }
1693 pti->pcti->dwcPumpHook--;
1694 return TRUE;
1695 }
1696 return FALSE;
1697 }
1698
1699 /** Functions ******************************************************************/
1700
1701 BOOL APIENTRY
1702 NtUserPostMessage(HWND hWnd,
1703 UINT Msg,
1704 WPARAM wParam,
1705 LPARAM lParam)
1706 {
1707 BOOL ret;
1708
1709 UserEnterExclusive();
1710
1711 ret = UserPostMessage(hWnd, Msg, wParam, lParam);
1712
1713 UserLeave();
1714
1715 return ret;
1716 }
1717
1718 BOOL APIENTRY
1719 NtUserPostThreadMessage(DWORD idThread,
1720 UINT Msg,
1721 WPARAM wParam,
1722 LPARAM lParam)
1723 {
1724 BOOL ret;
1725
1726 UserEnterExclusive();
1727
1728 ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
1729
1730 UserLeave();
1731
1732 return ret;
1733 }
1734
1735 BOOL APIENTRY
1736 NtUserWaitMessage(VOID)
1737 {
1738 BOOL ret;
1739
1740 UserEnterExclusive();
1741 DPRINT("NtUserWaitMessage Enter\n");
1742 ret = co_IntWaitMessage(NULL, 0, 0);
1743 DPRINT("NtUserWaitMessage Leave\n");
1744 UserLeave();
1745
1746 return ret;
1747 }
1748
1749 BOOL APIENTRY
1750 NtUserGetMessage(PMSG pMsg,
1751 HWND hWnd,
1752 UINT MsgFilterMin,
1753 UINT MsgFilterMax )
1754 {
1755 MSG Msg;
1756 BOOL Ret;
1757
1758 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
1759 {
1760 EngSetLastError(ERROR_INVALID_PARAMETER);
1761 return FALSE;
1762 }
1763
1764 UserEnterExclusive();
1765
1766 RtlZeroMemory(&Msg, sizeof(MSG));
1767
1768 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
1769
1770 UserLeave();
1771
1772 if (Ret)
1773 {
1774 _SEH2_TRY
1775 {
1776 ProbeForWrite(pMsg, sizeof(MSG), 1);
1777 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1778 }
1779 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1780 {
1781 SetLastNtError(_SEH2_GetExceptionCode());
1782 Ret = FALSE;
1783 }
1784 _SEH2_END;
1785 }
1786
1787 return Ret;
1788 }
1789
1790 BOOL APIENTRY
1791 NtUserPeekMessage( PMSG pMsg,
1792 HWND hWnd,
1793 UINT MsgFilterMin,
1794 UINT MsgFilterMax,
1795 UINT RemoveMsg)
1796 {
1797 MSG Msg;
1798 BOOL Ret;
1799
1800 if ( RemoveMsg & PM_BADMSGFLAGS )
1801 {
1802 EngSetLastError(ERROR_INVALID_FLAGS);
1803 return FALSE;
1804 }
1805
1806 UserEnterExclusive();
1807
1808 RtlZeroMemory(&Msg, sizeof(MSG));
1809
1810 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
1811
1812 UserLeave();
1813
1814 if (Ret)
1815 {
1816 _SEH2_TRY
1817 {
1818 ProbeForWrite(pMsg, sizeof(MSG), 1);
1819 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1820 }
1821 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1822 {
1823 SetLastNtError(_SEH2_GetExceptionCode());
1824 Ret = FALSE;
1825 }
1826 _SEH2_END;
1827 }
1828
1829 return Ret;
1830 }
1831
1832 BOOL APIENTRY
1833 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
1834 {
1835 BOOL Ret = FALSE;
1836 MSG Msg;
1837
1838 _SEH2_TRY
1839 {
1840 ProbeForRead(lpmsg, sizeof(MSG), 1);
1841 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
1842 }
1843 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1844 {
1845 _SEH2_YIELD(return FALSE);
1846 }
1847 _SEH2_END;
1848
1849 UserEnterExclusive();
1850
1851 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
1852 {
1853 Ret = TRUE;
1854 }
1855 else
1856 {
1857 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
1858 }
1859
1860 UserLeave();
1861
1862 _SEH2_TRY
1863 {
1864 ProbeForWrite(lpmsg, sizeof(MSG), 1);
1865 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
1866 }
1867 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1868 {
1869 Ret = FALSE;
1870 }
1871 _SEH2_END;
1872
1873 return Ret;
1874 }
1875
1876 LRESULT APIENTRY
1877 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
1878 {
1879 LRESULT Res = 0;
1880 MSG SafeMsg;
1881
1882 _SEH2_TRY
1883 {
1884 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
1885 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
1886 }
1887 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1888 {
1889 SetLastNtError(_SEH2_GetExceptionCode());
1890 _SEH2_YIELD(return FALSE);
1891 }
1892 _SEH2_END;
1893
1894 UserEnterExclusive();
1895
1896 Res = IntDispatchMessage(&SafeMsg);
1897
1898 UserLeave();
1899 return Res;
1900 }
1901
1902
1903 BOOL APIENTRY
1904 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
1905 {
1906 MSG SafeMsg;
1907 BOOL Ret;
1908
1909 _SEH2_TRY
1910 {
1911 ProbeForRead(lpMsg, sizeof(MSG), 1);
1912 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
1913 }
1914 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1915 {
1916 SetLastNtError(_SEH2_GetExceptionCode());
1917 _SEH2_YIELD(return FALSE);
1918 }
1919 _SEH2_END;
1920
1921 UserEnterExclusive();
1922
1923 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
1924
1925 UserLeave();
1926
1927 return Ret;
1928 }
1929
1930 BOOL APIENTRY
1931 NtUserMessageCall( HWND hWnd,
1932 UINT Msg,
1933 WPARAM wParam,
1934 LPARAM lParam,
1935 ULONG_PTR ResultInfo,
1936 DWORD dwType, // fnID?
1937 BOOL Ansi)
1938 {
1939 LRESULT lResult = 0;
1940 BOOL Ret = FALSE;
1941 PWND Window = NULL;
1942 USER_REFERENCE_ENTRY Ref;
1943
1944 UserEnterExclusive();
1945
1946 /* Validate input */
1947 if (hWnd && (hWnd != INVALID_HANDLE_VALUE))
1948 {
1949 Window = UserGetWindowObject(hWnd);
1950 if (!Window)
1951 {
1952 UserLeave();
1953 return FALSE;
1954 }
1955 }
1956
1957 switch(dwType)
1958 {
1959 case FNID_DEFWINDOWPROC:
1960 if (Window) UserRefObjectCo(Window, &Ref);
1961 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
1962 Ret = TRUE;
1963 if (Window) UserDerefObjectCo(Window);
1964 break;
1965 case FNID_SENDNOTIFYMESSAGE:
1966 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
1967 break;
1968 case FNID_BROADCASTSYSTEMMESSAGE:
1969 {
1970 BROADCASTPARM parm;
1971 DWORD_PTR RetVal = 0;
1972
1973 if (ResultInfo)
1974 {
1975 _SEH2_TRY
1976 {
1977 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
1978 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
1979 }
1980 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1981 {
1982 Ret = FALSE;
1983 _SEH2_YIELD(break);
1984 }
1985 _SEH2_END;
1986 }
1987 else
1988 break;
1989
1990 if ( parm.recipients & BSM_ALLDESKTOPS ||
1991 parm.recipients == BSM_ALLCOMPONENTS )
1992 {
1993 }
1994 else if (parm.recipients & BSM_APPLICATIONS)
1995 {
1996 if (parm.flags & BSF_QUERY)
1997 {
1998 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
1999 {
2000 co_IntSendMessageTimeout( HWND_BROADCAST,
2001 Msg,
2002 wParam,
2003 lParam,
2004 SMTO_ABORTIFHUNG,
2005 2000,
2006 &RetVal);
2007 }
2008 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2009 {
2010 co_IntSendMessageTimeout( HWND_BROADCAST,
2011 Msg,
2012 wParam,
2013 lParam,
2014 SMTO_NOTIMEOUTIFNOTHUNG,
2015 2000,
2016 &RetVal);
2017 }
2018 else
2019 {
2020 co_IntSendMessageTimeout( HWND_BROADCAST,
2021 Msg,
2022 wParam,
2023 lParam,
2024 SMTO_NORMAL,
2025 2000,
2026 &RetVal);
2027 }
2028 Ret = RetVal;
2029 }
2030 else if (parm.flags & BSF_POSTMESSAGE)
2031 {
2032 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2033 }
2034 else //Everything else,,,, if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2035 {
2036 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2037 }
2038 }
2039 }
2040 break;
2041 case FNID_SENDMESSAGECALLBACK:
2042 {
2043 CALL_BACK_INFO CallBackInfo;
2044 ULONG_PTR uResult;
2045
2046 _SEH2_TRY
2047 {
2048 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
2049 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
2050 }
2051 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2052 {
2053 Ret = FALSE;
2054 _SEH2_YIELD(break);
2055 }
2056 _SEH2_END;
2057
2058 if (!co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2059 CallBackInfo.CallBack, CallBackInfo.Context, &uResult))
2060 {
2061 DPRINT1("Callback failure!\n");
2062 }
2063 }
2064 break;
2065 case FNID_SENDMESSAGE:
2066 {
2067 Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
2068
2069 if (ResultInfo)
2070 {
2071 _SEH2_TRY
2072 {
2073 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
2074 RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
2075 }
2076 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2077 {
2078 Ret = FALSE;
2079 _SEH2_YIELD(break);
2080 }
2081 _SEH2_END;
2082 }
2083 break;
2084 }
2085 case FNID_SENDMESSAGETIMEOUT:
2086 {
2087 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
2088 if (ResultInfo)
2089 {
2090 _SEH2_TRY
2091 {
2092 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
2093 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
2094 }
2095 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2096 {
2097 Ret = FALSE;
2098 _SEH2_YIELD(break);
2099 }
2100 _SEH2_END;
2101 }
2102
2103 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
2104
2105 if (pdsm)
2106 {
2107 _SEH2_TRY
2108 {
2109 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
2110 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2111 }
2112 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2113 {
2114 Ret = FALSE;
2115 _SEH2_YIELD(break);
2116 }
2117 _SEH2_END;
2118 }
2119 break;
2120 }
2121 // CallNextHook bypass.
2122 case FNID_CALLWNDPROC:
2123 case FNID_CALLWNDPROCRET:
2124 {
2125 PTHREADINFO pti;
2126 PCLIENTINFO ClientInfo;
2127 PHOOK NextObj, Hook;
2128
2129 pti = GetW32ThreadInfo();
2130
2131 Hook = pti->sphkCurrent;
2132
2133 if (!Hook) break;
2134
2135 NextObj = Hook->phkNext;
2136 ClientInfo = pti->pClientInfo;
2137 _SEH2_TRY
2138 {
2139 ClientInfo->phkCurrent = NextObj;
2140 }
2141 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2142 {
2143 ClientInfo = NULL;
2144 }
2145 _SEH2_END;
2146
2147 if (!ClientInfo || !NextObj) break;
2148
2149 NextObj->phkNext = IntGetNextHook(NextObj);
2150
2151 if ( Hook->HookId == WH_CALLWNDPROC)
2152 {
2153 CWPSTRUCT CWP;
2154 CWP.hwnd = hWnd;
2155 CWP.message = Msg;
2156 CWP.wParam = wParam;
2157 CWP.lParam = lParam;
2158 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2159
2160 lResult = co_IntCallHookProc( Hook->HookId,
2161 HC_ACTION,
2162 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2163 (LPARAM)&CWP,
2164 Hook->Proc,
2165 Hook->Ansi,
2166 &Hook->ModuleName);
2167 }
2168 else
2169 {
2170 CWPRETSTRUCT CWPR;
2171 CWPR.hwnd = hWnd;
2172 CWPR.message = Msg;
2173 CWPR.wParam = wParam;
2174 CWPR.lParam = lParam;
2175 CWPR.lResult = ClientInfo->dwHookData;
2176
2177 lResult = co_IntCallHookProc( Hook->HookId,
2178 HC_ACTION,
2179 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2180 (LPARAM)&CWPR,
2181 Hook->Proc,
2182 Hook->Ansi,
2183 &Hook->ModuleName);
2184 }
2185 }
2186 break;
2187 }
2188
2189 switch(dwType)
2190 {
2191 case FNID_DEFWINDOWPROC:
2192 case FNID_CALLWNDPROC:
2193 case FNID_CALLWNDPROCRET:
2194 if (ResultInfo)
2195 {
2196 _SEH2_TRY
2197 {
2198 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2199 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2200 }
2201 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2202 {
2203 Ret = FALSE;
2204 }
2205 _SEH2_END;
2206 }
2207 break;
2208 default:
2209 break;
2210 }
2211
2212 UserLeave();
2213
2214 return Ret;
2215 }
2216
2217 #define INFINITE 0xFFFFFFFF
2218 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2219
2220 DWORD
2221 APIENTRY
2222 NtUserWaitForInputIdle( IN HANDLE hProcess,
2223 IN DWORD dwMilliseconds,
2224 IN BOOL Unknown2)
2225 {
2226 PEPROCESS Process;
2227 PPROCESSINFO W32Process;
2228 PTHREADINFO pti;
2229 NTSTATUS Status;
2230 HANDLE Handles[3];
2231 LARGE_INTEGER Timeout;
2232
2233 UserEnterExclusive();
2234
2235 Status = ObReferenceObjectByHandle(hProcess,
2236 PROCESS_QUERY_INFORMATION,
2237 PsProcessType,
2238 UserMode,
2239 (PVOID*)&Process,
2240 NULL);
2241
2242 if (!NT_SUCCESS(Status))
2243 {
2244 UserLeave();
2245 SetLastNtError(Status);
2246 return WAIT_FAILED;
2247 }
2248
2249 pti = PsGetCurrentThreadWin32Thread();
2250
2251 W32Process = (PPROCESSINFO)Process->Win32Process;
2252
2253 if ( PsGetProcessExitProcessCalled(Process) ||
2254 !W32Process ||
2255 pti->ppi == W32Process)
2256 {
2257 ObDereferenceObject(Process);
2258 UserLeave();
2259 EngSetLastError(ERROR_INVALID_PARAMETER);
2260 return WAIT_FAILED;
2261 }
2262
2263 Handles[0] = Process;
2264 Handles[1] = W32Process->InputIdleEvent;
2265 Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2266
2267 if (!Handles[1])
2268 {
2269 ObDereferenceObject(Process);
2270 UserLeave();
2271 return STATUS_SUCCESS; /* no event to wait on */
2272 }
2273
2274 if (dwMilliseconds != INFINITE)
2275 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2276
2277 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2278 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2279 {
2280 pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2281 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2282 }
2283
2284 DPRINT("WFII: ppi 0x%x\n",W32Process);
2285 DPRINT("WFII: waiting for %p\n", Handles[1] );
2286 do
2287 {
2288 UserLeave();
2289 Status = KeWaitForMultipleObjects( 3,
2290 Handles,
2291 WaitAny,
2292 UserRequest,
2293 UserMode,
2294 FALSE,
2295 dwMilliseconds == INFINITE ? NULL : &Timeout,
2296 NULL);
2297 UserEnterExclusive();
2298
2299 if (!NT_SUCCESS(Status))
2300 {
2301 SetLastNtError(Status);
2302 Status = WAIT_FAILED;
2303 goto WaitExit;
2304 }
2305
2306 switch (Status)
2307 {
2308 case STATUS_WAIT_0:
2309 goto WaitExit;
2310
2311 case STATUS_WAIT_2:
2312 {
2313 MSG Msg;
2314 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
2315 DPRINT1("WFII: WAIT 2\n");
2316 }
2317 break;
2318
2319 case STATUS_TIMEOUT:
2320 DPRINT1("WFII: timeout\n");
2321 case WAIT_FAILED:
2322 goto WaitExit;
2323
2324 default:
2325 DPRINT1("WFII: finished\n");
2326 Status = STATUS_SUCCESS;
2327 goto WaitExit;
2328 }
2329 }
2330 while (TRUE);
2331
2332 WaitExit:
2333 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2334 {
2335 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
2336 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2337 }
2338 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
2339 ObDereferenceObject(Process);
2340 UserLeave();
2341 return Status;
2342 }
2343
2344 /* EOF */