[win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / message.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Messages
5 * FILE: subsystems/win32/win32k/ntuser/message.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <win32k.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 BOOLEAN NTAPI PsGetProcessExitProcessCalled(PEPROCESS Process);
19
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, USERTAG_WINDOWLIST);
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 /* This function posts a message if the destination's message queue belongs to
1553 another thread, otherwise it sends the message. It does not support broadcast
1554 messages! */
1555 LRESULT FASTCALL
1556 co_IntPostOrSendMessage( HWND hWnd,
1557 UINT Msg,
1558 WPARAM wParam,
1559 LPARAM lParam )
1560 {
1561 ULONG_PTR Result;
1562 PTHREADINFO pti;
1563 PWND Window;
1564
1565 if ( hWnd == HWND_BROADCAST )
1566 {
1567 return 0;
1568 }
1569
1570 if(!(Window = UserGetWindowObject(hWnd)))
1571 {
1572 return 0;
1573 }
1574
1575 pti = PsGetCurrentThreadWin32Thread();
1576
1577 if ( Window->head.pti->MessageQueue != pti->MessageQueue &&
1578 FindMsgMemory(Msg) == 0 )
1579 {
1580 Result = UserPostMessage(hWnd, Msg, wParam, lParam);
1581 }
1582 else
1583 {
1584 if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
1585 {
1586 Result = 0;
1587 }
1588 }
1589
1590 return (LRESULT)Result;
1591 }
1592
1593 LRESULT FASTCALL
1594 co_IntDoSendMessage( HWND hWnd,
1595 UINT Msg,
1596 WPARAM wParam,
1597 LPARAM lParam,
1598 PDOSENDMESSAGE dsm)
1599 {
1600 PTHREADINFO pti;
1601 LRESULT Result = TRUE;
1602 NTSTATUS Status;
1603 PWND Window = NULL;
1604 MSG UserModeMsg;
1605 MSG KernelModeMsg;
1606 PMSGMEMORY MsgMemoryEntry;
1607
1608 if (HWND_BROADCAST != hWnd)
1609 {
1610 Window = UserGetWindowObject(hWnd);
1611 if ( !Window )
1612 {
1613 return 0;
1614 }
1615 }
1616
1617 /* Check for an exiting window. */
1618 if (Window && Window->state & WNDS_DESTROYED)
1619 {
1620 DPRINT1("co_IntDoSendMessage Window Exiting!\n");
1621 }
1622
1623 /* See if the current thread can handle the message */
1624 pti = PsGetCurrentThreadWin32Thread();
1625
1626 UserModeMsg.hwnd = hWnd;
1627 UserModeMsg.message = Msg;
1628 UserModeMsg.wParam = wParam;
1629 UserModeMsg.lParam = lParam;
1630 MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
1631
1632 Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
1633 if (! NT_SUCCESS(Status))
1634 {
1635 EngSetLastError(ERROR_INVALID_PARAMETER);
1636 return (dsm ? 0 : -1);
1637 }
1638
1639 if (!dsm)
1640 {
1641 Result = co_IntSendMessage( KernelModeMsg.hwnd,
1642 KernelModeMsg.message,
1643 KernelModeMsg.wParam,
1644 KernelModeMsg.lParam );
1645 }
1646 else
1647 {
1648 Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
1649 KernelModeMsg.message,
1650 KernelModeMsg.wParam,
1651 KernelModeMsg.lParam,
1652 dsm->uFlags,
1653 dsm->uTimeout,
1654 &dsm->Result );
1655 }
1656
1657 Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
1658 if (! NT_SUCCESS(Status))
1659 {
1660 EngSetLastError(ERROR_INVALID_PARAMETER);
1661 return(dsm ? 0 : -1);
1662 }
1663
1664 return (LRESULT)Result;
1665 }
1666
1667 BOOL FASTCALL
1668 UserSendNotifyMessage( HWND hWnd,
1669 UINT Msg,
1670 WPARAM wParam,
1671 LPARAM lParam )
1672 {
1673 BOOL Ret = TRUE;
1674
1675 if (is_pointer_message(Msg))
1676 {
1677 EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
1678 return FALSE;
1679 }
1680
1681 // Basicly the same as IntPostOrSendMessage
1682 if (hWnd == HWND_BROADCAST) //Handle Broadcast
1683 {
1684 HWND *List;
1685 PWND DesktopWindow;
1686 ULONG i;
1687
1688 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1689 List = IntWinListChildren(DesktopWindow);
1690
1691 if (List != NULL)
1692 {
1693 UserSendNotifyMessage(DesktopWindow->head.h, Msg, wParam, lParam);
1694 for (i = 0; List[i]; i++)
1695 {
1696 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
1697 if (!Ret)
1698 {
1699 DPRINT1("SendNotifyMessage: Failed in Broadcast!\n");
1700 break;
1701 }
1702 }
1703 ExFreePool(List);
1704 }
1705 }
1706 else
1707 {
1708 ULONG_PTR lResult = 0;
1709 Ret = co_IntSendMessageWithCallBack( hWnd,
1710 Msg,
1711 wParam,
1712 lParam,
1713 NULL,
1714 0,
1715 &lResult);
1716 }
1717 return Ret;
1718 }
1719
1720
1721 DWORD APIENTRY
1722 IntGetQueueStatus(DWORD Changes)
1723 {
1724 PTHREADINFO pti;
1725 PUSER_MESSAGE_QUEUE Queue;
1726 DWORD Result;
1727
1728 pti = PsGetCurrentThreadWin32Thread();
1729 Queue = pti->MessageQueue;
1730 // wine:
1731 Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
1732
1733 /* High word, types of messages currently in the queue.
1734 Low word, types of messages that have been added to the queue and that
1735 are still in the queue
1736 */
1737 Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
1738
1739 pti->pcti->fsChangeBits &= ~Changes;
1740
1741 return Result;
1742 }
1743
1744 BOOL APIENTRY
1745 IntInitMessagePumpHook()
1746 {
1747 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1748
1749 if (pti->pcti)
1750 {
1751 pti->pcti->dwcPumpHook++;
1752 return TRUE;
1753 }
1754 return FALSE;
1755 }
1756
1757 BOOL APIENTRY
1758 IntUninitMessagePumpHook()
1759 {
1760 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1761
1762 if (pti->pcti)
1763 {
1764 if (pti->pcti->dwcPumpHook <= 0)
1765 {
1766 return FALSE;
1767 }
1768 pti->pcti->dwcPumpHook--;
1769 return TRUE;
1770 }
1771 return FALSE;
1772 }
1773
1774 /** Functions ******************************************************************/
1775
1776 BOOL APIENTRY
1777 NtUserPostMessage(HWND hWnd,
1778 UINT Msg,
1779 WPARAM wParam,
1780 LPARAM lParam)
1781 {
1782 BOOL ret;
1783
1784 UserEnterExclusive();
1785
1786 ret = UserPostMessage(hWnd, Msg, wParam, lParam);
1787
1788 UserLeave();
1789
1790 return ret;
1791 }
1792
1793 BOOL APIENTRY
1794 NtUserPostThreadMessage(DWORD idThread,
1795 UINT Msg,
1796 WPARAM wParam,
1797 LPARAM lParam)
1798 {
1799 BOOL ret;
1800
1801 UserEnterExclusive();
1802
1803 ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
1804
1805 UserLeave();
1806
1807 return ret;
1808 }
1809
1810 BOOL APIENTRY
1811 NtUserWaitMessage(VOID)
1812 {
1813 BOOL ret;
1814
1815 UserEnterExclusive();
1816 DPRINT("NtUserWaitMessage Enter\n");
1817 ret = co_IntWaitMessage(NULL, 0, 0);
1818 DPRINT("NtUserWaitMessage Leave\n");
1819 UserLeave();
1820
1821 return ret;
1822 }
1823
1824 BOOL APIENTRY
1825 NtUserGetMessage(PMSG pMsg,
1826 HWND hWnd,
1827 UINT MsgFilterMin,
1828 UINT MsgFilterMax )
1829 {
1830 MSG Msg;
1831 BOOL Ret;
1832
1833 if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
1834 {
1835 EngSetLastError(ERROR_INVALID_PARAMETER);
1836 return FALSE;
1837 }
1838
1839 UserEnterExclusive();
1840
1841 RtlZeroMemory(&Msg, sizeof(MSG));
1842
1843 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
1844
1845 UserLeave();
1846
1847 if (Ret)
1848 {
1849 _SEH2_TRY
1850 {
1851 ProbeForWrite(pMsg, sizeof(MSG), 1);
1852 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1853 }
1854 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1855 {
1856 SetLastNtError(_SEH2_GetExceptionCode());
1857 Ret = FALSE;
1858 }
1859 _SEH2_END;
1860 }
1861
1862 return Ret;
1863 }
1864
1865 BOOL APIENTRY
1866 NtUserPeekMessage( PMSG pMsg,
1867 HWND hWnd,
1868 UINT MsgFilterMin,
1869 UINT MsgFilterMax,
1870 UINT RemoveMsg)
1871 {
1872 MSG Msg;
1873 BOOL Ret;
1874
1875 if ( RemoveMsg & PM_BADMSGFLAGS )
1876 {
1877 EngSetLastError(ERROR_INVALID_FLAGS);
1878 return FALSE;
1879 }
1880
1881 UserEnterExclusive();
1882
1883 RtlZeroMemory(&Msg, sizeof(MSG));
1884
1885 Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
1886
1887 UserLeave();
1888
1889 if (Ret)
1890 {
1891 _SEH2_TRY
1892 {
1893 ProbeForWrite(pMsg, sizeof(MSG), 1);
1894 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
1895 }
1896 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1897 {
1898 SetLastNtError(_SEH2_GetExceptionCode());
1899 Ret = FALSE;
1900 }
1901 _SEH2_END;
1902 }
1903
1904 return Ret;
1905 }
1906
1907 BOOL APIENTRY
1908 NtUserCallMsgFilter( LPMSG lpmsg, INT code)
1909 {
1910 BOOL Ret = FALSE;
1911 MSG Msg;
1912
1913 _SEH2_TRY
1914 {
1915 ProbeForRead(lpmsg, sizeof(MSG), 1);
1916 RtlCopyMemory( &Msg, lpmsg, sizeof(MSG));
1917 }
1918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1919 {
1920 _SEH2_YIELD(return FALSE);
1921 }
1922 _SEH2_END;
1923
1924 UserEnterExclusive();
1925
1926 if ( co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
1927 {
1928 Ret = TRUE;
1929 }
1930 else
1931 {
1932 Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
1933 }
1934
1935 UserLeave();
1936
1937 _SEH2_TRY
1938 {
1939 ProbeForWrite(lpmsg, sizeof(MSG), 1);
1940 RtlCopyMemory(lpmsg, &Msg, sizeof(MSG));
1941 }
1942 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1943 {
1944 Ret = FALSE;
1945 }
1946 _SEH2_END;
1947
1948 return Ret;
1949 }
1950
1951 LRESULT APIENTRY
1952 NtUserDispatchMessage(PMSG UnsafeMsgInfo)
1953 {
1954 LRESULT Res = 0;
1955 MSG SafeMsg;
1956
1957 _SEH2_TRY
1958 {
1959 ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
1960 RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
1961 }
1962 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1963 {
1964 SetLastNtError(_SEH2_GetExceptionCode());
1965 _SEH2_YIELD(return FALSE);
1966 }
1967 _SEH2_END;
1968
1969 UserEnterExclusive();
1970
1971 Res = IntDispatchMessage(&SafeMsg);
1972
1973 UserLeave();
1974 return Res;
1975 }
1976
1977
1978 BOOL APIENTRY
1979 NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
1980 {
1981 MSG SafeMsg;
1982 BOOL Ret;
1983
1984 _SEH2_TRY
1985 {
1986 ProbeForRead(lpMsg, sizeof(MSG), 1);
1987 RtlCopyMemory(&SafeMsg, lpMsg, sizeof(MSG));
1988 }
1989 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1990 {
1991 SetLastNtError(_SEH2_GetExceptionCode());
1992 _SEH2_YIELD(return FALSE);
1993 }
1994 _SEH2_END;
1995
1996 UserEnterExclusive();
1997
1998 Ret = IntTranslateKbdMessage(&SafeMsg, flags);
1999
2000 UserLeave();
2001
2002 return Ret;
2003 }
2004
2005 BOOL APIENTRY
2006 NtUserMessageCall( HWND hWnd,
2007 UINT Msg,
2008 WPARAM wParam,
2009 LPARAM lParam,
2010 ULONG_PTR ResultInfo,
2011 DWORD dwType, // fnID?
2012 BOOL Ansi)
2013 {
2014 LRESULT lResult = 0;
2015 BOOL Ret = FALSE;
2016 PWND Window = NULL;
2017 USER_REFERENCE_ENTRY Ref;
2018
2019 UserEnterExclusive();
2020
2021 /* Validate input */
2022 if (hWnd && (hWnd != INVALID_HANDLE_VALUE))
2023 {
2024 Window = UserGetWindowObject(hWnd);
2025 if (!Window)
2026 {
2027 UserLeave();
2028 return FALSE;
2029 }
2030 }
2031
2032 switch(dwType)
2033 {
2034 case FNID_DEFWINDOWPROC:
2035 if (Window) UserRefObjectCo(Window, &Ref);
2036 lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
2037 Ret = TRUE;
2038 if (Window) UserDerefObjectCo(Window);
2039 break;
2040 case FNID_SENDNOTIFYMESSAGE:
2041 Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
2042 break;
2043 case FNID_BROADCASTSYSTEMMESSAGE:
2044 {
2045 BROADCASTPARM parm;
2046 DWORD_PTR RetVal = 0;
2047
2048 if (ResultInfo)
2049 {
2050 _SEH2_TRY
2051 {
2052 ProbeForWrite((PVOID)ResultInfo, sizeof(BROADCASTPARM), 1);
2053 RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
2054 }
2055 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2056 {
2057 Ret = FALSE;
2058 _SEH2_YIELD(break);
2059 }
2060 _SEH2_END;
2061 }
2062 else
2063 break;
2064
2065 if ( parm.recipients & BSM_ALLDESKTOPS ||
2066 parm.recipients == BSM_ALLCOMPONENTS )
2067 {
2068 }
2069 else if (parm.recipients & BSM_APPLICATIONS)
2070 {
2071 if (parm.flags & BSF_QUERY)
2072 {
2073 if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
2074 {
2075 co_IntSendMessageTimeout( HWND_BROADCAST,
2076 Msg,
2077 wParam,
2078 lParam,
2079 SMTO_ABORTIFHUNG,
2080 2000,
2081 &RetVal);
2082 }
2083 else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
2084 {
2085 co_IntSendMessageTimeout( HWND_BROADCAST,
2086 Msg,
2087 wParam,
2088 lParam,
2089 SMTO_NOTIMEOUTIFNOTHUNG,
2090 2000,
2091 &RetVal);
2092 }
2093 else
2094 {
2095 co_IntSendMessageTimeout( HWND_BROADCAST,
2096 Msg,
2097 wParam,
2098 lParam,
2099 SMTO_NORMAL,
2100 2000,
2101 &RetVal);
2102 }
2103 Ret = RetVal;
2104 }
2105 else if (parm.flags & BSF_POSTMESSAGE)
2106 {
2107 Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
2108 }
2109 else //Everything else,,,, if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
2110 {
2111 Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
2112 }
2113 }
2114 }
2115 break;
2116 case FNID_SENDMESSAGECALLBACK:
2117 {
2118 CALL_BACK_INFO CallBackInfo;
2119 ULONG_PTR uResult;
2120
2121 _SEH2_TRY
2122 {
2123 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
2124 RtlCopyMemory(&CallBackInfo, (PVOID)ResultInfo, sizeof(CALL_BACK_INFO));
2125 }
2126 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2127 {
2128 Ret = FALSE;
2129 _SEH2_YIELD(break);
2130 }
2131 _SEH2_END;
2132
2133 if (!co_IntSendMessageWithCallBack(hWnd, Msg, wParam, lParam,
2134 CallBackInfo.CallBack, CallBackInfo.Context, &uResult))
2135 {
2136 DPRINT1("Callback failure!\n");
2137 }
2138 }
2139 break;
2140 case FNID_SENDMESSAGE:
2141 {
2142 Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
2143
2144 if (ResultInfo)
2145 {
2146 _SEH2_TRY
2147 {
2148 ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
2149 RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
2150 }
2151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2152 {
2153 Ret = FALSE;
2154 _SEH2_YIELD(break);
2155 }
2156 _SEH2_END;
2157 }
2158 break;
2159 }
2160 case FNID_SENDMESSAGETIMEOUT:
2161 {
2162 DOSENDMESSAGE dsm, *pdsm = (PDOSENDMESSAGE)ResultInfo;
2163 if (ResultInfo)
2164 {
2165 _SEH2_TRY
2166 {
2167 ProbeForRead(pdsm, sizeof(DOSENDMESSAGE), 1);
2168 RtlCopyMemory(&dsm, pdsm, sizeof(DOSENDMESSAGE));
2169 }
2170 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2171 {
2172 Ret = FALSE;
2173 _SEH2_YIELD(break);
2174 }
2175 _SEH2_END;
2176 }
2177
2178 Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
2179
2180 if (pdsm)
2181 {
2182 _SEH2_TRY
2183 {
2184 ProbeForWrite(pdsm, sizeof(DOSENDMESSAGE), 1);
2185 RtlCopyMemory(pdsm, &dsm, sizeof(DOSENDMESSAGE));
2186 }
2187 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2188 {
2189 Ret = FALSE;
2190 _SEH2_YIELD(break);
2191 }
2192 _SEH2_END;
2193 }
2194 break;
2195 }
2196 // CallNextHook bypass.
2197 case FNID_CALLWNDPROC:
2198 case FNID_CALLWNDPROCRET:
2199 {
2200 PTHREADINFO pti;
2201 PCLIENTINFO ClientInfo;
2202 PHOOK NextObj, Hook;
2203
2204 pti = GetW32ThreadInfo();
2205
2206 Hook = pti->sphkCurrent;
2207
2208 if (!Hook) break;
2209
2210 NextObj = Hook->phkNext;
2211 ClientInfo = pti->pClientInfo;
2212 _SEH2_TRY
2213 {
2214 ClientInfo->phkCurrent = NextObj;
2215 }
2216 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2217 {
2218 ClientInfo = NULL;
2219 }
2220 _SEH2_END;
2221
2222 if (!ClientInfo || !NextObj) break;
2223
2224 NextObj->phkNext = IntGetNextHook(NextObj);
2225
2226 if ( Hook->HookId == WH_CALLWNDPROC)
2227 {
2228 CWPSTRUCT CWP;
2229 CWP.hwnd = hWnd;
2230 CWP.message = Msg;
2231 CWP.wParam = wParam;
2232 CWP.lParam = lParam;
2233 DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
2234
2235 lResult = co_IntCallHookProc( Hook->HookId,
2236 HC_ACTION,
2237 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2238 (LPARAM)&CWP,
2239 Hook->Proc,
2240 Hook->Ansi,
2241 &Hook->ModuleName);
2242 }
2243 else
2244 {
2245 CWPRETSTRUCT CWPR;
2246 CWPR.hwnd = hWnd;
2247 CWPR.message = Msg;
2248 CWPR.wParam = wParam;
2249 CWPR.lParam = lParam;
2250 CWPR.lResult = ClientInfo->dwHookData;
2251
2252 lResult = co_IntCallHookProc( Hook->HookId,
2253 HC_ACTION,
2254 ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
2255 (LPARAM)&CWPR,
2256 Hook->Proc,
2257 Hook->Ansi,
2258 &Hook->ModuleName);
2259 }
2260 }
2261 break;
2262 }
2263
2264 switch(dwType)
2265 {
2266 case FNID_DEFWINDOWPROC:
2267 case FNID_CALLWNDPROC:
2268 case FNID_CALLWNDPROCRET:
2269 if (ResultInfo)
2270 {
2271 _SEH2_TRY
2272 {
2273 ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
2274 RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
2275 }
2276 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2277 {
2278 Ret = FALSE;
2279 }
2280 _SEH2_END;
2281 }
2282 break;
2283 default:
2284 break;
2285 }
2286
2287 UserLeave();
2288
2289 return Ret;
2290 }
2291
2292 #define INFINITE 0xFFFFFFFF
2293 #define WAIT_FAILED ((DWORD)0xFFFFFFFF)
2294
2295 DWORD
2296 APIENTRY
2297 NtUserWaitForInputIdle( IN HANDLE hProcess,
2298 IN DWORD dwMilliseconds,
2299 IN BOOL Unknown2)
2300 {
2301 PEPROCESS Process;
2302 PPROCESSINFO W32Process;
2303 PTHREADINFO pti;
2304 NTSTATUS Status;
2305 HANDLE Handles[3];
2306 LARGE_INTEGER Timeout;
2307
2308 UserEnterExclusive();
2309
2310 Status = ObReferenceObjectByHandle(hProcess,
2311 PROCESS_QUERY_INFORMATION,
2312 PsProcessType,
2313 UserMode,
2314 (PVOID*)&Process,
2315 NULL);
2316
2317 if (!NT_SUCCESS(Status))
2318 {
2319 UserLeave();
2320 SetLastNtError(Status);
2321 return WAIT_FAILED;
2322 }
2323
2324 pti = PsGetCurrentThreadWin32Thread();
2325
2326 W32Process = (PPROCESSINFO)Process->Win32Process;
2327
2328 if ( PsGetProcessExitProcessCalled(Process) ||
2329 !W32Process ||
2330 pti->ppi == W32Process)
2331 {
2332 ObDereferenceObject(Process);
2333 UserLeave();
2334 EngSetLastError(ERROR_INVALID_PARAMETER);
2335 return WAIT_FAILED;
2336 }
2337
2338 Handles[0] = Process;
2339 Handles[1] = W32Process->InputIdleEvent;
2340 Handles[2] = pti->MessageQueue->NewMessages; // pEventQueueServer; IntMsqSetWakeMask returns hEventQueueClient
2341
2342 if (!Handles[1])
2343 {
2344 ObDereferenceObject(Process);
2345 UserLeave();
2346 return STATUS_SUCCESS; /* no event to wait on */
2347 }
2348
2349 if (dwMilliseconds != INFINITE)
2350 Timeout.QuadPart = (LONGLONG) dwMilliseconds * (LONGLONG) -10000;
2351
2352 W32Process->W32PF_flags |= W32PF_WAITFORINPUTIDLE;
2353 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2354 {
2355 pti->TIF_flags |= TIF_WAITFORINPUTIDLE;
2356 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2357 }
2358
2359 DPRINT("WFII: ppi 0x%x\n",W32Process);
2360 DPRINT("WFII: waiting for %p\n", Handles[1] );
2361 do
2362 {
2363 UserLeave();
2364 Status = KeWaitForMultipleObjects( 3,
2365 Handles,
2366 WaitAny,
2367 UserRequest,
2368 UserMode,
2369 FALSE,
2370 dwMilliseconds == INFINITE ? NULL : &Timeout,
2371 NULL);
2372 UserEnterExclusive();
2373
2374 if (!NT_SUCCESS(Status))
2375 {
2376 SetLastNtError(Status);
2377 Status = WAIT_FAILED;
2378 goto WaitExit;
2379 }
2380
2381 switch (Status)
2382 {
2383 case STATUS_WAIT_0:
2384 goto WaitExit;
2385
2386 case STATUS_WAIT_2:
2387 {
2388 MSG Msg;
2389 co_IntGetPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, FALSE);
2390 DPRINT1("WFII: WAIT 2\n");
2391 }
2392 break;
2393
2394 case STATUS_TIMEOUT:
2395 DPRINT1("WFII: timeout\n");
2396 case WAIT_FAILED:
2397 goto WaitExit;
2398
2399 default:
2400 DPRINT1("WFII: finished\n");
2401 Status = STATUS_SUCCESS;
2402 goto WaitExit;
2403 }
2404 }
2405 while (TRUE);
2406
2407 WaitExit:
2408 for (pti = W32Process->ptiList; pti; pti = pti->ptiSibling)
2409 {
2410 pti->TIF_flags &= ~TIF_WAITFORINPUTIDLE;
2411 pti->pClientInfo->dwTIFlags = pti->TIF_flags;
2412 }
2413 W32Process->W32PF_flags &= ~W32PF_WAITFORINPUTIDLE;
2414 ObDereferenceObject(Process);
2415 UserLeave();
2416 return Status;
2417 }
2418
2419 /* EOF */