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