- Revert 51255 that was committed on accident. The patch is not ready yet.
[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 == TRUE)
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 if ((INT)Ret != -1)
1880 Ret = Ret ? (WM_QUIT != pMsg->message) : FALSE;
1881
1882 return Ret;
1883 }
1884
1885 BOOL APIENTRY
1886 NtUserPeekMessage( PMSG pMsg,
1887 HWND hWnd,
1888 UINT MsgFilterMin,
1889 UINT MsgFilterMax,
1890 UINT RemoveMsg)
1891 {
1892 MSG Msg;
1893 BOOL Ret;
1894
1895 if ( RemoveMsg & PM_BADMSGFLAGS )
1896 {
1897 EngSetLastError(ERROR_INVALID_FLAGS);
1898 return FALSE;
1899 }
1900
1901 UserEnterExclusive();
1902
1903 RtlZeroMemory(&Msg, sizeof(MSG));
1904
1905 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
1906
1907 UserLeave();
1908
1909 if (Ret)
1910 {
1911 _SEH2_TRY
1912 {
1913 ProbeForWrite(pMsg, sizeof(MSG), 1);
1914 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1915 }
1916 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1917 {
1918 SetLastNtError(_SEH2_GetExceptionCode());
1919 Ret = FALSE;
1920 }
1921 _SEH2_END;
1922 }
1923
1924 return Ret;
1925 }
1926
1927 BOOL APIENTRY
1928 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
1929 {
1930 BOOL Ret = FALSE;
1931 MSG Msg;
1932
1933 _SEH2_TRY
1934 {
1935 ProbeForRead(lpmsg, sizeof(MSG), 1);
1936 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
1937 }
1938 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1939 {
1940 _SEH2_YIELD(return FALSE);
1941 }
1942 _SEH2_END;
1943
1944 UserEnterExclusive();
1945
1946 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
1947 {
1948 Ret = TRUE;
1949 }
1950 else
1951 {
1952 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
1953 }
1954
1955 UserLeave();
1956
1957 _SEH2_TRY
1958 {
1959 ProbeForWrite(lpmsg, sizeof(MSG), 1);
1960 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
1961 }
1962 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1963 {
1964 Ret = FALSE;
1965 }
1966 _SEH2_END;
1967
1968 return Ret;
1969 }
1970
1971 LRESULT APIENTRY
1972 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
1973 {
1974 LRESULT Res = 0;
1975 MSG SafeMsg;
1976
1977 _SEH2_TRY
1978 {
1979 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
1980 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
1981 }
1982 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1983 {
1984 SetLastNtError(_SEH2_GetExceptionCode());
1985 _SEH2_YIELD(return FALSE);
1986 }
1987 _SEH2_END;
1988
1989 UserEnterExclusive();
1990
1991 Res = IntDispatchMessage(&SafeMsg);
1992
1993 UserLeave();
1994 return Res;
1995 }
1996
1997
1998 BOOL APIENTRY
1999 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
2000 {
2001 MSG SafeMsg;
2002 BOOL Ret;
2003
2004 _SEH2_TRY
2005 {
2006 ProbeForRead(lpMsg, sizeof(MSG), 1);
2007 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
2008 }
2009 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2010 {
2011 SetLastNtError(_SEH2_GetExceptionCode());
2012 _SEH2_YIELD(return FALSE);
2013 }
2014 _SEH2_END;
2015
2016 UserEnterExclusive();
2017
2018 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
2019
2020 UserLeave();
2021
2022 return Ret;
2023 }
2024
2025 BOOL APIENTRY
2026 NtUserMessageCall( HWND hWnd,
2027 UINT Msg,
2028 WPARAM wParam,
2029 LPARAM lParam,
2030 ULONG_PTR ResultInfo,
2031 DWORD dwType, // fnID?
2032 BOOL Ansi)
2033 {
2034 LRESULT lResult = 0;
2035 BOOL Ret = FALSE;
2036 PWND Window = NULL;
2037 USER_REFERENCE_ENTRY Ref;
2038
2039 UserEnterExclusive();
2040
2041 switch(dwType)
2042 {
2043 case FNID_DEFWINDOWPROC:
2044 /* Validate input */
2045 if (hWnd && (hWnd != INVALID_HANDLE_VALUE))
2046 {
2047 Window = UserGetWindowObject(hWnd);
2048 if (!Window)
2049 {
2050 UserLeave();
2051 return FALSE;
2052 }
2053 }
2054 UserRefObjectCo(Window, &Ref);
2055 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2056 Ret = TRUE;
2057 UserDerefObjectCo(Window);
2058 break;
2059 case FNID_SENDNOTIFYMESSAGE:
2060 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2061 break;
2062 case FNID_BROADCASTSYSTEMMESSAGE:
2063 {
2064 BROADCASTPARM parm;
2065 DWORD_PTR RetVal = 0;
2066
2067 if (ResultInfo)
2068 {
2069 _SEH2_TRY
2070 {
2071 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
2072 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2073 }
2074 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2075 {
2076 _SEH2_YIELD(break);
2077 }
2078 _SEH2_END;
2079 }
2080 else
2081 break;
2082
2083 if ( parm.recipients & BSM_ALLDESKTOPS ||
2084 parm.recipients == BSM_ALLCOMPONENTS )
2085 {
2086 }
2087 else if (parm.recipients & BSM_APPLICATIONS)
2088 {
2089 if (parm.flags & BSF_QUERY)
2090 {
2091 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2092 {
2093 co_IntSendMessageTimeout( HWND_BROADCAST,
2094 Msg,
2095 wParam,
2096 lParam,
2097 SMTO_ABORTIFHUNG,
2098 2000,
2099 &RetVal);
2100 }
2101 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2102 {
2103 co_IntSendMessageTimeout( HWND_BROADCAST,
2104 Msg,
2105 wParam,
2106 lParam,
2107 SMTO_NOTIMEOUTIFNOTHUNG,
2108 2000,
2109 &RetVal);
2110 }
2111 else
2112 {
2113 co_IntSendMessageTimeout( HWND_BROADCAST,
2114 Msg,
2115 wParam,
2116 lParam,
2117 SMTO_NORMAL,
2118 2000,
2119 &RetVal);
2120 }
2121 Ret = RetVal;
2122 }
2123 else if (parm.flags & BSF_POSTMESSAGE)
2124 {
2125 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2126 }
2127 else //Everything else,,,, if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2128 {
2129 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2130 }
2131 }
2132 }
2133 break;
2134 case FNID_SENDMESSAGECALLBACK:
2135 {
2136 CALL_BACK_INFO CallBackInfo;
2137 ULONG_PTR uResult;
2138
2139 _SEH2_TRY
2140 {
2141 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
2142 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
2143 }
2144 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2145 {
2146 _SEH2_YIELD(break);
2147 }
2148 _SEH2_END;
2149
2150 if (is_pointer_message(Msg))
2151 {
2152 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
2153 break;
2154 }
2155
2156 if (!(Ret = co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2157 CallBackInfo.CallBack, CallBackInfo.Context, &uResult)))
2158 {
2159 DPRINT1("Callback failure!\n");
2160 }
2161 }
2162 break;
2163 case FNID_SENDMESSAGE:
2164 {
2165 Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
2166
2167 if (ResultInfo)
2168 {
2169 _SEH2_TRY
2170 {
2171 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
2172 RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
2173 }
2174 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2175 {
2176 Ret = FALSE;
2177 _SEH2_YIELD(break);
2178 }
2179 _SEH2_END;
2180 }
2181 break;
2182 }
2183 case FNID_SENDMESSAGETIMEOUT:
2184 {
2185 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
2186 if (ResultInfo)
2187 {
2188 _SEH2_TRY
2189 {
2190 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
2191 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
2192 }
2193 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2194 {
2195 _SEH2_YIELD(break);
2196 }
2197 _SEH2_END;
2198 }
2199
2200 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
2201
2202 if (pdsm)
2203 {
2204 _SEH2_TRY
2205 {
2206 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
2207 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2208 }
2209 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2210 {
2211 Ret = FALSE;
2212 _SEH2_YIELD(break);
2213 }
2214 _SEH2_END;
2215 }
2216 break;
2217 }
2218 // CallNextHook bypass.
2219 case FNID_CALLWNDPROC:
2220 case FNID_CALLWNDPROCRET:
2221 {
2222 PTHREADINFO pti;
2223 PCLIENTINFO ClientInfo;
2224 PHOOK NextObj, Hook;
2225
2226 pti = GetW32ThreadInfo();
2227
2228 Hook = pti->sphkCurrent;
2229
2230 if (!Hook) break;
2231
2232 NextObj = Hook->phkNext;
2233 ClientInfo = pti->pClientInfo;
2234 _SEH2_TRY
2235 {
2236 ClientInfo->phkCurrent = NextObj;
2237 }
2238 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2239 {
2240 ClientInfo = NULL;
2241 }
2242 _SEH2_END;
2243
2244 if (!ClientInfo || !NextObj) break;
2245
2246 NextObj->phkNext = IntGetNextHook(NextObj);
2247
2248 if ( Hook->HookId == WH_CALLWNDPROC)
2249 {
2250 CWPSTRUCT CWP;
2251 CWP.hwnd = hWnd;
2252 CWP.message = Msg;
2253 CWP.wParam = wParam;
2254 CWP.lParam = lParam;
2255 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2256
2257 lResult = co_IntCallHookProc( Hook->HookId,
2258 HC_ACTION,
2259 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2260 (LPARAM)&CWP,
2261 Hook->Proc,
2262 Hook->Ansi,
2263 &Hook->ModuleName);
2264 }
2265 else
2266 {
2267 CWPRETSTRUCT CWPR;
2268 CWPR.hwnd = hWnd;
2269 CWPR.message = Msg;
2270 CWPR.wParam = wParam;
2271 CWPR.lParam = lParam;
2272 CWPR.lResult = ClientInfo->dwHookData;
2273
2274 lResult = co_IntCallHookProc( Hook->HookId,
2275 HC_ACTION,
2276 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2277 (LPARAM)&CWPR,
2278 Hook->Proc,
2279 Hook->Ansi,
2280 &Hook->ModuleName);
2281 }
2282 }
2283 break;
2284 }
2285
2286 switch(dwType)
2287 {
2288 case FNID_DEFWINDOWPROC:
2289 case FNID_CALLWNDPROC:
2290 case FNID_CALLWNDPROCRET:
2291 if (ResultInfo)
2292 {
2293 _SEH2_TRY
2294 {
2295 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2296 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2297 }
2298 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2299 {
2300 Ret = FALSE;
2301 }
2302 _SEH2_END;
2303 }
2304 break;
2305 default:
2306 break;
2307 }
2308
2309 UserLeave();
2310
2311 return Ret;
2312 }
2313
2314 #define INFINITE 0xFFFFFFFF
2315 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2316
2317 DWORD
2318 APIENTRY
2319 NtUserWaitForInputIdle( IN HANDLE hProcess,
2320 IN DWORD dwMilliseconds,
2321 IN BOOL Unknown2)
2322 {
2323 PEPROCESS Process;
2324 PPROCESSINFO W32Process;
2325 PTHREADINFO pti;
2326 NTSTATUS Status;
2327 HANDLE Handles[3];
2328 LARGE_INTEGER Timeout;
2329
2330 UserEnterExclusive();
2331
2332 Status = ObReferenceObjectByHandle(hProcess,
2333 PROCESS_QUERY_INFORMATION,
2334 PsProcessType,
2335 UserMode,
2336 (PVOID*)&Process,
2337 NULL);
2338
2339 if (!NT_SUCCESS(Status))
2340 {
2341 UserLeave();
2342 SetLastNtError(Status);
2343 return WAIT_FAILED;
2344 }
2345
2346 pti = PsGetCurrentThreadWin32Thread();
2347
2348 W32Process = (PPROCESSINFO)Process->Win32Process;
2349
2350 if ( PsGetProcessExitProcessCalled(Process) ||
2351 !W32Process ||
2352 pti->ppi == W32Process)
2353 {
2354 ObDereferenceObject(Process);
2355 UserLeave();
2356 EngSetLastError(ERROR_INVALID_PARAMETER);
2357 return WAIT_FAILED;
2358 }
2359
2360 Handles[0] = Process;
2361 Handles[1] = W32Process->InputIdleEvent;
2362 Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2363
2364 if (!Handles[1])
2365 {
2366 ObDereferenceObject(Process);
2367 UserLeave();
2368 return STATUS_SUCCESS; /* no event to wait on */
2369 }
2370
2371 if (dwMilliseconds != INFINITE)
2372 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2373
2374 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2375 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2376 {
2377 pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2378 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2379 }
2380
2381 DPRINT("WFII: ppi 0x%x\n",W32Process);
2382 DPRINT("WFII: waiting for %p\n", Handles[1] );
2383 do
2384 {
2385 UserLeave();
2386 Status = KeWaitForMultipleObjects( 3,
2387 Handles,
2388 WaitAny,
2389 UserRequest,
2390 UserMode,
2391 FALSE,
2392 dwMilliseconds == INFINITE ? NULL : &Timeout,
2393 NULL);
2394 UserEnterExclusive();
2395
2396 if (!NT_SUCCESS(Status))
2397 {
2398 SetLastNtError(Status);
2399 Status = WAIT_FAILED;
2400 goto WaitExit;
2401 }
2402
2403 switch (Status)
2404 {
2405 case STATUS_WAIT_0:
2406 goto WaitExit;
2407
2408 case STATUS_WAIT_2:
2409 {
2410 MSG Msg;
2411 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
2412 DPRINT1("WFII: WAIT 2\n");
2413 }
2414 break;
2415
2416 case STATUS_TIMEOUT:
2417 DPRINT1("WFII: timeout\n");
2418 case WAIT_FAILED:
2419 goto WaitExit;
2420
2421 default:
2422 DPRINT1("WFII: finished\n");
2423 Status = STATUS_SUCCESS;
2424 goto WaitExit;
2425 }
2426 }
2427 while (TRUE);
2428
2429 WaitExit:
2430 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2431 {
2432 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
2433 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2434 }
2435 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
2436 ObDereferenceObject(Process);
2437 UserLeave();
2438 return Status;
2439 }
2440
2441 /* EOF */