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