[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( Window->head.pti->MessageQueue,
1265 hWnd,
1266 Msg,
1267 wParam,
1268 lParam,
1269 uTimeout,
1270 (uFlags & SMTO_BLOCK),
1271 MSQ_NORMAL,
1272 uResult );
1273 }
1274 while ((STATUS_TIMEOUT == Status) &&
1275 (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
1276 !MsqIsHung(Window->head.pti->MessageQueue)); // FIXME - Set window hung and add to a list.
1277
1278 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1279
1280 if (STATUS_TIMEOUT == Status)
1281 {
1282 /*
1283 MSDN says:
1284 Microsoft Windows 2000: If GetLastError returns zero, then the function
1285 timed out.
1286 XP+ : If the function fails or times out, the return value is zero.
1287 To get extended error information, call GetLastError. If GetLastError
1288 returns ERROR_TIMEOUT, then the function timed out.
1289 */
1290 EngSetLastError(ERROR_TIMEOUT);
1291 RETURN( FALSE);
1292 }
1293 else if (! NT_SUCCESS(Status))
1294 {
1295 SetLastNtError(Status);
1296 RETURN( FALSE);
1297 }
1298
1299 RETURN( TRUE);
1300
1301 CLEANUP:
1302 if (Window) UserDerefObjectCo(Window);
1303 END_CLEANUP;
1304 }
1305
1306 LRESULT FASTCALL
1307 co_IntSendMessageTimeout( HWND hWnd,
1308 UINT Msg,
1309 WPARAM wParam,
1310 LPARAM lParam,
1311 UINT uFlags,
1312 UINT uTimeout,
1313 ULONG_PTR *uResult )
1314 {
1315 PWND DesktopWindow;
1316 HWND *Children;
1317 HWND *Child;
1318
1319 if (HWND_BROADCAST != hWnd)
1320 {
1321 return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1322 }
1323
1324 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1325 if (NULL == DesktopWindow)
1326 {
1327 EngSetLastError(ERROR_INTERNAL_ERROR);
1328 return 0;
1329 }
1330
1331 /* Send message to the desktop window too! */
1332 co_IntSendMessageTimeoutSingle(DesktopWindow->head.h, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1333
1334 Children = IntWinListChildren(DesktopWindow);
1335 if (NULL == Children)
1336 {
1337 return 0;
1338 }
1339
1340 for (Child = Children; NULL != *Child; Child++)
1341 {
1342 co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
1343 }
1344
1345 ExFreePool(Children);
1346
1347 return (LRESULT) TRUE;
1348 }
1349
1350 LRESULT FASTCALL
1351 co_IntSendMessageNoWait(HWND hWnd,
1352 UINT Msg,
1353 WPARAM wParam,
1354 LPARAM lParam)
1355 {
1356 ULONG_PTR Result = 0;
1357 co_IntSendMessageWithCallBack(hWnd,
1358 Msg,
1359 wParam,
1360 lParam,
1361 NULL,
1362 0,
1363 &Result);
1364 return Result;
1365 }
1366 /* MSDN:
1367 If you send a message in the range below WM_USER to the asynchronous message
1368 functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its
1369 message parameters cannot include pointers. Otherwise, the operation will fail.
1370 The functions will return before the receiving thread has had a chance to
1371 process the message and the sender will free the memory before it is used.
1372 */
1373 LRESULT FASTCALL
1374 co_IntSendMessageWithCallBack( HWND hWnd,
1375 UINT Msg,
1376 WPARAM wParam,
1377 LPARAM lParam,
1378 SENDASYNCPROC CompletionCallback,
1379 ULONG_PTR CompletionCallbackContext,
1380 ULONG_PTR *uResult)
1381 {
1382 ULONG_PTR Result;
1383 PWND Window = NULL;
1384 PMSGMEMORY MsgMemoryEntry;
1385 INT lParamBufferSize;
1386 LPARAM lParamPacked;
1387 PTHREADINFO Win32Thread;
1388 DECLARE_RETURN(LRESULT);
1389 USER_REFERENCE_ENTRY Ref;
1390 PUSER_SENT_MESSAGE Message;
1391
1392 if (!(Window = UserGetWindowObject(hWnd)))
1393 {
1394 RETURN(FALSE);
1395 }
1396
1397 UserRefObjectCo(Window, &Ref);
1398
1399 if (Window->state & WNDS_DESTROYED)
1400 {
1401 /* FIXME - last error? */
1402 DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
1403 RETURN(FALSE);
1404 }
1405
1406 Win32Thread = PsGetCurrentThreadWin32Thread();
1407
1408 IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
1409
1410 if (Win32Thread == NULL)
1411 {
1412 ASSERT(FALSE);
1413 RETURN(FALSE);
1414 }
1415
1416 if (Win32Thread->TIF_flags & TIF_INCLEANUP)
1417 {
1418 /* Never send messages to exiting threads */
1419 RETURN(FALSE);
1420 }
1421
1422 /* See if this message type is present in the table */
1423 MsgMemoryEntry = FindMsgMemory(Msg);
1424 if (NULL == MsgMemoryEntry)
1425 {
1426 lParamBufferSize = -1;
1427 }
1428 else
1429 {
1430 lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
1431 }
1432
1433 if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, Window->head.pti->MessageQueue != Win32Thread->MessageQueue)))
1434 {
1435 DPRINT1("Failed to pack message parameters\n");
1436 RETURN( FALSE);
1437 }
1438
1439 /* If this is not a callback and it can be sent now, then send it. */
1440 if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
1441 {
1442 ObReferenceObject(Win32Thread->pEThread);
1443 Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
1444 !Window->Unicode,
1445 hWnd,
1446 Msg,
1447 wParam,
1448 lParamPacked,
1449 lParamBufferSize );
1450 if(uResult)
1451 {
1452 *uResult = Result;
1453 }
1454 ObDereferenceObject(Win32Thread->pEThread);
1455 }
1456
1457 IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
1458
1459 if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
1460 {
1461 if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
1462 {
1463 DPRINT1("Failed to unpack message parameters\n");
1464 }
1465 RETURN(TRUE);
1466 }
1467
1468 if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
1469 {
1470 DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
1471 RETURN( FALSE);
1472 }
1473
1474 Message->Msg.hwnd = hWnd;
1475 Message->Msg.message = Msg;
1476 Message->Msg.wParam = wParam;
1477 Message->Msg.lParam = lParamPacked;
1478 Message->CompletionEvent = NULL;
1479 Message->Result = 0;
1480 Message->lResult = 0;
1481 Message->QS_Flags = 0;
1482 Message->SenderQueue = NULL; // mjmartin, you are right! This is null.
1483 Message->CallBackSenderQueue = Win32Thread->MessageQueue;
1484
1485 IntReferenceMessageQueue(Window->head.pti->MessageQueue);
1486 Message->CompletionCallback = CompletionCallback;
1487 Message->CompletionCallbackContext = CompletionCallbackContext;
1488 Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT;
1489 Message->HasPackedLParam = (lParamBufferSize > 0);
1490
1491 Message->QS_Flags = QS_SENDMESSAGE;
1492 MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, FALSE);
1493
1494 InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
1495 IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
1496
1497 RETURN(TRUE);
1498
1499 CLEANUP:
1500 if (Window) UserDerefObjectCo(Window);
1501 END_CLEANUP;
1502 }
1503
1504 /* This function posts a message if the destination's message queue belongs to
1505 another thread, otherwise it sends the message. It does not support broadcast
1506 messages! */
1507 LRESULT FASTCALL
1508 co_IntPostOrSendMessage( HWND hWnd,
1509 UINT Msg,
1510 WPARAM wParam,
1511 LPARAM lParam )
1512 {
1513 ULONG_PTR Result;
1514 PTHREADINFO pti;
1515 PWND Window;
1516
1517 if ( hWnd == HWND_BROADCAST )
1518 {
1519 return 0;
1520 }
1521
1522 if(!(Window = UserGetWindowObject(hWnd)))
1523 {
1524 return 0;
1525 }
1526
1527 pti = PsGetCurrentThreadWin32Thread();
1528
1529 if ( Window->head.pti->MessageQueue != pti->MessageQueue &&
1530 FindMsgMemory(Msg) == 0 )
1531 {
1532 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1533 }
1534 else
1535 {
1536 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1537 {
1538 Result = 0;
1539 }
1540 }
1541
1542 return (LRESULT)Result;
1543 }
1544
1545 LRESULT FASTCALL
1546 co_IntDoSendMessage( HWND hWnd,
1547 UINT Msg,
1548 WPARAM wParam,
1549 LPARAM lParam,
1550 PDOSENDMESSAGE dsm)
1551 {
1552 PTHREADINFO pti;
1553 LRESULT Result = TRUE;
1554 NTSTATUS Status;
1555 PWND Window = NULL;
1556 MSG UserModeMsg;
1557 MSG KernelModeMsg;
1558 PMSGMEMORY MsgMemoryEntry;
1559
1560 if (HWND_BROADCAST != hWnd)
1561 {
1562 Window = UserGetWindowObject(hWnd);
1563 if ( !Window )
1564 {
1565 return 0;
1566 }
1567 }
1568
1569 /* Check for an exiting window. */
1570 if (Window && Window->state & WNDS_DESTROYED)
1571 {
1572 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1573 }
1574
1575 /* See if the current thread can handle the message */
1576 pti = PsGetCurrentThreadWin32Thread();
1577
1578 UserModeMsg.hwnd = hWnd;
1579 UserModeMsg.message = Msg;
1580 UserModeMsg.wParam = wParam;
1581 UserModeMsg.lParam = lParam;
1582 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1583
1584 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1585 if (! NT_SUCCESS(Status))
1586 {
1587 EngSetLastError(ERROR_INVALID_PARAMETER);
1588 return (dsm ? 0 : -1);
1589 }
1590
1591 if (!dsm)
1592 {
1593 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1594 KernelModeMsg.message,
1595 KernelModeMsg.wParam,
1596 KernelModeMsg.lParam );
1597 }
1598 else
1599 {
1600 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1601 KernelModeMsg.message,
1602 KernelModeMsg.wParam,
1603 KernelModeMsg.lParam,
1604 dsm->uFlags,
1605 dsm->uTimeout,
1606 &dsm->Result );
1607 }
1608
1609 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1610 if (! NT_SUCCESS(Status))
1611 {
1612 EngSetLastError(ERROR_INVALID_PARAMETER);
1613 return(dsm ? 0 : -1);
1614 }
1615
1616 return (LRESULT)Result;
1617 }
1618
1619 BOOL FASTCALL
1620 UserSendNotifyMessage( HWND hWnd,
1621 UINT Msg,
1622 WPARAM wParam,
1623 LPARAM lParam )
1624 {
1625 BOOL Ret = TRUE;
1626
1627 if (is_pointer_message(Msg))
1628 {
1629 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1630 return FALSE;
1631 }
1632
1633 // Basicly the same as IntPostOrSendMessage
1634 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1635 {
1636 HWND *List;
1637 PWND DesktopWindow;
1638 ULONG i;
1639
1640 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1641 List = IntWinListChildren(DesktopWindow);
1642
1643 if (List != NULL)
1644 {
1645 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1646 for (i = 0; List[i]; i++)
1647 {
1648 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1649 }
1650 ExFreePool(List);
1651 }
1652 }
1653 else
1654 {
1655 ULONG_PTR lResult = 0;
1656 Ret = co_IntSendMessageWithCallBack( hWnd,
1657 Msg,
1658 wParam,
1659 lParam,
1660 NULL,
1661 0,
1662 &lResult);
1663 }
1664 return Ret;
1665 }
1666
1667
1668 DWORD APIENTRY
1669 IntGetQueueStatus(DWORD Changes)
1670 {
1671 PTHREADINFO pti;
1672 PUSER_MESSAGE_QUEUE Queue;
1673 DWORD Result;
1674
1675 pti = PsGetCurrentThreadWin32Thread();
1676 Queue = pti->MessageQueue;
1677 // wine:
1678 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1679
1680 /* High word, types of messages currently in the queue.
1681 Low word, types of messages that have been added to the queue and that
1682 are still in the queue
1683 */
1684 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
1685
1686 pti->pcti->fsChangeBits &= ~Changes;
1687
1688 return Result;
1689 }
1690
1691 BOOL APIENTRY
1692 IntInitMessagePumpHook()
1693 {
1694 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1695
1696 if (pti->pcti)
1697 {
1698 pti->pcti->dwcPumpHook++;
1699 return TRUE;
1700 }
1701 return FALSE;
1702 }
1703
1704 BOOL APIENTRY
1705 IntUninitMessagePumpHook()
1706 {
1707 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1708
1709 if (pti->pcti)
1710 {
1711 if (pti->pcti->dwcPumpHook <= 0)
1712 {
1713 return FALSE;
1714 }
1715 pti->pcti->dwcPumpHook--;
1716 return TRUE;
1717 }
1718 return FALSE;
1719 }
1720
1721 /** Functions ******************************************************************/
1722
1723 BOOL
1724 APIENTRY
1725 NtUserDragDetect(
1726 HWND hWnd,
1727 POINT pt) // Just like the User call.
1728 {
1729 MSG msg;
1730 RECT rect;
1731 WORD wDragWidth, wDragHeight;
1732 DECLARE_RETURN(BOOL);
1733
1734 DPRINT("Enter NtUserDragDetect(%x)\n", hWnd);
1735 UserEnterExclusive();
1736
1737 wDragWidth = UserGetSystemMetrics(SM_CXDRAG);
1738 wDragHeight= UserGetSystemMetrics(SM_CYDRAG);
1739
1740 rect.left = pt.x - wDragWidth;
1741 rect.right = pt.x + wDragWidth;
1742
1743 rect.top = pt.y - wDragHeight;
1744 rect.bottom = pt.y + wDragHeight;
1745
1746 co_UserSetCapture(hWnd);
1747
1748 for (;;)
1749 {
1750 while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) ||
1751 co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC, WM_QUEUESYNC, PM_REMOVE, FALSE ) ||
1752 co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE, FALSE ) )
1753 {
1754 if ( msg.message == WM_LBUTTONUP )
1755 {
1756 co_UserSetCapture(NULL);
1757 RETURN( FALSE);
1758 }
1759 if ( msg.message == WM_MOUSEMOVE )
1760 {
1761 POINT tmp;
1762 tmp.x = (short)LOWORD(msg.lParam);
1763 tmp.y = (short)HIWORD(msg.lParam);
1764 if( !IntPtInRect( &rect, tmp ) )
1765 {
1766 co_UserSetCapture(NULL);
1767 RETURN( TRUE);
1768 }
1769 }
1770 if ( msg.message == WM_KEYDOWN )
1771 {
1772 if ( msg.wParam == VK_ESCAPE )
1773 {
1774 co_UserSetCapture(NULL);
1775 RETURN( TRUE);
1776 }
1777 }
1778 if ( msg.message == WM_QUEUESYNC )
1779 {
1780 co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 );
1781 }
1782 }
1783 co_IntWaitMessage(NULL, 0, 0);
1784 }
1785 RETURN( FALSE);
1786
1787 CLEANUP:
1788 DPRINT("Leave NtUserDragDetect, ret=%i\n",_ret_);
1789 UserLeave();
1790 END_CLEANUP;
1791 }
1792
1793 BOOL APIENTRY
1794 NtUserPostMessage(HWND hWnd,
1795 UINT Msg,
1796 WPARAM wParam,
1797 LPARAM lParam)
1798 {
1799 BOOL ret;
1800
1801 UserEnterExclusive();
1802
1803 ret = UserPostMessage(hWnd, Msg, wParam, lParam);
1804
1805 UserLeave();
1806
1807 return ret;
1808 }
1809
1810 BOOL APIENTRY
1811 NtUserPostThreadMessage(DWORD idThread,
1812 UINT Msg,
1813 WPARAM wParam,
1814 LPARAM lParam)
1815 {
1816 BOOL ret;
1817
1818 UserEnterExclusive();
1819
1820 ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
1821
1822 UserLeave();
1823
1824 return ret;
1825 }
1826
1827 BOOL APIENTRY
1828 NtUserWaitMessage(VOID)
1829 {
1830 BOOL ret;
1831
1832 UserEnterExclusive();
1833 DPRINT("NtUserWaitMessage Enter\n");
1834 ret = co_IntWaitMessage(NULL, 0, 0);
1835 DPRINT("NtUserWaitMessage Leave\n");
1836 UserLeave();
1837
1838 return ret;
1839 }
1840
1841 BOOL APIENTRY
1842 NtUserGetMessage(PMSG pMsg,
1843 HWND hWnd,
1844 UINT MsgFilterMin,
1845 UINT MsgFilterMax )
1846 {
1847 MSG Msg;
1848 BOOL Ret;
1849
1850 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
1851 {
1852 EngSetLastError(ERROR_INVALID_PARAMETER);
1853 return FALSE;
1854 }
1855
1856 UserEnterExclusive();
1857
1858 RtlZeroMemory(&Msg, sizeof(MSG));
1859
1860 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
1861
1862 UserLeave();
1863
1864 if (Ret)
1865 {
1866 _SEH2_TRY
1867 {
1868 ProbeForWrite(pMsg, sizeof(MSG), 1);
1869 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1870 }
1871 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1872 {
1873 SetLastNtError(_SEH2_GetExceptionCode());
1874 Ret = FALSE;
1875 }
1876 _SEH2_END;
1877 }
1878
1879 return Ret ? (WM_QUIT != pMsg->message) : FALSE;
1880 }
1881
1882 BOOL APIENTRY
1883 NtUserPeekMessage( PMSG pMsg,
1884 HWND hWnd,
1885 UINT MsgFilterMin,
1886 UINT MsgFilterMax,
1887 UINT RemoveMsg)
1888 {
1889 MSG Msg;
1890 BOOL Ret;
1891
1892 if ( RemoveMsg & PM_BADMSGFLAGS )
1893 {
1894 EngSetLastError(ERROR_INVALID_FLAGS);
1895 return FALSE;
1896 }
1897
1898 UserEnterExclusive();
1899
1900 RtlZeroMemory(&Msg, sizeof(MSG));
1901
1902 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
1903
1904 UserLeave();
1905
1906 if (Ret)
1907 {
1908 _SEH2_TRY
1909 {
1910 ProbeForWrite(pMsg, sizeof(MSG), 1);
1911 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1912 }
1913 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1914 {
1915 SetLastNtError(_SEH2_GetExceptionCode());
1916 Ret = FALSE;
1917 }
1918 _SEH2_END;
1919 }
1920
1921 return Ret;
1922 }
1923
1924 BOOL APIENTRY
1925 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
1926 {
1927 BOOL Ret = FALSE;
1928 MSG Msg;
1929
1930 _SEH2_TRY
1931 {
1932 ProbeForRead(lpmsg, sizeof(MSG), 1);
1933 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
1934 }
1935 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1936 {
1937 _SEH2_YIELD(return FALSE);
1938 }
1939 _SEH2_END;
1940
1941 UserEnterExclusive();
1942
1943 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
1944 {
1945 Ret = TRUE;
1946 }
1947 else
1948 {
1949 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
1950 }
1951
1952 UserLeave();
1953
1954 _SEH2_TRY
1955 {
1956 ProbeForWrite(lpmsg, sizeof(MSG), 1);
1957 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
1958 }
1959 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1960 {
1961 Ret = FALSE;
1962 }
1963 _SEH2_END;
1964
1965 return Ret;
1966 }
1967
1968 LRESULT APIENTRY
1969 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
1970 {
1971 LRESULT Res = 0;
1972 MSG SafeMsg;
1973
1974 _SEH2_TRY
1975 {
1976 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
1977 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
1978 }
1979 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1980 {
1981 SetLastNtError(_SEH2_GetExceptionCode());
1982 _SEH2_YIELD(return FALSE);
1983 }
1984 _SEH2_END;
1985
1986 UserEnterExclusive();
1987
1988 Res = IntDispatchMessage(&SafeMsg);
1989
1990 UserLeave();
1991 return Res;
1992 }
1993
1994
1995 BOOL APIENTRY
1996 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
1997 {
1998 MSG SafeMsg;
1999 BOOL Ret;
2000
2001 _SEH2_TRY
2002 {
2003 ProbeForRead(lpMsg, sizeof(MSG), 1);
2004 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
2005 }
2006 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2007 {
2008 SetLastNtError(_SEH2_GetExceptionCode());
2009 _SEH2_YIELD(return FALSE);
2010 }
2011 _SEH2_END;
2012
2013 UserEnterExclusive();
2014
2015 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
2016
2017 UserLeave();
2018
2019 return Ret;
2020 }
2021
2022 BOOL APIENTRY
2023 NtUserMessageCall( HWND hWnd,
2024 UINT Msg,
2025 WPARAM wParam,
2026 LPARAM lParam,
2027 ULONG_PTR ResultInfo,
2028 DWORD dwType, // fnID?
2029 BOOL Ansi)
2030 {
2031 LRESULT lResult = 0;
2032 BOOL Ret = FALSE;
2033 PWND Window = NULL;
2034 USER_REFERENCE_ENTRY Ref;
2035
2036 UserEnterExclusive();
2037
2038 switch(dwType)
2039 {
2040 case FNID_DEFWINDOWPROC:
2041 /* Validate input */
2042 if (hWnd && (hWnd != INVALID_HANDLE_VALUE))
2043 {
2044 Window = UserGetWindowObject(hWnd);
2045 if (!Window)
2046 {
2047 UserLeave();
2048 return FALSE;
2049 }
2050 }
2051 UserRefObjectCo(Window, &Ref);
2052 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2053 Ret = TRUE;
2054 UserDerefObjectCo(Window);
2055 break;
2056 case FNID_SENDNOTIFYMESSAGE:
2057 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2058 break;
2059 case FNID_BROADCASTSYSTEMMESSAGE:
2060 {
2061 BROADCASTPARM parm;
2062 DWORD_PTR RetVal = 0;
2063
2064 if (ResultInfo)
2065 {
2066 _SEH2_TRY
2067 {
2068 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
2069 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2070 }
2071 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2072 {
2073 _SEH2_YIELD(break);
2074 }
2075 _SEH2_END;
2076 }
2077 else
2078 break;
2079
2080 if ( parm.recipients & BSM_ALLDESKTOPS ||
2081 parm.recipients == BSM_ALLCOMPONENTS )
2082 {
2083 }
2084 else if (parm.recipients & BSM_APPLICATIONS)
2085 {
2086 if (parm.flags & BSF_QUERY)
2087 {
2088 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2089 {
2090 co_IntSendMessageTimeout( HWND_BROADCAST,
2091 Msg,
2092 wParam,
2093 lParam,
2094 SMTO_ABORTIFHUNG,
2095 2000,
2096 &RetVal);
2097 }
2098 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2099 {
2100 co_IntSendMessageTimeout( HWND_BROADCAST,
2101 Msg,
2102 wParam,
2103 lParam,
2104 SMTO_NOTIMEOUTIFNOTHUNG,
2105 2000,
2106 &RetVal);
2107 }
2108 else
2109 {
2110 co_IntSendMessageTimeout( HWND_BROADCAST,
2111 Msg,
2112 wParam,
2113 lParam,
2114 SMTO_NORMAL,
2115 2000,
2116 &RetVal);
2117 }
2118 Ret = RetVal;
2119 }
2120 else if (parm.flags & BSF_POSTMESSAGE)
2121 {
2122 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2123 }
2124 else //Everything else,,,, if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2125 {
2126 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2127 }
2128 }
2129 }
2130 break;
2131 case FNID_SENDMESSAGECALLBACK:
2132 {
2133 CALL_BACK_INFO CallBackInfo;
2134 ULONG_PTR uResult;
2135
2136 _SEH2_TRY
2137 {
2138 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
2139 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
2140 }
2141 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2142 {
2143 _SEH2_YIELD(break);
2144 }
2145 _SEH2_END;
2146
2147 if (is_pointer_message(Msg))
2148 {
2149 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
2150 break;
2151 }
2152
2153 if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2154 CallBackInfo.CallBack, CallBackInfo.Context, &uResult)))
2155 {
2156 DPRINT1("Callback failure!\n");
2157 }
2158 }
2159 break;
2160 case FNID_SENDMESSAGE:
2161 {
2162 Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
2163
2164 if (ResultInfo)
2165 {
2166 _SEH2_TRY
2167 {
2168 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
2169 RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
2170 }
2171 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2172 {
2173 Ret = FALSE;
2174 _SEH2_YIELD(break);
2175 }
2176 _SEH2_END;
2177 }
2178 break;
2179 }
2180 case FNID_SENDMESSAGETIMEOUT:
2181 {
2182 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
2183 if (ResultInfo)
2184 {
2185 _SEH2_TRY
2186 {
2187 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
2188 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
2189 }
2190 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2191 {
2192 _SEH2_YIELD(break);
2193 }
2194 _SEH2_END;
2195 }
2196
2197 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
2198
2199 if (pdsm)
2200 {
2201 _SEH2_TRY
2202 {
2203 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
2204 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2205 }
2206 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2207 {
2208 Ret = FALSE;
2209 _SEH2_YIELD(break);
2210 }
2211 _SEH2_END;
2212 }
2213 break;
2214 }
2215 // CallNextHook bypass.
2216 case FNID_CALLWNDPROC:
2217 case FNID_CALLWNDPROCRET:
2218 {
2219 PTHREADINFO pti;
2220 PCLIENTINFO ClientInfo;
2221 PHOOK NextObj, Hook;
2222
2223 pti = GetW32ThreadInfo();
2224
2225 Hook = pti->sphkCurrent;
2226
2227 if (!Hook) break;
2228
2229 NextObj = Hook->phkNext;
2230 ClientInfo = pti->pClientInfo;
2231 _SEH2_TRY
2232 {
2233 ClientInfo->phkCurrent = NextObj;
2234 }
2235 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2236 {
2237 ClientInfo = NULL;
2238 }
2239 _SEH2_END;
2240
2241 if (!ClientInfo || !NextObj) break;
2242
2243 NextObj->phkNext = IntGetNextHook(NextObj);
2244
2245 if ( Hook->HookId == WH_CALLWNDPROC)
2246 {
2247 CWPSTRUCT CWP;
2248 CWP.hwnd = hWnd;
2249 CWP.message = Msg;
2250 CWP.wParam = wParam;
2251 CWP.lParam = lParam;
2252 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2253
2254 lResult = co_IntCallHookProc( Hook->HookId,
2255 HC_ACTION,
2256 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2257 (LPARAM)&CWP,
2258 Hook->Proc,
2259 Hook->Ansi,
2260 &Hook->ModuleName);
2261 }
2262 else
2263 {
2264 CWPRETSTRUCT CWPR;
2265 CWPR.hwnd = hWnd;
2266 CWPR.message = Msg;
2267 CWPR.wParam = wParam;
2268 CWPR.lParam = lParam;
2269 CWPR.lResult = ClientInfo->dwHookData;
2270
2271 lResult = co_IntCallHookProc( Hook->HookId,
2272 HC_ACTION,
2273 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2274 (LPARAM)&CWPR,
2275 Hook->Proc,
2276 Hook->Ansi,
2277 &Hook->ModuleName);
2278 }
2279 }
2280 break;
2281 }
2282
2283 switch(dwType)
2284 {
2285 case FNID_DEFWINDOWPROC:
2286 case FNID_CALLWNDPROC:
2287 case FNID_CALLWNDPROCRET:
2288 if (ResultInfo)
2289 {
2290 _SEH2_TRY
2291 {
2292 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2293 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2294 }
2295 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2296 {
2297 Ret = FALSE;
2298 }
2299 _SEH2_END;
2300 }
2301 break;
2302 default:
2303 break;
2304 }
2305
2306 UserLeave();
2307
2308 return Ret;
2309 }
2310
2311 #define INFINITE 0xFFFFFFFF
2312 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2313
2314 DWORD
2315 APIENTRY
2316 NtUserWaitForInputIdle( IN HANDLE hProcess,
2317 IN DWORD dwMilliseconds,
2318 IN BOOL Unknown2)
2319 {
2320 PEPROCESS Process;
2321 PPROCESSINFO W32Process;
2322 PTHREADINFO pti;
2323 NTSTATUS Status;
2324 HANDLE Handles[3];
2325 LARGE_INTEGER Timeout;
2326
2327 UserEnterExclusive();
2328
2329 Status = ObReferenceObjectByHandle(hProcess,
2330 PROCESS_QUERY_INFORMATION,
2331 PsProcessType,
2332 UserMode,
2333 (PVOID*)&Process,
2334 NULL);
2335
2336 if (!NT_SUCCESS(Status))
2337 {
2338 UserLeave();
2339 SetLastNtError(Status);
2340 return WAIT_FAILED;
2341 }
2342
2343 pti = PsGetCurrentThreadWin32Thread();
2344
2345 W32Process = (PPROCESSINFO)Process->Win32Process;
2346
2347 if ( PsGetProcessExitProcessCalled(Process) ||
2348 !W32Process ||
2349 pti->ppi == W32Process)
2350 {
2351 ObDereferenceObject(Process);
2352 UserLeave();
2353 EngSetLastError(ERROR_INVALID_PARAMETER);
2354 return WAIT_FAILED;
2355 }
2356
2357 Handles[0] = Process;
2358 Handles[1] = W32Process->InputIdleEvent;
2359 Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2360
2361 if (!Handles[1])
2362 {
2363 ObDereferenceObject(Process);
2364 UserLeave();
2365 return STATUS_SUCCESS; /* no event to wait on */
2366 }
2367
2368 if (dwMilliseconds != INFINITE)
2369 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2370
2371 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2372 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2373 {
2374 pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2375 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2376 }
2377
2378 DPRINT("WFII: ppi 0x%x\n",W32Process);
2379 DPRINT("WFII: waiting for %p\n", Handles[1] );
2380 do
2381 {
2382 UserLeave();
2383 Status = KeWaitForMultipleObjects( 3,
2384 Handles,
2385 WaitAny,
2386 UserRequest,
2387 UserMode,
2388 FALSE,
2389 dwMilliseconds == INFINITE ? NULL : &Timeout,
2390 NULL);
2391 UserEnterExclusive();
2392
2393 if (!NT_SUCCESS(Status))
2394 {
2395 SetLastNtError(Status);
2396 Status = WAIT_FAILED;
2397 goto WaitExit;
2398 }
2399
2400 switch (Status)
2401 {
2402 case STATUS_WAIT_0:
2403 goto WaitExit;
2404
2405 case STATUS_WAIT_2:
2406 {
2407 MSG Msg;
2408 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
2409 DPRINT1("WFII: WAIT 2\n");
2410 }
2411 break;
2412
2413 case STATUS_TIMEOUT:
2414 DPRINT1("WFII: timeout\n");
2415 case WAIT_FAILED:
2416 goto WaitExit;
2417
2418 default:
2419 DPRINT1("WFII: finished\n");
2420 Status = STATUS_SUCCESS;
2421 goto WaitExit;
2422 }
2423 }
2424 while (TRUE);
2425
2426 WaitExit:
2427 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2428 {
2429 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
2430 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2431 }
2432 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
2433 ObDereferenceObject(Process);
2434 UserLeave();
2435 return Status;
2436 }
2437
2438 /* EOF */