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