6c849042b7a03a9e566dd0f7169975376d80297a
[reactos.git] / reactos / dll / win32 / user32 / windows / message.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: lib/user32/windows/message.c
5 * PURPOSE: Messages
6 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * UPDATE HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 #include <user32.h>
12
13 #include <wine/debug.h>
14 WINE_DEFAULT_DEBUG_CHANNEL(user32);
15
16 /* DDE message exchange
17 *
18 * - Session initialization
19 * Client sends a WM_DDE_INITIATE message, usually a broadcast message. lParam of
20 * this message contains a pair of global atoms, the Application and Topic atoms.
21 * The client must destroy the atoms.
22 * Server window proc handles the WM_DDE_INITIATE message and if the Application
23 * and Topic atoms are recognized sends a WM_DDE_ACK message to the client. lParam
24 * of the reply message contains another pair of global atoms (Application and
25 * Topic again), which must be destroyed by the server.
26 *
27 * - Execute
28 * Client posts a WM_DDE_EXECUTE message to the server window. lParam of that message
29 * is a global memory handle containing the string to execute. After the command has
30 * been executed the server posts a WM_DDE_ACK message to the client, which contains
31 * a packed lParam which in turn contains that global memory handle. The client takes
32 * ownership of both the packed lParam (meaning it needs to call FreeDDElParam() on
33 * it and the global memory handle.
34 * This might work nice and easy in Win3.1, but things are more complicated for NT.
35 * Global memory handles in NT are not really global, they're still local to the
36 * process. So, what happens under the hood is that PostMessage must handle the
37 * WM_DDE_EXECUTE message specially. It will obtain the contents of the global memory
38 * area, repack that into a new structure together with the original memory handle
39 * and pass that off to the win32k. Win32k will marshall that data over to the target
40 * (server) process where it will be unpacked and stored in a newly allocated global
41 * memory area. The handle of that area will then be sent to the window proc, after
42 * storing it together with the "original" (client) handle in a table.
43 * The server will eventually post the WM_DDE_ACK response, containing the global
44 * memory handle it received. PostMessage must then lookup that memory handle (only
45 * valid in the server process) and replace it with the corresponding client memory
46 * handle. To avoid memory leaks, the server-side global memory block must be freed.
47 * Also, the WM_DDE_ACK lParam (a PackDDElParam() result) is unpacked and the
48 * individual components are handed to win32k.sys to post to the client side. Since
49 * the server side app hands over ownership of the packed lParam when it calls
50 * PostMessage(), the packed lParam needs to be freed on the server side too.
51 * When the WM_DDE_ACK message (containing the client-side global memory handle)
52 * arrives at the client side a new lParam is PackDDElParam()'ed and this is handed
53 * to the client side window proc which is expected to free/reuse it.
54 */
55
56 /* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
57 * to the memory handle, we keep track (in the server side) of all pairs of handle
58 * used (the client passes its value and the content of the memory handle), and
59 * the server stored both values (the client, and the local one, created after the
60 * content). When a ACK message is generated, the list of pair is searched for a
61 * matching pair, so that the client memory handle can be returned.
62 */
63
64 typedef struct tagDDEPAIR
65 {
66 HGLOBAL ClientMem;
67 HGLOBAL ServerMem;
68 } DDEPAIR, *PDDEPAIR;
69
70 static PDDEPAIR DdePairs = NULL;
71 static unsigned DdeNumAlloc = 0;
72 static unsigned DdeNumUsed = 0;
73 static CRITICAL_SECTION DdeCrst;
74
75 static BOOL FASTCALL
76 DdeAddPair(HGLOBAL ClientMem, HGLOBAL ServerMem)
77 {
78 unsigned i;
79
80 EnterCriticalSection(&DdeCrst);
81
82 /* now remember the pair of hMem on both sides */
83 if (DdeNumUsed == DdeNumAlloc)
84 {
85 #define GROWBY 4
86 PDDEPAIR New;
87 if (NULL != DdePairs)
88 {
89 New = HeapReAlloc(GetProcessHeap(), 0, DdePairs,
90 (DdeNumAlloc + GROWBY) * sizeof(DDEPAIR));
91 }
92 else
93 {
94 New = HeapAlloc(GetProcessHeap(), 0,
95 (DdeNumAlloc + GROWBY) * sizeof(DDEPAIR));
96 }
97
98 if (NULL == New)
99 {
100 LeaveCriticalSection(&DdeCrst);
101 return FALSE;
102 }
103 DdePairs = New;
104 /* zero out newly allocated part */
105 memset(&DdePairs[DdeNumAlloc], 0, GROWBY * sizeof(DDEPAIR));
106 DdeNumAlloc += GROWBY;
107 #undef GROWBY
108 }
109
110 for (i = 0; i < DdeNumAlloc; i++)
111 {
112 if (NULL == DdePairs[i].ServerMem)
113 {
114 DdePairs[i].ClientMem = ClientMem;
115 DdePairs[i].ServerMem = ServerMem;
116 DdeNumUsed++;
117 break;
118 }
119 }
120 LeaveCriticalSection(&DdeCrst);
121
122 return TRUE;
123 }
124
125 static HGLOBAL FASTCALL
126 DdeGetPair(HGLOBAL ServerMem)
127 {
128 unsigned i;
129 HGLOBAL Ret = NULL;
130
131 EnterCriticalSection(&DdeCrst);
132 for (i = 0; i < DdeNumAlloc; i++)
133 {
134 if (DdePairs[i].ServerMem == ServerMem)
135 {
136 /* free this pair */
137 DdePairs[i].ServerMem = 0;
138 DdeNumUsed--;
139 Ret = DdePairs[i].ClientMem;
140 break;
141 }
142 }
143 LeaveCriticalSection(&DdeCrst);
144
145 return Ret;
146 }
147
148 static BOOL FASTCALL
149 MsgiUMToKMMessage(PMSG UMMsg, PMSG KMMsg, BOOL Posted)
150 {
151 *KMMsg = *UMMsg;
152
153 switch (UMMsg->message)
154 {
155 case WM_DDE_ACK:
156 {
157 PKMDDELPARAM DdeLparam;
158 DdeLparam = HeapAlloc(GetProcessHeap(), 0, sizeof(KMDDELPARAM));
159 if (NULL == DdeLparam)
160 {
161 return FALSE;
162 }
163 if (Posted)
164 {
165 DdeLparam->Packed = TRUE;
166 if (! UnpackDDElParam(UMMsg->message, UMMsg->lParam,
167 &DdeLparam->Value.Packed.uiLo,
168 &DdeLparam->Value.Packed.uiHi))
169 {
170 return FALSE;
171 }
172 if (0 != HIWORD(DdeLparam->Value.Packed.uiHi))
173 {
174 /* uiHi should contain a hMem from WM_DDE_EXECUTE */
175 HGLOBAL h = DdeGetPair((HGLOBAL) DdeLparam->Value.Packed.uiHi);
176 if (NULL != h)
177 {
178 GlobalFree((HGLOBAL) DdeLparam->Value.Packed.uiHi);
179 DdeLparam->Value.Packed.uiHi = (UINT) h;
180 }
181 }
182 FreeDDElParam(UMMsg->message, UMMsg->lParam);
183 }
184 else
185 {
186 DdeLparam->Packed = FALSE;
187 DdeLparam->Value.Unpacked = UMMsg->lParam;
188 }
189 KMMsg->lParam = (LPARAM) DdeLparam;
190 }
191 break;
192
193 case WM_DDE_EXECUTE:
194 {
195 SIZE_T Size;
196 PKMDDEEXECUTEDATA KMDdeExecuteData;
197 PVOID Data;
198
199 Size = GlobalSize((HGLOBAL) UMMsg->lParam);
200 Data = GlobalLock((HGLOBAL) UMMsg->lParam);
201 if (NULL == Data)
202 {
203 SetLastError(ERROR_INVALID_HANDLE);
204 return FALSE;
205 }
206 KMDdeExecuteData = HeapAlloc(GetProcessHeap(), 0, sizeof(KMDDEEXECUTEDATA) + Size);
207 if (NULL == KMDdeExecuteData)
208 {
209 SetLastError(ERROR_OUTOFMEMORY);
210 return FALSE;
211 }
212 KMDdeExecuteData->Sender = (HWND) UMMsg->wParam;
213 KMDdeExecuteData->ClientMem = (HGLOBAL) UMMsg->lParam;
214 memcpy((PVOID) (KMDdeExecuteData + 1), Data, Size);
215 KMMsg->wParam = sizeof(KMDDEEXECUTEDATA) + Size;
216 KMMsg->lParam = (LPARAM) KMDdeExecuteData;
217 GlobalUnlock((HGLOBAL) UMMsg->lParam);
218 }
219 break;
220
221 case WM_COPYDATA:
222 {
223 PCOPYDATASTRUCT pUMCopyData = (PCOPYDATASTRUCT)UMMsg->lParam;
224 PCOPYDATASTRUCT pKMCopyData;
225
226 pKMCopyData = HeapAlloc(GetProcessHeap(), 0,
227 sizeof(COPYDATASTRUCT) + pUMCopyData->cbData);
228 if (pKMCopyData == NULL)
229 {
230 SetLastError(ERROR_OUTOFMEMORY);
231 return FALSE;
232 }
233
234 pKMCopyData->dwData = pUMCopyData->dwData;
235 pKMCopyData->cbData = pUMCopyData->cbData;
236 pKMCopyData->lpData = pKMCopyData + 1;
237
238 RtlCopyMemory(pKMCopyData + 1, pUMCopyData->lpData,
239 pUMCopyData->cbData);
240
241 KMMsg->lParam = (LPARAM)pKMCopyData;
242 }
243 break;
244
245 default:
246 break;
247 }
248
249 return TRUE;
250 }
251
252 static VOID FASTCALL
253 MsgiUMToKMCleanup(PMSG UMMsg, PMSG KMMsg)
254 {
255 switch (KMMsg->message)
256 {
257 case WM_DDE_ACK:
258 case WM_DDE_EXECUTE:
259 case WM_COPYDATA:
260 HeapFree(GetProcessHeap(), 0, (LPVOID) KMMsg->lParam);
261 break;
262 default:
263 break;
264 }
265
266 return;
267 }
268
269 static BOOL FASTCALL
270 MsgiUMToKMReply(PMSG UMMsg, PMSG KMMsg, LRESULT *Result)
271 {
272 MsgiUMToKMCleanup(UMMsg, KMMsg);
273
274 return TRUE;
275 }
276
277 static BOOL FASTCALL
278 MsgiKMToUMMessage(PMSG KMMsg, PMSG UMMsg)
279 {
280 *UMMsg = *KMMsg;
281
282 switch (UMMsg->message)
283 {
284 case WM_CREATE:
285 case WM_NCCREATE:
286 {
287 CREATESTRUCTW *Cs = (CREATESTRUCTW *) KMMsg->lParam;
288 PCHAR Class;
289 Cs->lpszName = (LPCWSTR) ((PCHAR) Cs + (DWORD_PTR) Cs->lpszName);
290 Class = (PCHAR) Cs + (DWORD_PTR) Cs->lpszClass;
291 if (L'A' == *((WCHAR *) Class))
292 {
293 Class += sizeof(WCHAR);
294 Cs->lpszClass = (LPCWSTR)(DWORD_PTR) (*((ATOM *) Class));
295 }
296 else
297 {
298 ASSERT(L'S' == *((WCHAR *) Class));
299 Class += sizeof(WCHAR);
300 Cs->lpszClass = (LPCWSTR) Class;
301 }
302 }
303 break;
304
305 case WM_DDE_ACK:
306 {
307 PKMDDELPARAM DdeLparam = (PKMDDELPARAM) KMMsg->lParam;
308 if (DdeLparam->Packed)
309 {
310 UMMsg->lParam = PackDDElParam(KMMsg->message,
311 DdeLparam->Value.Packed.uiLo,
312 DdeLparam->Value.Packed.uiHi);
313 }
314 else
315 {
316 UMMsg->lParam = DdeLparam->Value.Unpacked;
317 }
318 }
319 break;
320
321 case WM_DDE_EXECUTE:
322 {
323 PKMDDEEXECUTEDATA KMDdeExecuteData;
324 HGLOBAL GlobalData;
325 PVOID Data;
326
327 KMDdeExecuteData = (PKMDDEEXECUTEDATA) KMMsg->lParam;
328 GlobalData = GlobalAlloc(GMEM_MOVEABLE, KMMsg->wParam - sizeof(KMDDEEXECUTEDATA));
329 if (NULL == GlobalData)
330 {
331 return FALSE;
332 }
333 Data = GlobalLock(GlobalData);
334 if (NULL == Data)
335 {
336 GlobalFree(GlobalData);
337 return FALSE;
338 }
339 memcpy(Data, (PVOID) (KMDdeExecuteData + 1), KMMsg->wParam - sizeof(KMDDEEXECUTEDATA));
340 GlobalUnlock(GlobalData);
341 if (! DdeAddPair(KMDdeExecuteData->ClientMem, GlobalData))
342 {
343 GlobalFree(GlobalData);
344 return FALSE;
345 }
346 UMMsg->wParam = (WPARAM) KMDdeExecuteData->Sender;
347 UMMsg->lParam = (LPARAM) GlobalData;
348 }
349 break;
350
351 case WM_COPYDATA:
352 {
353 PCOPYDATASTRUCT pKMCopyData = (PCOPYDATASTRUCT)KMMsg->lParam;
354 pKMCopyData->lpData = pKMCopyData + 1;
355 }
356 break;
357
358 default:
359 break;
360 }
361
362 return TRUE;
363 }
364
365 static VOID FASTCALL
366 MsgiKMToUMCleanup(PMSG KMMsg, PMSG UMMsg)
367 {
368 switch (KMMsg->message)
369 {
370 case WM_DDE_EXECUTE:
371 #ifdef TODO
372 HeapFree(GetProcessHeap(), 0, (LPVOID) KMMsg->lParam);
373 GlobalUnlock((HGLOBAL) UMMsg->lParam);
374 #endif
375 break;
376 default:
377 break;
378 }
379
380 return;
381 }
382
383 static BOOL FASTCALL
384 MsgiKMToUMReply(PMSG KMMsg, PMSG UMMsg, LRESULT *Result)
385 {
386 MsgiKMToUMCleanup(KMMsg, UMMsg);
387
388 return TRUE;
389 }
390
391 static BOOL FASTCALL
392 MsgiAnsiToUnicodeMessage(LPMSG UnicodeMsg, LPMSG AnsiMsg)
393 {
394 UNICODE_STRING UnicodeString;
395
396 *UnicodeMsg = *AnsiMsg;
397
398 switch (AnsiMsg->message)
399 {
400 case WM_GETTEXT:
401 case WM_ASKCBFORMATNAME:
402 {
403 LPWSTR Buffer = HeapAlloc(GetProcessHeap(), 0,
404 AnsiMsg->wParam * sizeof(WCHAR));
405 if (!Buffer)
406 {
407 return FALSE;
408 }
409 UnicodeMsg->lParam = (LPARAM)Buffer;
410 break;
411 }
412
413 /* AnsiMsg->lParam is string (0-terminated) */
414 case WM_SETTEXT:
415 case WM_WININICHANGE:
416 case WM_DEVMODECHANGE:
417 case CB_DIR:
418 case LB_DIR:
419 case LB_ADDFILE:
420 case EM_REPLACESEL:
421 {
422 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam);
423 UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer;
424 break;
425 }
426
427 case LB_ADDSTRING:
428 case LB_ADDSTRING_LOWER:
429 case LB_ADDSTRING_UPPER:
430 case LB_INSERTSTRING:
431 case LB_INSERTSTRING_UPPER:
432 case LB_INSERTSTRING_LOWER:
433 case LB_FINDSTRING:
434 case LB_FINDSTRINGEXACT:
435 case LB_SELECTSTRING:
436 {
437 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
438 if (!(dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) &&
439 (dwStyle & LBS_HASSTRINGS))
440 {
441 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam);
442 UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer;
443 }
444 break;
445 }
446
447 case CB_ADDSTRING:
448 case CB_INSERTSTRING:
449 case CB_FINDSTRING:
450 case CB_FINDSTRINGEXACT:
451 case CB_SELECTSTRING:
452 {
453 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
454 if (!(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
455 (dwStyle & CBS_HASSTRINGS))
456 {
457 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam);
458 UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer;
459 }
460 break;
461 }
462
463 case WM_NCCREATE:
464 case WM_CREATE:
465 {
466 struct s
467 {
468 CREATESTRUCTW cs; /* new structure */
469 LPCWSTR lpszName; /* allocated Name */
470 LPCWSTR lpszClass; /* allocated Class */
471 };
472
473 struct s *xs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct s));
474 if (!xs)
475 {
476 return FALSE;
477 }
478 xs->cs = *(CREATESTRUCTW *)AnsiMsg->lParam;
479 if (!IS_INTRESOURCE(xs->cs.lpszName))
480 {
481 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)xs->cs.lpszName);
482 xs->lpszName = xs->cs.lpszName = UnicodeString.Buffer;
483 }
484 if (!IS_ATOM(xs->cs.lpszClass))
485 {
486 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)xs->cs.lpszClass);
487 xs->lpszClass = xs->cs.lpszClass = UnicodeString.Buffer;
488 }
489 UnicodeMsg->lParam = (LPARAM)xs;
490 break;
491 }
492
493 case WM_MDICREATE:
494 {
495 MDICREATESTRUCTW *cs =
496 (MDICREATESTRUCTW *)HeapAlloc(GetProcessHeap(), 0, sizeof(*cs));
497
498 if (!cs)
499 {
500 return FALSE;
501 }
502
503 *cs = *(MDICREATESTRUCTW *)AnsiMsg->lParam;
504
505 if (!IS_ATOM(cs->szClass))
506 {
507 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)cs->szClass);
508 cs->szClass = UnicodeString.Buffer;
509 }
510
511 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)cs->szTitle);
512 cs->szTitle = UnicodeString.Buffer;
513
514 UnicodeMsg->lParam = (LPARAM)cs;
515 break;
516 }
517 }
518
519 return TRUE;
520 }
521
522
523 static BOOL FASTCALL
524 MsgiAnsiToUnicodeCleanup(LPMSG UnicodeMsg, LPMSG AnsiMsg)
525 {
526 UNICODE_STRING UnicodeString;
527
528 switch (AnsiMsg->message)
529 {
530 case WM_GETTEXT:
531 case WM_ASKCBFORMATNAME:
532 {
533 HeapFree(GetProcessHeap(), 0, (PVOID) UnicodeMsg->lParam);
534 break;
535 }
536
537 case WM_SETTEXT:
538 case WM_WININICHANGE:
539 case WM_DEVMODECHANGE:
540 case CB_DIR:
541 case LB_DIR:
542 case LB_ADDFILE:
543 case EM_REPLACESEL:
544 {
545 RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam);
546 RtlFreeUnicodeString(&UnicodeString);
547 break;
548 }
549
550 case LB_ADDSTRING:
551 case LB_ADDSTRING_LOWER:
552 case LB_ADDSTRING_UPPER:
553 case LB_INSERTSTRING:
554 case LB_INSERTSTRING_UPPER:
555 case LB_INSERTSTRING_LOWER:
556 case LB_FINDSTRING:
557 case LB_FINDSTRINGEXACT:
558 case LB_SELECTSTRING:
559 {
560 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
561 if (!(dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) &&
562 (dwStyle & LBS_HASSTRINGS))
563 {
564 RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam);
565 RtlFreeUnicodeString(&UnicodeString);
566 }
567 break;
568 }
569
570 case CB_ADDSTRING:
571 case CB_INSERTSTRING:
572 case CB_FINDSTRING:
573 case CB_FINDSTRINGEXACT:
574 case CB_SELECTSTRING:
575 {
576 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
577 if (!(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
578 (dwStyle & CBS_HASSTRINGS))
579 {
580 RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam);
581 RtlFreeUnicodeString(&UnicodeString);
582 }
583 break;
584 }
585
586 case WM_NCCREATE:
587 case WM_CREATE:
588 {
589 struct s
590 {
591 CREATESTRUCTW cs; /* new structure */
592 LPWSTR lpszName; /* allocated Name */
593 LPWSTR lpszClass; /* allocated Class */
594 };
595
596 struct s *xs = (struct s *)UnicodeMsg->lParam;
597 if (xs->lpszName)
598 {
599 RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszName);
600 RtlFreeUnicodeString(&UnicodeString);
601 }
602 if (xs->lpszClass)
603 {
604 RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszClass);
605 RtlFreeUnicodeString(&UnicodeString);
606 }
607 HeapFree(GetProcessHeap(), 0, xs);
608 break;
609 }
610
611 case WM_MDICREATE:
612 {
613 MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)UnicodeMsg->lParam;
614 RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szTitle);
615 RtlFreeUnicodeString(&UnicodeString);
616 if (!IS_ATOM(cs->szClass))
617 {
618 RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szClass);
619 RtlFreeUnicodeString(&UnicodeString);
620 }
621 HeapFree(GetProcessHeap(), 0, cs);
622 break;
623 }
624 }
625
626 return(TRUE);
627 }
628
629
630 static BOOL FASTCALL
631 MsgiAnsiToUnicodeReply(LPMSG UnicodeMsg, LPMSG AnsiMsg, LRESULT *Result)
632 {
633 switch (AnsiMsg->message)
634 {
635 case WM_GETTEXT:
636 case WM_ASKCBFORMATNAME:
637 {
638 LPWSTR Buffer = (LPWSTR)UnicodeMsg->lParam;
639 LPSTR AnsiBuffer = (LPSTR)AnsiMsg->lParam;
640 if (UnicodeMsg->wParam > 0 &&
641 !WideCharToMultiByte(CP_ACP, 0, Buffer, -1,
642 AnsiBuffer, UnicodeMsg->wParam, NULL, NULL))
643 {
644 AnsiBuffer[UnicodeMsg->wParam - 1] = 0;
645 }
646 break;
647 }
648 }
649
650 MsgiAnsiToUnicodeCleanup(UnicodeMsg, AnsiMsg);
651
652 return TRUE;
653 }
654
655
656 static BOOL FASTCALL
657 MsgiUnicodeToAnsiMessage(LPMSG AnsiMsg, LPMSG UnicodeMsg)
658 {
659 ANSI_STRING AnsiString;
660 UNICODE_STRING UnicodeString;
661
662 *AnsiMsg = *UnicodeMsg;
663
664 switch(UnicodeMsg->message)
665 {
666 case WM_CREATE:
667 case WM_NCCREATE:
668 {
669 CREATESTRUCTA* CsA;
670 CREATESTRUCTW* CsW;
671 NTSTATUS Status;
672
673 CsW = (CREATESTRUCTW*)(UnicodeMsg->lParam);
674 CsA = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(CREATESTRUCTA));
675 if (NULL == CsA)
676 {
677 return FALSE;
678 }
679 memcpy(CsA, CsW, sizeof(CREATESTRUCTW));
680
681 RtlInitUnicodeString(&UnicodeString, CsW->lpszName);
682 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
683 if (! NT_SUCCESS(Status))
684 {
685 RtlFreeHeap(GetProcessHeap(), 0, CsA);
686 return FALSE;
687 }
688 CsA->lpszName = AnsiString.Buffer;
689 if (HIWORD((ULONG)CsW->lpszClass) != 0)
690 {
691 RtlInitUnicodeString(&UnicodeString, CsW->lpszClass);
692 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
693 if (! NT_SUCCESS(Status))
694 {
695 RtlInitAnsiString(&AnsiString, CsA->lpszName);
696 RtlFreeAnsiString(&AnsiString);
697 RtlFreeHeap(GetProcessHeap(), 0, CsA);
698 return FALSE;
699 }
700 CsA->lpszClass = AnsiString.Buffer;
701 }
702 AnsiMsg->lParam = (LPARAM)CsA;
703 break;
704 }
705 case WM_GETTEXT:
706 {
707 /* Ansi string might contain MBCS chars so we need 2 * the number of chars */
708 AnsiMsg->wParam = UnicodeMsg->wParam * 2;
709 AnsiMsg->lParam = (LPARAM) RtlAllocateHeap(GetProcessHeap(), 0, AnsiMsg->wParam);
710 if (NULL == (PVOID) AnsiMsg->lParam)
711 {
712 return FALSE;
713 }
714 break;
715 }
716 case WM_SETTEXT:
717 case CB_DIR:
718 case LB_DIR:
719 case LB_ADDFILE:
720 {
721 RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
722 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
723 &UnicodeString,
724 TRUE)))
725 {
726 return FALSE;
727 }
728 AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
729 break;
730 }
731
732 case LB_ADDSTRING:
733 case LB_ADDSTRING_LOWER:
734 case LB_ADDSTRING_UPPER:
735 case LB_INSERTSTRING:
736 case LB_INSERTSTRING_UPPER:
737 case LB_INSERTSTRING_LOWER:
738 case LB_FINDSTRING:
739 case LB_FINDSTRINGEXACT:
740 case LB_SELECTSTRING:
741 {
742 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
743 if (!(dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) &&
744 (dwStyle & LBS_HASSTRINGS))
745 {
746 RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
747 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
748 &UnicodeString,
749 TRUE)))
750 {
751 return FALSE;
752 }
753 AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
754 }
755 break;
756 }
757
758 case CB_ADDSTRING:
759 case CB_INSERTSTRING:
760 case CB_FINDSTRING:
761 case CB_FINDSTRINGEXACT:
762 case CB_SELECTSTRING:
763 {
764 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
765 if (!(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
766 (dwStyle & CBS_HASSTRINGS))
767 {
768 RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
769 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
770 &UnicodeString,
771 TRUE)))
772 {
773 return FALSE;
774 }
775 AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
776 }
777 break;
778 }
779
780 case WM_MDICREATE:
781 {
782 MDICREATESTRUCTA *cs =
783 (MDICREATESTRUCTA *)HeapAlloc(GetProcessHeap(), 0, sizeof(*cs));
784
785 if (!cs)
786 {
787 return FALSE;
788 }
789
790 *cs = *(MDICREATESTRUCTA *)UnicodeMsg->lParam;
791
792 if (!IS_ATOM(cs->szClass))
793 {
794 RtlInitUnicodeString(&UnicodeString, (LPCWSTR)cs->szClass);
795 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
796 &UnicodeString,
797 TRUE)))
798 {
799 return FALSE;
800 }
801 cs->szClass = AnsiString.Buffer;
802 }
803
804 RtlInitUnicodeString(&UnicodeString, (LPCWSTR)cs->szTitle);
805 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
806 &UnicodeString,
807 TRUE)))
808 {
809 if (!IS_ATOM(cs->szClass))
810 {
811 RtlInitAnsiString(&AnsiString, cs->szClass);
812 RtlFreeAnsiString(&AnsiString);
813 }
814 return FALSE;
815 }
816 cs->szTitle = AnsiString.Buffer;
817
818 AnsiMsg->lParam = (LPARAM)cs;
819 break;
820 }
821 }
822
823 return TRUE;
824 }
825
826
827 static BOOL FASTCALL
828 MsgiUnicodeToAnsiCleanup(LPMSG AnsiMsg, LPMSG UnicodeMsg)
829 {
830 ANSI_STRING AnsiString;
831
832 switch(UnicodeMsg->message)
833 {
834 case WM_GETTEXT:
835 {
836 RtlFreeHeap(GetProcessHeap(), 0, (PVOID) AnsiMsg->lParam);
837 break;
838 }
839 case WM_SETTEXT:
840 {
841 RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
842 RtlFreeAnsiString(&AnsiString);
843 break;
844 }
845 case WM_CREATE:
846 case WM_NCCREATE:
847 {
848 CREATESTRUCTA* Cs;
849
850 Cs = (CREATESTRUCTA*) AnsiMsg->lParam;
851 RtlInitAnsiString(&AnsiString, Cs->lpszName);
852 RtlFreeAnsiString(&AnsiString);
853 if (HIWORD((ULONG)Cs->lpszClass) != 0)
854 {
855 RtlInitAnsiString(&AnsiString, Cs->lpszClass);
856 RtlFreeAnsiString(&AnsiString);
857 }
858 RtlFreeHeap(GetProcessHeap(), 0, Cs);
859 break;
860 }
861
862 case LB_ADDSTRING:
863 case LB_ADDSTRING_LOWER:
864 case LB_ADDSTRING_UPPER:
865 case LB_INSERTSTRING:
866 case LB_INSERTSTRING_UPPER:
867 case LB_INSERTSTRING_LOWER:
868 case LB_FINDSTRING:
869 case LB_FINDSTRINGEXACT:
870 case LB_SELECTSTRING:
871 {
872 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
873 if (!(dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) &&
874 (dwStyle & LBS_HASSTRINGS))
875 {
876 RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
877 RtlFreeAnsiString(&AnsiString);
878 }
879 break;
880 }
881
882 case CB_ADDSTRING:
883 case CB_INSERTSTRING:
884 case CB_FINDSTRING:
885 case CB_FINDSTRINGEXACT:
886 case CB_SELECTSTRING:
887 {
888 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
889 if (!(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
890 (dwStyle & CBS_HASSTRINGS))
891 {
892 RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
893 RtlFreeAnsiString(&AnsiString);
894 }
895 break;
896 }
897
898 case WM_MDICREATE:
899 {
900 MDICREATESTRUCTA *cs = (MDICREATESTRUCTA *)AnsiMsg->lParam;
901 RtlInitAnsiString(&AnsiString, (PCSTR)cs->szTitle);
902 RtlFreeAnsiString(&AnsiString);
903 if (!IS_ATOM(cs->szClass))
904 {
905 RtlInitAnsiString(&AnsiString, (PCSTR)cs->szClass);
906 RtlFreeAnsiString(&AnsiString);
907 }
908 HeapFree(GetProcessHeap(), 0, cs);
909 break;
910 }
911
912 }
913
914 return TRUE;
915 }
916
917
918 static BOOL FASTCALL
919 MsgiUnicodeToAnsiReply(LPMSG AnsiMsg, LPMSG UnicodeMsg, LRESULT *Result)
920 {
921 switch (UnicodeMsg->message)
922 {
923 case WM_GETTEXT:
924 case WM_ASKCBFORMATNAME:
925 {
926 LPSTR Buffer = (LPSTR) AnsiMsg->lParam;
927 LPWSTR UBuffer = (LPWSTR) UnicodeMsg->lParam;
928 if (0 < AnsiMsg->wParam &&
929 ! MultiByteToWideChar(CP_ACP, 0, Buffer, -1, UBuffer, UnicodeMsg->wParam))
930 {
931 UBuffer[UnicodeMsg->wParam - 1] = L'\0';
932 }
933 break;
934 }
935 }
936
937 MsgiUnicodeToAnsiCleanup(AnsiMsg, UnicodeMsg);
938
939 return TRUE;
940 }
941
942 typedef struct tagMSGCONVERSION
943 {
944 BOOL InUse;
945 BOOL Ansi;
946 MSG KMMsg;
947 MSG UnicodeMsg;
948 MSG AnsiMsg;
949 PMSG FinalMsg;
950 ULONG LParamSize;
951 } MSGCONVERSION, *PMSGCONVERSION;
952
953 static PMSGCONVERSION MsgConversions = NULL;
954 static unsigned MsgConversionNumAlloc = 0;
955 static unsigned MsgConversionNumUsed = 0;
956 static CRITICAL_SECTION MsgConversionCrst;
957
958 static BOOL FASTCALL
959 MsgConversionAdd(PMSGCONVERSION Conversion)
960 {
961 unsigned i;
962
963 EnterCriticalSection(&MsgConversionCrst);
964
965 if (MsgConversionNumUsed == MsgConversionNumAlloc)
966 {
967 #define GROWBY 4
968 PMSGCONVERSION New;
969 if (NULL != MsgConversions)
970 {
971 New = HeapReAlloc(GetProcessHeap(), 0, MsgConversions,
972 (MsgConversionNumAlloc + GROWBY) * sizeof(MSGCONVERSION));
973 }
974 else
975 {
976 New = HeapAlloc(GetProcessHeap(), 0,
977 (MsgConversionNumAlloc + GROWBY) * sizeof(MSGCONVERSION));
978 }
979
980 if (NULL == New)
981 {
982 LeaveCriticalSection(&MsgConversionCrst);
983 return FALSE;
984 }
985 MsgConversions = New;
986 /* zero out newly allocated part */
987 memset(MsgConversions + MsgConversionNumAlloc, 0, GROWBY * sizeof(MSGCONVERSION));
988 MsgConversionNumAlloc += GROWBY;
989 #undef GROWBY
990 }
991
992 for (i = 0; i < MsgConversionNumAlloc; i++)
993 {
994 if (! MsgConversions[i].InUse)
995 {
996 MsgConversions[i] = *Conversion;
997 MsgConversions[i].InUse = TRUE;
998 MsgConversionNumUsed++;
999 break;
1000 }
1001 }
1002 LeaveCriticalSection(&MsgConversionCrst);
1003
1004 return TRUE;
1005 }
1006
1007 static void FASTCALL
1008 MsgConversionCleanup(CONST MSG *Msg, BOOL Ansi, BOOL CheckMsgContents, LRESULT *Result)
1009 {
1010 BOOL Found;
1011 PMSGCONVERSION Conversion;
1012 LRESULT Dummy;
1013
1014 EnterCriticalSection(&MsgConversionCrst);
1015 for (Conversion = MsgConversions;
1016 Conversion < MsgConversions + MsgConversionNumAlloc;
1017 Conversion++)
1018 {
1019 if (Conversion->InUse &&
1020 ((Ansi && Conversion->Ansi) ||
1021 (! Ansi && ! Conversion->Ansi)))
1022 {
1023 Found = (Conversion->FinalMsg == Msg);
1024 if (! Found && CheckMsgContents)
1025 {
1026 if (Ansi)
1027 {
1028 Found = (0 == memcmp(Msg, &Conversion->AnsiMsg, sizeof(MSG)));
1029 }
1030 else
1031 {
1032 Found = (0 == memcmp(Msg, &Conversion->UnicodeMsg, sizeof(MSG)));
1033 }
1034 }
1035 if (Found)
1036 {
1037 if (Ansi)
1038 {
1039 MsgiUnicodeToAnsiReply(&Conversion->AnsiMsg, &Conversion->UnicodeMsg,
1040 NULL == Result ? &Dummy : Result);
1041 }
1042 MsgiKMToUMReply(&Conversion->KMMsg, &Conversion->UnicodeMsg,
1043 NULL == Result ? &Dummy : Result);
1044 if (0 != Conversion->LParamSize)
1045 {
1046 NtFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &Conversion->KMMsg.lParam,
1047 &Conversion->LParamSize, MEM_DECOMMIT);
1048 }
1049 Conversion->InUse = FALSE;
1050 MsgConversionNumUsed--;
1051 }
1052 }
1053 }
1054 LeaveCriticalSection(&MsgConversionCrst);
1055 }
1056
1057 /*
1058 * @implemented
1059 */
1060 LPARAM
1061 WINAPI
1062 GetMessageExtraInfo(VOID)
1063 {
1064 return (LPARAM)NtUserCallNoParam(NOPARAM_ROUTINE_GETMESSAGEEXTRAINFO);
1065 }
1066
1067
1068 /*
1069 * @implemented
1070 */
1071 DWORD
1072 WINAPI
1073 GetMessagePos(VOID)
1074 {
1075 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
1076 return(MAKELONG(ThreadData->LastMessage.pt.x, ThreadData->LastMessage.pt.y));
1077 }
1078
1079
1080 /*
1081 * @implemented
1082 */
1083 LONG WINAPI
1084 GetMessageTime(VOID)
1085 {
1086 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
1087 return(ThreadData->LastMessage.time);
1088 // return NtUserGetThreadState(THREADSTATE_GETMESSAGETIME);
1089 }
1090
1091
1092 /*
1093 * @unimplemented
1094 */
1095 BOOL
1096 WINAPI
1097 InSendMessage(VOID)
1098 {
1099 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
1100 // FIXME("ISM %x\n",pcti);
1101 if ( pcti )
1102 {
1103 if (pcti->CTI_flags & CTI_INSENDMESSAGE)
1104 {
1105 return TRUE;
1106 }
1107 }
1108 return(NtUserGetThreadState(THREADSTATE_INSENDMESSAGE) != ISMEX_NOSEND);
1109 }
1110
1111
1112 /*
1113 * @unimplemented
1114 */
1115 DWORD
1116 WINAPI
1117 InSendMessageEx(
1118 LPVOID lpReserved)
1119 {
1120 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
1121 // FIXME("ISMEX %x\n",pcti);
1122 if (pcti && !(pcti->CTI_flags & CTI_INSENDMESSAGE))
1123 return ISMEX_NOSEND;
1124 else
1125 return NtUserGetThreadState(THREADSTATE_INSENDMESSAGE);
1126 }
1127
1128
1129 /*
1130 * @implemented
1131 */
1132 BOOL
1133 WINAPI
1134 ReplyMessage(
1135 LRESULT lResult)
1136 {
1137 return NtUserCallOneParam(lResult, ONEPARAM_ROUTINE_REPLYMESSAGE);
1138 }
1139
1140
1141 /*
1142 * @implemented
1143 */
1144 LPARAM
1145 WINAPI
1146 SetMessageExtraInfo(
1147 LPARAM lParam)
1148 {
1149 return NtUserSetMessageExtraInfo(lParam);
1150 }
1151
1152 LRESULT FASTCALL
1153 IntCallWindowProcW(BOOL IsAnsiProc,
1154 WNDPROC WndProc,
1155 PWND pWnd,
1156 HWND hWnd,
1157 UINT Msg,
1158 WPARAM wParam,
1159 LPARAM lParam)
1160 {
1161 MSG AnsiMsg;
1162 MSG UnicodeMsg;
1163 BOOL Hook = FALSE, MsgOverride = FALSE, Dialog;
1164 LRESULT Result = 0, PreResult = 0;
1165 DWORD Data = 0;
1166
1167 if (WndProc == NULL)
1168 {
1169 WARN("IntCallWindowsProcW() called with WndProc = NULL!\n");
1170 return FALSE;
1171 }
1172
1173 if (pWnd)
1174 Dialog = (pWnd->fnid == FNID_DIALOG);
1175 else
1176 Dialog = FALSE;
1177
1178 Hook = BeginIfHookedUserApiHook();
1179 if (Hook)
1180 {
1181 if (!Dialog)
1182 MsgOverride = IsMsgOverride( Msg, &guah.WndProcArray);
1183 else
1184 MsgOverride = IsMsgOverride( Msg, &guah.DlgProcArray);
1185 }
1186
1187 if (IsAnsiProc)
1188 {
1189 UnicodeMsg.hwnd = hWnd;
1190 UnicodeMsg.message = Msg;
1191 UnicodeMsg.wParam = wParam;
1192 UnicodeMsg.lParam = lParam;
1193 if (! MsgiUnicodeToAnsiMessage(&AnsiMsg, &UnicodeMsg))
1194 {
1195 goto Exit;
1196 }
1197
1198 if (Hook && MsgOverride)
1199 {
1200 _SEH2_TRY
1201 {
1202 if (!Dialog)
1203 PreResult = guah.PreWndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1204 else
1205 PreResult = guah.PreDefDlgProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1206 }
1207 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1208 {
1209 }
1210 _SEH2_END;
1211 }
1212
1213 if (PreResult) goto Exit;
1214
1215 _SEH2_TRY // wine does this.
1216 {
1217 Result = WndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam);
1218 }
1219 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1220 {
1221 }
1222 _SEH2_END;
1223
1224 if (Hook && MsgOverride)
1225 {
1226 _SEH2_TRY
1227 {
1228 if (!Dialog)
1229 guah.PostWndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1230 else
1231 guah.PostDefDlgProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1232 }
1233 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1234 {
1235 }
1236 _SEH2_END;
1237 }
1238
1239 if (! MsgiUnicodeToAnsiReply(&AnsiMsg, &UnicodeMsg, &Result))
1240 {
1241 goto Exit;
1242 }
1243 }
1244 else
1245 {
1246 if (Hook && MsgOverride)
1247 {
1248 _SEH2_TRY
1249 {
1250 if (!Dialog)
1251 PreResult = guah.PreWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1252 else
1253 PreResult = guah.PreDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1254 }
1255 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1256 {
1257 }
1258 _SEH2_END;
1259 }
1260
1261 if (PreResult) goto Exit;
1262
1263 _SEH2_TRY
1264 {
1265 Result = WndProc(hWnd, Msg, wParam, lParam);
1266 }
1267 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1268 {
1269 }
1270 _SEH2_END;
1271
1272 if (Hook && MsgOverride)
1273 {
1274 _SEH2_TRY
1275 {
1276 if (!Dialog)
1277 guah.PostWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1278 else
1279 guah.PostDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1280 }
1281 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1282 {
1283 }
1284 _SEH2_END;
1285 }
1286 }
1287
1288 Exit:
1289 if (Hook) EndUserApiHook();
1290 return Result;
1291 }
1292
1293 static LRESULT FASTCALL
1294 IntCallWindowProcA(BOOL IsAnsiProc,
1295 WNDPROC WndProc,
1296 PWND pWnd,
1297 HWND hWnd,
1298 UINT Msg,
1299 WPARAM wParam,
1300 LPARAM lParam)
1301 {
1302 MSG AnsiMsg;
1303 MSG UnicodeMsg;
1304 BOOL Hook = FALSE, MsgOverride = FALSE, Dialog;
1305 LRESULT Result = 0, PreResult = 0;
1306 DWORD Data = 0;
1307
1308 if (WndProc == NULL)
1309 {
1310 WARN("IntCallWindowsProcA() called with WndProc = NULL!\n");
1311 return FALSE;
1312 }
1313
1314 if (pWnd)
1315 Dialog = (pWnd->fnid == FNID_DIALOG);
1316 else
1317 Dialog = FALSE;
1318
1319 Hook = BeginIfHookedUserApiHook();
1320 if (Hook)
1321 {
1322 if (!Dialog)
1323 MsgOverride = IsMsgOverride( Msg, &guah.WndProcArray);
1324 else
1325 MsgOverride = IsMsgOverride( Msg, &guah.DlgProcArray);
1326 }
1327
1328 if (IsAnsiProc)
1329 {
1330 if (Hook && MsgOverride)
1331 {
1332 _SEH2_TRY
1333 {
1334 if (!Dialog)
1335 PreResult = guah.PreWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1336 else
1337 PreResult = guah.PreDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1338 }
1339 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1340 {
1341 }
1342 _SEH2_END;
1343 }
1344
1345 if (PreResult) goto Exit;
1346
1347 _SEH2_TRY
1348 {
1349 Result = WndProc(hWnd, Msg, wParam, lParam);
1350 }
1351 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1352 {
1353 }
1354 _SEH2_END;
1355
1356 if (Hook && MsgOverride)
1357 {
1358 _SEH2_TRY
1359 {
1360 if (!Dialog)
1361 guah.PostWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1362 else
1363 guah.PostDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1364 }
1365 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1366 {
1367 }
1368 _SEH2_END;
1369 }
1370 }
1371 else
1372 {
1373 AnsiMsg.hwnd = hWnd;
1374 AnsiMsg.message = Msg;
1375 AnsiMsg.wParam = wParam;
1376 AnsiMsg.lParam = lParam;
1377 if (! MsgiAnsiToUnicodeMessage(&UnicodeMsg, &AnsiMsg))
1378 {
1379 goto Exit;
1380 }
1381
1382 if (Hook && MsgOverride)
1383 {
1384 _SEH2_TRY
1385 {
1386 if (!Dialog)
1387 PreResult = guah.PreWndProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1388 else
1389 PreResult = guah.PreDefDlgProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1390 }
1391 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1392 {
1393 }
1394 _SEH2_END;
1395 }
1396
1397 if (PreResult) goto Exit;
1398
1399 _SEH2_TRY
1400 {
1401 Result = WndProc(UnicodeMsg.hwnd, UnicodeMsg.message,
1402 UnicodeMsg.wParam, UnicodeMsg.lParam);
1403 }
1404 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1405 {
1406 }
1407 _SEH2_END;
1408
1409 if (Hook && MsgOverride)
1410 {
1411 _SEH2_TRY
1412 {
1413 if (!Dialog)
1414 guah.PostWndProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1415 else
1416 guah.PostDefDlgProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1417 }
1418 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1419 {
1420 }
1421 _SEH2_END;
1422 }
1423
1424 if (! MsgiAnsiToUnicodeReply(&UnicodeMsg, &AnsiMsg, &Result))
1425 {
1426 goto Exit;
1427 }
1428 }
1429
1430 Exit:
1431 if (Hook) EndUserApiHook();
1432 return Result;
1433 }
1434
1435
1436 static LRESULT WINAPI
1437 IntCallMessageProc(IN PWND Wnd, IN HWND hWnd, IN UINT Msg, IN WPARAM wParam, IN LPARAM lParam, IN BOOL Ansi)
1438 {
1439 WNDPROC WndProc;
1440 BOOL IsAnsi;
1441 PCLS Class;
1442
1443 Class = DesktopPtrToUser(Wnd->pcls);
1444 WndProc = NULL;
1445 /*
1446 This is the message exchange for user32. If there's a need to monitor messages,
1447 do it here!
1448 */
1449 TRACE("HWND 0x%x, MSG %d, WPARAM 0x%x, LPARAM 0x%x, Ansi &d\n",hWnd,Msg,wParam,lParam,Ansi);
1450 // if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON )
1451 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_FIRST )
1452 {
1453 if (Ansi)
1454 {
1455 if (GETPFNCLIENTW(Class->fnid) == Wnd->lpfnWndProc)
1456 WndProc = GETPFNCLIENTA(Class->fnid);
1457 }
1458 else
1459 {
1460 if (GETPFNCLIENTA(Class->fnid) == Wnd->lpfnWndProc)
1461 WndProc = GETPFNCLIENTW(Class->fnid);
1462 }
1463
1464 IsAnsi = Ansi;
1465
1466 if (!WndProc)
1467 {
1468 IsAnsi = !Wnd->Unicode;
1469 WndProc = Wnd->lpfnWndProc;
1470 }
1471 }
1472 else
1473 {
1474 IsAnsi = !Wnd->Unicode;
1475 WndProc = Wnd->lpfnWndProc;
1476 }
1477 /*
1478 Message caller can be Ansi/Unicode and the receiver can be Unicode/Ansi or
1479 the same.
1480 */
1481 if (!Ansi)
1482 return IntCallWindowProcW(IsAnsi, WndProc, Wnd, hWnd, Msg, wParam, lParam);
1483 else
1484 return IntCallWindowProcA(IsAnsi, WndProc, Wnd, hWnd, Msg, wParam, lParam);
1485 }
1486
1487
1488 /*
1489 * @implemented
1490 */
1491 LRESULT WINAPI
1492 CallWindowProcA(WNDPROC lpPrevWndFunc,
1493 HWND hWnd,
1494 UINT Msg,
1495 WPARAM wParam,
1496 LPARAM lParam)
1497 {
1498 PWND pWnd;
1499 PCALLPROCDATA CallProc;
1500
1501 if (lpPrevWndFunc == NULL)
1502 {
1503 WARN("CallWindowProcA: lpPrevWndFunc == NULL!\n");
1504 return 0;
1505 }
1506
1507 pWnd = ValidateHwnd(hWnd);
1508
1509 if (!IsCallProcHandle(lpPrevWndFunc))
1510 return IntCallWindowProcA(TRUE, lpPrevWndFunc, pWnd, hWnd, Msg, wParam, lParam);
1511 else
1512 {
1513 CallProc = ValidateCallProc((HANDLE)lpPrevWndFunc);
1514 if (CallProc != NULL)
1515 {
1516 return IntCallWindowProcA(!(CallProc->wType & UserGetCPDA2U),
1517 CallProc->pfnClientPrevious,
1518 pWnd,
1519 hWnd,
1520 Msg,
1521 wParam,
1522 lParam);
1523 }
1524 else
1525 {
1526 WARN("CallWindowProcA: can not dereference WndProcHandle\n");
1527 return 0;
1528 }
1529 }
1530 }
1531
1532
1533 /*
1534 * @implemented
1535 */
1536 LRESULT WINAPI
1537 CallWindowProcW(WNDPROC lpPrevWndFunc,
1538 HWND hWnd,
1539 UINT Msg,
1540 WPARAM wParam,
1541 LPARAM lParam)
1542 {
1543 PWND pWnd;
1544 PCALLPROCDATA CallProc;
1545
1546 /* FIXME - can the first parameter be NULL? */
1547 if (lpPrevWndFunc == NULL)
1548 {
1549 WARN("CallWindowProcA: lpPrevWndFunc == NULL!\n");
1550 return 0;
1551 }
1552
1553 pWnd = ValidateHwnd(hWnd);
1554
1555 if (!IsCallProcHandle(lpPrevWndFunc))
1556 return IntCallWindowProcW(FALSE, lpPrevWndFunc, pWnd, hWnd, Msg, wParam, lParam);
1557 else
1558 {
1559 CallProc = ValidateCallProc((HANDLE)lpPrevWndFunc);
1560 if (CallProc != NULL)
1561 {
1562 return IntCallWindowProcW(!(CallProc->wType & UserGetCPDA2U),
1563 CallProc->pfnClientPrevious,
1564 pWnd,
1565 hWnd,
1566 Msg,
1567 wParam,
1568 lParam);
1569 }
1570 else
1571 {
1572 WARN("CallWindowProcW: can not dereference WndProcHandle\n");
1573 return 0;
1574 }
1575 }
1576 }
1577
1578
1579 /*
1580 * @implemented
1581 */
1582 LRESULT WINAPI
1583 DispatchMessageA(CONST MSG *lpmsg)
1584 {
1585 LRESULT Ret = 0;
1586 MSG UnicodeMsg;
1587 PWND Wnd;
1588
1589 if (lpmsg->hwnd != NULL)
1590 {
1591 Wnd = ValidateHwnd(lpmsg->hwnd);
1592 if (!Wnd || Wnd->head.pti != GetW32ThreadInfo())
1593 return 0;
1594 }
1595 else
1596 Wnd = NULL;
1597
1598 if ((lpmsg->message == WM_TIMER || lpmsg->message == WM_SYSTIMER) && lpmsg->lParam != 0)
1599 {
1600 WNDPROC WndProc = (WNDPROC)lpmsg->lParam;
1601
1602 if ( lpmsg->message == WM_SYSTIMER )
1603 return NtUserDispatchMessage( (PMSG)lpmsg );
1604
1605 _SEH2_TRY // wine does this.
1606 {
1607 Ret = WndProc(lpmsg->hwnd,
1608 lpmsg->message,
1609 lpmsg->wParam,
1610 GetTickCount());
1611 }
1612 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1613 {
1614 }
1615 _SEH2_END;
1616
1617 }
1618 else if (Wnd != NULL)
1619 {
1620 if ( (lpmsg->message != WM_PAINT) && !(Wnd->state & WNDS_SERVERSIDEWINDOWPROC) )
1621 {
1622 Ret = IntCallMessageProc(Wnd,
1623 lpmsg->hwnd,
1624 lpmsg->message,
1625 lpmsg->wParam,
1626 lpmsg->lParam,
1627 TRUE);
1628 }
1629 else
1630 {
1631 if (!MsgiAnsiToUnicodeMessage(&UnicodeMsg, (LPMSG)lpmsg))
1632 {
1633 return FALSE;
1634 }
1635
1636 Ret = NtUserDispatchMessage(&UnicodeMsg);
1637
1638 if (!MsgiAnsiToUnicodeReply(&UnicodeMsg, (LPMSG)lpmsg, &Ret))
1639 {
1640 return FALSE;
1641 }
1642 }
1643 }
1644 return Ret;
1645 }
1646
1647
1648 /*
1649 * @implemented
1650 */
1651 LRESULT WINAPI
1652 DispatchMessageW(CONST MSG *lpmsg)
1653 {
1654 LRESULT Ret = 0;
1655 PWND Wnd;
1656
1657 if (lpmsg->hwnd != NULL)
1658 {
1659 Wnd = ValidateHwnd(lpmsg->hwnd);
1660 if (!Wnd || Wnd->head.pti != GetW32ThreadInfo())
1661 return 0;
1662 }
1663 else
1664 Wnd = NULL;
1665
1666 if ((lpmsg->message == WM_TIMER || lpmsg->message == WM_SYSTIMER) && lpmsg->lParam != 0)
1667 {
1668 WNDPROC WndProc = (WNDPROC)lpmsg->lParam;
1669
1670 if ( lpmsg->message == WM_SYSTIMER )
1671 return NtUserDispatchMessage( (PMSG) lpmsg );
1672
1673 _SEH2_TRY
1674 {
1675 Ret = WndProc(lpmsg->hwnd,
1676 lpmsg->message,
1677 lpmsg->wParam,
1678 GetTickCount());
1679 }
1680 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1681 {
1682 }
1683 _SEH2_END;
1684 }
1685 else if (Wnd != NULL)
1686 {
1687 if ( (lpmsg->message != WM_PAINT) && !(Wnd->state & WNDS_SERVERSIDEWINDOWPROC) )
1688 {
1689 Ret = IntCallMessageProc(Wnd,
1690 lpmsg->hwnd,
1691 lpmsg->message,
1692 lpmsg->wParam,
1693 lpmsg->lParam,
1694 FALSE);
1695 }
1696 else
1697 Ret = NtUserDispatchMessage( (PMSG) lpmsg );
1698 }
1699
1700 return Ret;
1701 }
1702
1703
1704 /*
1705 * @implemented
1706 */
1707 BOOL WINAPI
1708 GetMessageA(LPMSG lpMsg,
1709 HWND hWnd,
1710 UINT wMsgFilterMin,
1711 UINT wMsgFilterMax)
1712 {
1713 BOOL Res;
1714 MSGCONVERSION Conversion;
1715 NTUSERGETMESSAGEINFO Info;
1716 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
1717
1718 MsgConversionCleanup(lpMsg, TRUE, FALSE, NULL);
1719 Res = NtUserGetMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax);
1720 if (-1 == (int) Res)
1721 {
1722 return Res;
1723 }
1724 Conversion.LParamSize = Info.LParamSize;
1725 Conversion.KMMsg = Info.Msg;
1726
1727 if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg))
1728 {
1729 return (BOOL) -1;
1730 }
1731 if (! MsgiUnicodeToAnsiMessage(&Conversion.AnsiMsg, &Conversion.UnicodeMsg))
1732 {
1733 MsgiKMToUMCleanup(&Info.Msg, &Conversion.UnicodeMsg);
1734 return (BOOL) -1;
1735 }
1736 if (!lpMsg)
1737 {
1738 SetLastError( ERROR_NOACCESS );
1739 return FALSE;
1740 }
1741 *lpMsg = Conversion.AnsiMsg;
1742 Conversion.Ansi = TRUE;
1743 Conversion.FinalMsg = lpMsg;
1744 MsgConversionAdd(&Conversion);
1745 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
1746 {
1747 ThreadData->LastMessage = Info.Msg;
1748 }
1749
1750 return Res;
1751 }
1752
1753
1754 /*
1755 * @implemented
1756 */
1757 BOOL WINAPI
1758 GetMessageW(LPMSG lpMsg,
1759 HWND hWnd,
1760 UINT wMsgFilterMin,
1761 UINT wMsgFilterMax)
1762 {
1763 BOOL Res;
1764 MSGCONVERSION Conversion;
1765 NTUSERGETMESSAGEINFO Info;
1766 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
1767
1768 MsgConversionCleanup(lpMsg, FALSE, FALSE, NULL);
1769 Res = NtUserGetMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax);
1770 if (-1 == (int) Res)
1771 {
1772 return Res;
1773 }
1774 Conversion.LParamSize = Info.LParamSize;
1775 Conversion.KMMsg = Info.Msg;
1776
1777 if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg))
1778 {
1779 return (BOOL) -1;
1780 }
1781 if (!lpMsg)
1782 {
1783 SetLastError( ERROR_NOACCESS );
1784 return FALSE;
1785 }
1786 *lpMsg = Conversion.UnicodeMsg;
1787 Conversion.Ansi = FALSE;
1788 Conversion.FinalMsg = lpMsg;
1789 MsgConversionAdd(&Conversion);
1790 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
1791 {
1792 ThreadData->LastMessage = Info.Msg;
1793 }
1794
1795 return Res;
1796 }
1797
1798
1799 /*
1800 * @implemented
1801 */
1802 BOOL WINAPI
1803 PeekMessageA(LPMSG lpMsg,
1804 HWND hWnd,
1805 UINT wMsgFilterMin,
1806 UINT wMsgFilterMax,
1807 UINT wRemoveMsg)
1808 {
1809 BOOL Res;
1810 MSGCONVERSION Conversion;
1811 NTUSERGETMESSAGEINFO Info;
1812 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
1813
1814 MsgConversionCleanup(lpMsg, TRUE, FALSE, NULL);
1815 Res = NtUserPeekMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
1816 if (-1 == (int) Res || !Res)
1817 {
1818 return FALSE;
1819 }
1820 Conversion.LParamSize = Info.LParamSize;
1821 Conversion.KMMsg = Info.Msg;
1822
1823 if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg))
1824 {
1825 return FALSE;
1826 }
1827 if (! MsgiUnicodeToAnsiMessage(&Conversion.AnsiMsg, &Conversion.UnicodeMsg))
1828 {
1829 MsgiKMToUMCleanup(&Info.Msg, &Conversion.UnicodeMsg);
1830 return FALSE;
1831 }
1832 if (!lpMsg)
1833 {
1834 SetLastError( ERROR_NOACCESS );
1835 return FALSE;
1836 }
1837 *lpMsg = Conversion.AnsiMsg;
1838 Conversion.Ansi = TRUE;
1839 Conversion.FinalMsg = lpMsg;
1840 MsgConversionAdd(&Conversion);
1841 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
1842 {
1843 ThreadData->LastMessage = Info.Msg;
1844 }
1845
1846 return Res;
1847 }
1848
1849
1850 /*
1851 * @implemented
1852 */
1853 BOOL
1854 WINAPI
1855 PeekMessageW(
1856 LPMSG lpMsg,
1857 HWND hWnd,
1858 UINT wMsgFilterMin,
1859 UINT wMsgFilterMax,
1860 UINT wRemoveMsg)
1861 {
1862 BOOL Res;
1863 MSGCONVERSION Conversion;
1864 NTUSERGETMESSAGEINFO Info;
1865 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
1866
1867 MsgConversionCleanup(lpMsg, FALSE, FALSE, NULL);
1868 Res = NtUserPeekMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
1869 if (-1 == (int) Res || !Res)
1870 {
1871 return FALSE;
1872 }
1873 Conversion.LParamSize = Info.LParamSize;
1874 Conversion.KMMsg = Info.Msg;
1875
1876 if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg))
1877 {
1878 return FALSE;
1879 }
1880 if (!lpMsg)
1881 {
1882 SetLastError( ERROR_NOACCESS );
1883 return FALSE;
1884 }
1885 *lpMsg = Conversion.UnicodeMsg;
1886 Conversion.Ansi = FALSE;
1887 Conversion.FinalMsg = lpMsg;
1888 MsgConversionAdd(&Conversion);
1889 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
1890 {
1891 ThreadData->LastMessage = Info.Msg;
1892 }
1893
1894 return Res;
1895 }
1896
1897 //
1898 // Worker function for post message.
1899 //
1900 BOOL
1901 FASTCALL
1902 PostMessageWorker(
1903 HWND Wnd,
1904 UINT Msg,
1905 WPARAM wParam,
1906 LPARAM lParam)
1907 {
1908 MSG UMMsg, KMMsg;
1909 LRESULT Result;
1910
1911 UMMsg.hwnd = Wnd;
1912 UMMsg.message = Msg;
1913 UMMsg.wParam = wParam;
1914 UMMsg.lParam = lParam;
1915 if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, TRUE))
1916 {
1917 return FALSE;
1918 }
1919 Result = NtUserPostMessage( Wnd,
1920 KMMsg.message,
1921 KMMsg.wParam,
1922 KMMsg.lParam);
1923
1924 MsgiUMToKMCleanup(&UMMsg, &KMMsg);
1925
1926 return Result;
1927 }
1928
1929 /*
1930 * @implemented
1931 */
1932 BOOL
1933 WINAPI
1934 PostMessageA(
1935 HWND hWnd,
1936 UINT Msg,
1937 WPARAM wParam,
1938 LPARAM lParam)
1939 {
1940 MSG AnsiMsg, UcMsg;
1941 BOOL Ret;
1942
1943 AnsiMsg.hwnd = hWnd;
1944 AnsiMsg.message = Msg;
1945 AnsiMsg.wParam = wParam;
1946 AnsiMsg.lParam = lParam;
1947
1948 if (!MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg))
1949 {
1950 return FALSE;
1951 }
1952
1953 Ret = PostMessageW( hWnd, UcMsg.message, UcMsg.wParam, UcMsg.lParam);
1954
1955 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
1956
1957 return Ret;
1958 }
1959
1960 /*
1961 * @implemented
1962 */
1963 BOOL
1964 WINAPI
1965 PostMessageW(
1966 HWND hWnd,
1967 UINT Msg,
1968 WPARAM wParam,
1969 LPARAM lParam)
1970 {
1971 LRESULT Ret;
1972
1973 /* Check for combo box or a list box to send names. */
1974 if (Msg == CB_DIR || Msg == LB_DIR)
1975 {
1976 /*
1977 Set DDL_POSTMSGS, so use the PostMessage function to send messages to the
1978 combo/list box. Forces a call like DlgDirListComboBox.
1979 */
1980 wParam |= DDL_POSTMSGS;
1981 return PostMessageWorker(hWnd, Msg, wParam, lParam);
1982 }
1983
1984 /* No drop files or current Process, just post message. */
1985 if ( (Msg != WM_DROPFILES) ||
1986 ( NtUserQueryWindow( hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID) ==
1987 PtrToUint(NtCurrentTeb()->ClientId.UniqueProcess) ) )
1988 {
1989 return PostMessageWorker(hWnd, Msg, wParam, lParam);
1990 }
1991
1992 /* We have drop files and this is not the same process for this window. */
1993
1994 /* Just incase, check wParam for Global memory handle and send size. */
1995 Ret = SendMessageW( hWnd,
1996 WM_COPYGLOBALDATA,
1997 (WPARAM)GlobalSize((HGLOBAL)wParam), // Zero if not a handle.
1998 (LPARAM)wParam); // Send wParam as lParam.
1999
2000 if ( Ret ) return PostMessageWorker(hWnd, Msg, (WPARAM)Ret, lParam);
2001
2002 return FALSE;
2003 }
2004
2005 /*
2006 * @implemented
2007 */
2008 VOID
2009 WINAPI
2010 PostQuitMessage(
2011 int nExitCode)
2012 {
2013 NtUserCallOneParam(nExitCode, ONEPARAM_ROUTINE_POSTQUITMESSAGE);
2014 }
2015
2016
2017 /*
2018 * @implemented
2019 */
2020 BOOL
2021 WINAPI
2022 PostThreadMessageA(
2023 DWORD idThread,
2024 UINT Msg,
2025 WPARAM wParam,
2026 LPARAM lParam)
2027 {
2028 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
2029 }
2030
2031
2032 /*
2033 * @implemented
2034 */
2035 BOOL
2036 WINAPI
2037 PostThreadMessageW(
2038 DWORD idThread,
2039 UINT Msg,
2040 WPARAM wParam,
2041 LPARAM lParam)
2042 {
2043 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
2044 }
2045
2046
2047 /*
2048 * @implemented
2049 */
2050 LRESULT WINAPI
2051 SendMessageW(HWND Wnd,
2052 UINT Msg,
2053 WPARAM wParam,
2054 LPARAM lParam)
2055 {
2056 MSG UMMsg, KMMsg;
2057 NTUSERSENDMESSAGEINFO Info;
2058 LRESULT Result;
2059 PWND Window;
2060 PTHREADINFO ti = GetW32ThreadInfo();
2061
2062 Window = ValidateHwnd(Wnd);
2063 if (!Window) return FALSE;
2064
2065 if (Wnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2066 {
2067 if (Window != NULL && Window->head.pti == ti && !IsThreadHooked(GetWin32ClientInfo()))
2068 {
2069 /* NOTE: We can directly send messages to the window procedure
2070 if *all* the following conditions are met:
2071
2072 * Window belongs to calling thread
2073 * The calling thread is not being hooked
2074 */
2075
2076 return IntCallMessageProc(Window, Wnd, Msg, wParam, lParam, FALSE);
2077 }
2078 }
2079
2080 UMMsg.hwnd = Wnd;
2081 UMMsg.message = Msg;
2082 UMMsg.wParam = wParam;
2083 UMMsg.lParam = lParam;
2084 if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, FALSE))
2085 {
2086 return FALSE;
2087 }
2088 Info.Ansi = FALSE;
2089 Result = NtUserSendMessage( KMMsg.hwnd,
2090 KMMsg.message,
2091 KMMsg.wParam,
2092 KMMsg.lParam,
2093 &Info);
2094 if (! Info.HandledByKernel)
2095 {
2096 MsgiUMToKMCleanup(&UMMsg, &KMMsg);
2097 /* We need to send the message ourselves */
2098 Result = IntCallWindowProcW( Info.Ansi,
2099 Info.Proc,
2100 Window,
2101 UMMsg.hwnd,
2102 UMMsg.message,
2103 UMMsg.wParam,
2104 UMMsg.lParam);
2105 }
2106 else if (! MsgiUMToKMReply(&UMMsg, &KMMsg, &Result))
2107 {
2108 return FALSE;
2109 }
2110
2111 return Result;
2112 }
2113
2114
2115 /*
2116 * @implemented
2117 */
2118 LRESULT WINAPI
2119 SendMessageA(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
2120 {
2121 MSG AnsiMsg, UcMsg;
2122 MSG KMMsg;
2123 LRESULT Result;
2124 NTUSERSENDMESSAGEINFO Info;
2125 PWND Window;
2126 PTHREADINFO ti = GetW32ThreadInfo();
2127
2128 Window = ValidateHwnd(Wnd);
2129 if (!Window) return FALSE;
2130
2131 if (Wnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2132 {
2133 if (Window != NULL && Window->head.pti == ti && !IsThreadHooked(GetWin32ClientInfo()))
2134 {
2135 /* NOTE: We can directly send messages to the window procedure
2136 if *all* the following conditions are met:
2137
2138 * Window belongs to calling thread
2139 * The calling thread is not being hooked
2140 */
2141
2142 return IntCallMessageProc(Window, Wnd, Msg, wParam, lParam, TRUE);
2143 }
2144 }
2145
2146 AnsiMsg.hwnd = Wnd;
2147 AnsiMsg.message = Msg;
2148 AnsiMsg.wParam = wParam;
2149 AnsiMsg.lParam = lParam;
2150 if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg))
2151 {
2152 return FALSE;
2153 }
2154
2155 if (! MsgiUMToKMMessage(&UcMsg, &KMMsg, FALSE))
2156 {
2157 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2158 return FALSE;
2159 }
2160 Info.Ansi = TRUE;
2161 Result = NtUserSendMessage( KMMsg.hwnd,
2162 KMMsg.message,
2163 KMMsg.wParam,
2164 KMMsg.lParam,
2165 &Info);
2166 if (! Info.HandledByKernel)
2167 {
2168 /* We need to send the message ourselves */
2169 if (Info.Ansi)
2170 {
2171 /* Ansi message and Ansi window proc, that's easy. Clean up
2172 the Unicode message though */
2173 MsgiUMToKMCleanup(&UcMsg, &KMMsg);
2174 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2175 Result = IntCallWindowProcA(Info.Ansi, Info.Proc, Window, Wnd, Msg, wParam, lParam);
2176 }
2177 else
2178 {
2179 /* Unicode winproc. Although we started out with an Ansi message we
2180 already converted it to Unicode for the kernel call. Reuse that
2181 message to avoid another conversion */
2182 Result = IntCallWindowProcW( Info.Ansi,
2183 Info.Proc,
2184 Window,
2185 UcMsg.hwnd,
2186 UcMsg.message,
2187 UcMsg.wParam,
2188 UcMsg.lParam);
2189 if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
2190 {
2191 return FALSE;
2192 }
2193 }
2194 }
2195 /* Message sent by kernel. Convert back to Ansi */
2196 else if (! MsgiUMToKMReply(&UcMsg, &KMMsg, &Result) ||
2197 ! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
2198 {
2199 return FALSE;
2200 }
2201
2202 return Result;
2203 }
2204
2205 /*
2206 * @implemented
2207 */
2208 BOOL
2209 WINAPI
2210 SendMessageCallbackA(
2211 HWND hWnd,
2212 UINT Msg,
2213 WPARAM wParam,
2214 LPARAM lParam,
2215 SENDASYNCPROC lpCallBack,
2216 ULONG_PTR dwData)
2217 {
2218 CALL_BACK_INFO CallBackInfo;
2219
2220 CallBackInfo.CallBack = lpCallBack;
2221 CallBackInfo.Context = dwData;
2222
2223 return NtUserMessageCall(hWnd,
2224 Msg,
2225 wParam,
2226 lParam,
2227 (ULONG_PTR)&CallBackInfo,
2228 FNID_SENDMESSAGECALLBACK,
2229 TRUE);
2230 }
2231
2232 /*
2233 * @implemented
2234 */
2235 BOOL
2236 WINAPI
2237 SendMessageCallbackW(
2238 HWND hWnd,
2239 UINT Msg,
2240 WPARAM wParam,
2241 LPARAM lParam,
2242 SENDASYNCPROC lpCallBack,
2243 ULONG_PTR dwData)
2244 {
2245
2246 CALL_BACK_INFO CallBackInfo;
2247
2248 CallBackInfo.CallBack = lpCallBack;
2249 CallBackInfo.Context = dwData;
2250
2251 return NtUserMessageCall(hWnd,
2252 Msg,
2253 wParam,
2254 lParam,
2255 (ULONG_PTR)&CallBackInfo,
2256 FNID_SENDMESSAGECALLBACK,
2257 FALSE);
2258 }
2259
2260 /*
2261 * @implemented
2262 */
2263 LRESULT
2264 WINAPI
2265 SendMessageTimeoutA(
2266 HWND hWnd,
2267 UINT Msg,
2268 WPARAM wParam,
2269 LPARAM lParam,
2270 UINT fuFlags,
2271 UINT uTimeout,
2272 PDWORD_PTR lpdwResult)
2273 {
2274 MSG AnsiMsg;
2275 MSG UcMsg;
2276 LRESULT Result;
2277 NTUSERSENDMESSAGEINFO Info;
2278
2279 AnsiMsg.hwnd = hWnd;
2280 AnsiMsg.message = Msg;
2281 AnsiMsg.wParam = wParam;
2282 AnsiMsg.lParam = lParam;
2283 if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg))
2284 {
2285 return FALSE;
2286 }
2287
2288 SPY_EnterMessage(SPY_SENDMESSAGE, hWnd, Msg, wParam, lParam);
2289
2290 Info.Ansi = TRUE;
2291 Result = NtUserSendMessageTimeout(UcMsg.hwnd, UcMsg.message,
2292 UcMsg.wParam, UcMsg.lParam,
2293 fuFlags, uTimeout, (ULONG_PTR*)lpdwResult, &Info);
2294 if(!Result)
2295 {
2296 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2297 return FALSE;
2298 }
2299 if (! Info.HandledByKernel)
2300 {
2301 PWND pWnd;
2302 pWnd = ValidateHwnd(hWnd);
2303 /* We need to send the message ourselves */
2304 if (Info.Ansi)
2305 {
2306 /* Ansi message and Ansi window proc, that's easy. Clean up
2307 the Unicode message though */
2308 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2309 Result = IntCallWindowProcA(Info.Ansi, Info.Proc, pWnd, hWnd, Msg, wParam, lParam);
2310 }
2311 else
2312 {
2313 /* Unicode winproc. Although we started out with an Ansi message we
2314 already converted it to Unicode for the kernel call. Reuse that
2315 message to avoid another conversion */
2316 Result = IntCallWindowProcW( Info.Ansi,
2317 Info.Proc,
2318 pWnd,
2319 UcMsg.hwnd,
2320 UcMsg.message,
2321 UcMsg.wParam,
2322 UcMsg.lParam);
2323 if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
2324 {
2325 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2326 return FALSE;
2327 }
2328 }
2329 if(lpdwResult)
2330 *lpdwResult = Result;
2331 Result = TRUE;
2332 }
2333 else
2334 {
2335 /* Message sent by kernel. Convert back to Ansi */
2336 if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
2337 {
2338 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2339 return FALSE;
2340 }
2341 }
2342
2343 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2344 return Result;
2345 }
2346
2347
2348 /*
2349 * @implemented
2350 */
2351 LRESULT
2352 WINAPI
2353 SendMessageTimeoutW(
2354 HWND hWnd,
2355 UINT Msg,
2356 WPARAM wParam,
2357 LPARAM lParam,
2358 UINT fuFlags,
2359 UINT uTimeout,
2360 PDWORD_PTR lpdwResult)
2361 {
2362 NTUSERSENDMESSAGEINFO Info;
2363 LRESULT Result;
2364
2365 SPY_EnterMessage(SPY_SENDMESSAGE, hWnd, Msg, wParam, lParam);
2366
2367 Info.Ansi = FALSE;
2368 Result = NtUserSendMessageTimeout(hWnd, Msg, wParam, lParam, fuFlags, uTimeout,
2369 lpdwResult, &Info);
2370 if (! Info.HandledByKernel)
2371 {
2372 PWND pWnd;
2373 pWnd = ValidateHwnd(hWnd);
2374 /* We need to send the message ourselves */
2375 Result = IntCallWindowProcW(Info.Ansi, Info.Proc, pWnd, hWnd, Msg, wParam, lParam);
2376 if(lpdwResult)
2377 *lpdwResult = Result;
2378
2379 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2380 return TRUE;
2381 }
2382
2383 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2384 return Result;
2385 }
2386
2387 /*
2388 * @implemented
2389 */
2390 BOOL
2391 WINAPI
2392 SendNotifyMessageA(
2393 HWND hWnd,
2394 UINT Msg,
2395 WPARAM wParam,
2396 LPARAM lParam)
2397 {
2398 BOOL Ret;
2399 MSG AnsiMsg, UcMsg;
2400
2401 AnsiMsg.hwnd = hWnd;
2402 AnsiMsg.message = Msg;
2403 AnsiMsg.wParam = wParam;
2404 AnsiMsg.lParam = lParam;
2405 if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg))
2406 {
2407 return FALSE;
2408 }
2409 Ret = SendNotifyMessageW(hWnd, UcMsg.message, UcMsg.wParam, UcMsg.lParam);
2410
2411 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2412
2413 return Ret;
2414 }
2415
2416 /*
2417 * @implemented
2418 */
2419 BOOL
2420 WINAPI
2421 SendNotifyMessageW(
2422 HWND hWnd,
2423 UINT Msg,
2424 WPARAM wParam,
2425 LPARAM lParam)
2426 {
2427 MSG UMMsg, KMMsg;
2428 LRESULT Result;
2429
2430 UMMsg.hwnd = hWnd;
2431 UMMsg.message = Msg;
2432 UMMsg.wParam = wParam;
2433 UMMsg.lParam = lParam;
2434 if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, TRUE))
2435 {
2436 return FALSE;
2437 }
2438 Result = NtUserMessageCall( hWnd,
2439 KMMsg.message,
2440 KMMsg.wParam,
2441 KMMsg.lParam,
2442 0,
2443 FNID_SENDNOTIFYMESSAGE,
2444 FALSE);
2445
2446 MsgiUMToKMCleanup(&UMMsg, &KMMsg);
2447
2448 return Result;
2449 }
2450
2451 /*
2452 * @implemented
2453 */
2454 BOOL WINAPI
2455 TranslateMessageEx(CONST MSG *lpMsg, DWORD unk)
2456 {
2457 switch (lpMsg->message)
2458 {
2459 case WM_KEYDOWN:
2460 case WM_KEYUP:
2461 case WM_SYSKEYDOWN:
2462 case WM_SYSKEYUP:
2463 return(NtUserTranslateMessage((LPMSG)lpMsg, unk));
2464
2465 default:
2466 if ( lpMsg->message & ~WM_MAXIMUM )
2467 SetLastError(ERROR_INVALID_PARAMETER);
2468 return FALSE;
2469 }
2470 }
2471
2472
2473 /*
2474 * @implemented
2475 */
2476 BOOL WINAPI
2477 TranslateMessage(CONST MSG *lpMsg)
2478 {
2479 BOOL Ret = FALSE;
2480
2481 // Ref: msdn ImmGetVirtualKey:
2482 // http://msdn.microsoft.com/en-us/library/aa912145.aspx
2483 /*
2484 if ( (LOWORD(lpMsg->wParam) != VK_PROCESSKEY) ||
2485 !(Ret = IMM_ImmTranslateMessage( lpMsg->hwnd,
2486 lpMsg->message,
2487 lpMsg->wParam,
2488 lpMsg->lParam)) )*/
2489 {
2490 Ret = TranslateMessageEx((LPMSG)lpMsg, 0);
2491 }
2492 return Ret;
2493 }
2494
2495
2496 /*
2497 * @implemented
2498 */
2499 UINT WINAPI
2500 RegisterWindowMessageA(LPCSTR lpString)
2501 {
2502 UNICODE_STRING String;
2503 BOOLEAN Result;
2504 UINT Atom;
2505
2506 Result = RtlCreateUnicodeStringFromAsciiz(&String, (PCSZ)lpString);
2507 if (!Result)
2508 {
2509 return(0);
2510 }
2511 Atom = NtUserRegisterWindowMessage(&String);
2512 RtlFreeUnicodeString(&String);
2513 return(Atom);
2514 }
2515
2516
2517 /*
2518 * @implemented
2519 */
2520 UINT WINAPI
2521 RegisterWindowMessageW(LPCWSTR lpString)
2522 {
2523 UNICODE_STRING String;
2524
2525 RtlInitUnicodeString(&String, lpString);
2526 return(NtUserRegisterWindowMessage(&String));
2527 }
2528
2529 /*
2530 * @implemented
2531 */
2532 HWND WINAPI
2533 GetCapture(VOID)
2534 {
2535 return (HWND)NtUserGetThreadState(THREADSTATE_CAPTUREWINDOW);
2536 }
2537
2538 /*
2539 * @implemented
2540 */
2541 BOOL WINAPI
2542 ReleaseCapture(VOID)
2543 {
2544 NtUserSetCapture(NULL);
2545 return(TRUE);
2546 }
2547
2548
2549 /*
2550 * @implemented
2551 */
2552 DWORD
2553 WINAPI
2554 RealGetQueueStatus(UINT flags)
2555 {
2556 if (flags & ~(QS_SMRESULT|QS_ALLPOSTMESSAGE|QS_ALLINPUT))
2557 {
2558 SetLastError( ERROR_INVALID_FLAGS );
2559 return 0;
2560 }
2561 return NtUserCallOneParam(flags, ONEPARAM_ROUTINE_GETQUEUESTATUS);
2562 }
2563
2564
2565 /*
2566 * @implemented
2567 */
2568 BOOL WINAPI GetInputState(VOID)
2569 {
2570 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
2571
2572 if ((!pcti) || (pcti->fsChangeBits & (QS_KEY|QS_MOUSEBUTTON)))
2573 return (BOOL)NtUserGetThreadState(THREADSTATE_GETINPUTSTATE);
2574
2575 return FALSE;
2576 }
2577
2578
2579 NTSTATUS WINAPI
2580 User32CallWindowProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
2581 {
2582 PWINDOWPROC_CALLBACK_ARGUMENTS CallbackArgs;
2583 MSG KMMsg, UMMsg;
2584 PWND pWnd = NULL;
2585 PCLIENTINFO pci = GetWin32ClientInfo();
2586
2587 /* Make sure we don't try to access mem beyond what we were given */
2588 if (ArgumentLength < sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
2589 {
2590 return STATUS_INFO_LENGTH_MISMATCH;
2591 }
2592
2593 CallbackArgs = (PWINDOWPROC_CALLBACK_ARGUMENTS) Arguments;
2594 KMMsg.hwnd = CallbackArgs->Wnd;
2595 KMMsg.message = CallbackArgs->Msg;
2596 KMMsg.wParam = CallbackArgs->wParam;
2597 /* Check if lParam is really a pointer and adjust it if it is */
2598 if (0 <= CallbackArgs->lParamBufferSize)
2599 {
2600 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)
2601 + CallbackArgs->lParamBufferSize)
2602 {
2603 return STATUS_INFO_LENGTH_MISMATCH;
2604 }
2605 KMMsg.lParam = (LPARAM) ((char *) CallbackArgs + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS));
2606 }
2607 else
2608 {
2609 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
2610 {
2611 return STATUS_INFO_LENGTH_MISMATCH;
2612 }
2613 KMMsg.lParam = CallbackArgs->lParam;
2614 }
2615
2616 if (WM_NCCALCSIZE == CallbackArgs->Msg && CallbackArgs->wParam)
2617 {
2618 NCCALCSIZE_PARAMS *Params = (NCCALCSIZE_PARAMS *) KMMsg.lParam;
2619 Params->lppos = (PWINDOWPOS) (Params + 1);
2620 }
2621
2622 if (! MsgiKMToUMMessage(&KMMsg, &UMMsg))
2623 {
2624 }
2625
2626 if (pci->CallbackWnd.hWnd == UMMsg.hwnd)
2627 pWnd = pci->CallbackWnd.pvWnd;
2628
2629 CallbackArgs->Result = IntCallWindowProcW( CallbackArgs->IsAnsiProc,
2630 CallbackArgs->Proc,
2631 pWnd,
2632 UMMsg.hwnd,
2633 UMMsg.message,
2634 UMMsg.wParam,
2635 UMMsg.lParam);
2636
2637 if (! MsgiKMToUMReply(&KMMsg, &UMMsg, &CallbackArgs->Result))
2638 {
2639 }
2640
2641 return ZwCallbackReturn(CallbackArgs, ArgumentLength, STATUS_SUCCESS);
2642 }
2643
2644 /*
2645 * @implemented
2646 */
2647 BOOL WINAPI SetMessageQueue(int cMessagesMax)
2648 {
2649 /* Function does nothing on 32 bit windows */
2650 return TRUE;
2651 }
2652 typedef DWORD (WINAPI * RealGetQueueStatusProc)(UINT flags);
2653 typedef DWORD (WINAPI * RealMsgWaitForMultipleObjectsExProc)(DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags);
2654
2655 typedef struct _USER_MESSAGE_PUMP_ADDRESSES {
2656 DWORD cbSize;
2657 //NtUserRealInternalGetMessageProc NtUserRealInternalGetMessage;
2658 //NtUserRealWaitMessageExProc NtUserRealWaitMessageEx;
2659 RealGetQueueStatusProc RealGetQueueStatus;
2660 RealMsgWaitForMultipleObjectsExProc RealMsgWaitForMultipleObjectsEx;
2661 } USER_MESSAGE_PUMP_ADDRESSES, * PUSER_MESSAGE_PUMP_ADDRESSES;
2662
2663 DWORD
2664 WINAPI
2665 RealMsgWaitForMultipleObjectsEx(
2666 DWORD nCount,
2667 CONST HANDLE *pHandles,
2668 DWORD dwMilliseconds,
2669 DWORD dwWakeMask,
2670 DWORD dwFlags);
2671
2672 typedef BOOL (WINAPI * MESSAGEPUMPHOOKPROC)(BOOL Unregistering,PUSER_MESSAGE_PUMP_ADDRESSES MessagePumpAddresses);
2673
2674 CRITICAL_SECTION gcsMPH;
2675 MESSAGEPUMPHOOKPROC gpfnInitMPH;
2676 DWORD gcLoadMPH = 0;
2677 USER_MESSAGE_PUMP_ADDRESSES gmph = {sizeof(USER_MESSAGE_PUMP_ADDRESSES),
2678 //NtUserRealInternalGetMessage,
2679 //NtUserRealInternalWaitMessageEx,
2680 RealGetQueueStatus,
2681 RealMsgWaitForMultipleObjectsEx
2682 };
2683
2684 DWORD gfMessagePumpHook = 0;
2685
2686 BOOL WINAPI IsInsideMessagePumpHook()
2687 { // Fixme: Need to fully implement this! FF uses this and polls it when Min/Max
2688 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
2689 // FIXME("IIMPH %x\n",pcti);
2690 return (gfMessagePumpHook && pcti && (pcti->dwcPumpHook > 0));
2691 }
2692
2693 void WINAPI ResetMessagePumpHook(PUSER_MESSAGE_PUMP_ADDRESSES Addresses)
2694 {
2695 Addresses->cbSize = sizeof(USER_MESSAGE_PUMP_ADDRESSES);
2696 //Addresses->NtUserRealInternalGetMessage = (NtUserRealInternalGetMessageProc)NtUserRealInternalGetMessage;
2697 //Addresses->NtUserRealWaitMessageEx = (NtUserRealWaitMessageExProc)NtUserRealInternalWaitMessageEx;
2698 Addresses->RealGetQueueStatus = RealGetQueueStatus;
2699 Addresses->RealMsgWaitForMultipleObjectsEx = RealMsgWaitForMultipleObjectsEx;
2700 }
2701
2702 BOOL WINAPI RegisterMessagePumpHook(MESSAGEPUMPHOOKPROC Hook)
2703 {
2704 EnterCriticalSection(&gcsMPH);
2705 if(!Hook) {
2706 SetLastError(ERROR_INVALID_PARAMETER);
2707 LeaveCriticalSection(&gcsMPH);
2708 return FALSE;
2709 }
2710 if(!gcLoadMPH) {
2711 USER_MESSAGE_PUMP_ADDRESSES Addresses;
2712 gpfnInitMPH = Hook;
2713 ResetMessagePumpHook(&Addresses);
2714 if(!Hook(FALSE, &Addresses) || !Addresses.cbSize) {
2715 LeaveCriticalSection(&gcsMPH);
2716 return FALSE;
2717 }
2718 memcpy(&gmph, &Addresses, Addresses.cbSize);
2719 } else {
2720 if(gpfnInitMPH != Hook) {
2721 LeaveCriticalSection(&gcsMPH);
2722 return FALSE;
2723 }
2724 }
2725 if(NtUserCallNoParam(NOPARAM_ROUTINE_INIT_MESSAGE_PUMP)) {
2726 LeaveCriticalSection(&gcsMPH);
2727 return FALSE;
2728 }
2729 if (!gcLoadMPH++) {
2730 InterlockedExchange((PLONG)&gfMessagePumpHook, 1);
2731 }
2732 LeaveCriticalSection(&gcsMPH);
2733 return TRUE;
2734 }
2735
2736 BOOL WINAPI UnregisterMessagePumpHook(VOID)
2737 {
2738 EnterCriticalSection(&gcsMPH);
2739 if(gcLoadMPH > 0) {
2740 if(NtUserCallNoParam(NOPARAM_ROUTINE_UNINIT_MESSAGE_PUMP)) {
2741 gcLoadMPH--;
2742 if(!gcLoadMPH) {
2743 InterlockedExchange((PLONG)&gfMessagePumpHook, 0);
2744 gpfnInitMPH(TRUE, NULL);
2745 ResetMessagePumpHook(&gmph);
2746 gpfnInitMPH = 0;
2747 }
2748 LeaveCriticalSection(&gcsMPH);
2749 return TRUE;
2750 }
2751 }
2752 LeaveCriticalSection(&gcsMPH);
2753 return FALSE;
2754 }
2755
2756 DWORD WINAPI GetQueueStatus(UINT flags)
2757 {
2758 return IsInsideMessagePumpHook() ? gmph.RealGetQueueStatus(flags) : RealGetQueueStatus(flags);
2759 }
2760
2761 /**
2762 * @name RealMsgWaitForMultipleObjectsEx
2763 *
2764 * Wait either for either message arrival or for one of the passed events
2765 * to be signalled.
2766 *
2767 * @param nCount
2768 * Number of handles in the pHandles array.
2769 * @param pHandles
2770 * Handles of events to wait for.
2771 * @param dwMilliseconds
2772 * Timeout interval.
2773 * @param dwWakeMask
2774 * Mask specifying on which message events we should wakeup.
2775 * @param dwFlags
2776 * Wait type (see MWMO_* constants).
2777 *
2778 * @implemented
2779 */
2780
2781 DWORD WINAPI
2782 RealMsgWaitForMultipleObjectsEx(
2783 DWORD nCount,
2784 const HANDLE *pHandles,
2785 DWORD dwMilliseconds,
2786 DWORD dwWakeMask,
2787 DWORD dwFlags)
2788 {
2789 LPHANDLE RealHandles;
2790 HANDLE MessageQueueHandle;
2791 DWORD Result;
2792
2793 if (dwFlags & ~(MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE))
2794 {
2795 SetLastError(ERROR_INVALID_PARAMETER);
2796 return WAIT_FAILED;
2797 }
2798
2799 /*
2800 if (dwFlags & MWMO_INPUTAVAILABLE)
2801 {
2802 RealGetQueueStatus(dwWakeMask);
2803 }
2804 */
2805
2806 MessageQueueHandle = NtUserMsqSetWakeMask(dwWakeMask);
2807 if (MessageQueueHandle == NULL)
2808 {
2809 SetLastError(0); /* ? */
2810 return WAIT_FAILED;
2811 }
2812
2813 RealHandles = HeapAlloc(GetProcessHeap(), 0, (nCount + 1) * sizeof(HANDLE));
2814 if (RealHandles == NULL)
2815 {
2816 NtUserMsqClearWakeMask();
2817 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2818 return WAIT_FAILED;
2819 }
2820
2821 RtlCopyMemory(RealHandles, pHandles, nCount * sizeof(HANDLE));
2822 RealHandles[nCount] = MessageQueueHandle;
2823
2824 Result = WaitForMultipleObjectsEx(nCount + 1, RealHandles,
2825 dwFlags & MWMO_WAITALL,
2826 dwMilliseconds, dwFlags & MWMO_ALERTABLE);
2827
2828 HeapFree(GetProcessHeap(), 0, RealHandles);
2829 NtUserMsqClearWakeMask();
2830
2831 return Result;
2832 }
2833
2834 /*
2835 * @implemented
2836 */
2837 DWORD WINAPI
2838 MsgWaitForMultipleObjectsEx(
2839 DWORD nCount,
2840 CONST HANDLE *lpHandles,
2841 DWORD dwMilliseconds,
2842 DWORD dwWakeMask,
2843 DWORD dwFlags)
2844 {
2845 return IsInsideMessagePumpHook() ? gmph.RealMsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds, dwWakeMask, dwFlags) : RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags);
2846 }
2847
2848 /*
2849 * @implemented
2850 */
2851 DWORD WINAPI
2852 MsgWaitForMultipleObjects(
2853 DWORD nCount,
2854 CONST HANDLE *lpHandles,
2855 BOOL fWaitAll,
2856 DWORD dwMilliseconds,
2857 DWORD dwWakeMask)
2858 {
2859 return MsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds,
2860 dwWakeMask, fWaitAll ? MWMO_WAITALL : 0);
2861 }
2862
2863
2864 BOOL FASTCALL MessageInit(VOID)
2865 {
2866 InitializeCriticalSection(&DdeCrst);
2867 InitializeCriticalSection(&MsgConversionCrst);
2868 InitializeCriticalSection(&gcsMPH);
2869
2870 return TRUE;
2871 }
2872
2873 VOID FASTCALL MessageCleanup(VOID)
2874 {
2875 DeleteCriticalSection(&DdeCrst);
2876 DeleteCriticalSection(&MsgConversionCrst);
2877 DeleteCriticalSection(&gcsMPH);
2878 }
2879
2880 /***********************************************************************
2881 * map_wparam_AtoW
2882 *
2883 * Convert the wparam of an ASCII message to Unicode.
2884 */
2885 static WPARAM
2886 map_wparam_AtoW( UINT message, WPARAM wparam )
2887 {
2888 switch(message)
2889 {
2890 case WM_CHARTOITEM:
2891 case EM_SETPASSWORDCHAR:
2892 case WM_CHAR:
2893 case WM_DEADCHAR:
2894 case WM_SYSCHAR:
2895 case WM_SYSDEADCHAR:
2896 case WM_MENUCHAR:
2897 {
2898 char ch[2];
2899 WCHAR wch[2];
2900 ch[0] = (wparam & 0xff);
2901 ch[1] = (wparam >> 8);
2902 MultiByteToWideChar(CP_ACP, 0, ch, 2, wch, 2);
2903 wparam = MAKEWPARAM(wch[0], wch[1]);
2904 }
2905 break;
2906 case WM_IME_CHAR:
2907 {
2908 char ch[2];
2909 WCHAR wch;
2910 ch[0] = (wparam >> 8);
2911 ch[1] = (wparam & 0xff);
2912 if (ch[0]) MultiByteToWideChar(CP_ACP, 0, ch, 2, &wch, 1);
2913 else MultiByteToWideChar(CP_ACP, 0, &ch[1], 1, &wch, 1);
2914 wparam = MAKEWPARAM( wch, HIWORD(wparam) );
2915 }
2916 break;
2917 }
2918 return wparam;
2919 }
2920
2921 /*
2922 * @implemented
2923 */
2924 BOOL WINAPI
2925 IsDialogMessageA( HWND hwndDlg, LPMSG pmsg )
2926 {
2927 MSG msg = *pmsg;
2928 msg.wParam = map_wparam_AtoW( msg.message, msg.wParam );
2929 return IsDialogMessageW( hwndDlg, &msg );
2930 }
2931
2932 LONG
2933 WINAPI
2934 IntBroadcastSystemMessage(
2935 DWORD dwflags,
2936 LPDWORD lpdwRecipients,
2937 UINT uiMessage,
2938 WPARAM wParam,
2939 LPARAM lParam,
2940 PBSMINFO pBSMInfo,
2941 BOOL Ansi)
2942 {
2943 BROADCASTPARM parm;
2944 DWORD recips = BSM_ALLCOMPONENTS;
2945 BOOL ret = -1; // Set to return fail
2946 static const DWORD all_flags = ( BSF_QUERY | BSF_IGNORECURRENTTASK | BSF_FLUSHDISK | BSF_NOHANG
2947 | BSF_POSTMESSAGE | BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG
2948 | BSF_ALLOWSFW | BSF_SENDNOTIFYMESSAGE | BSF_RETURNHDESK | BSF_LUID );
2949
2950 if ((dwflags & ~all_flags) ||
2951 (!pBSMInfo && (dwflags & (BSF_RETURNHDESK|BSF_LUID))) )
2952 {
2953 SetLastError(ERROR_INVALID_PARAMETER);
2954 return 0;
2955 }
2956
2957 if(uiMessage >= WM_USER && uiMessage < 0xC000)
2958 {
2959 SetLastError(ERROR_INVALID_PARAMETER);
2960 return 0;
2961 }
2962
2963 if (dwflags & BSF_FORCEIFHUNG) dwflags |= BSF_NOHANG;
2964
2965 if (dwflags & BSF_QUERY) dwflags &= ~BSF_SENDNOTIFYMESSAGE|BSF_POSTMESSAGE;
2966
2967 if (!lpdwRecipients)
2968 lpdwRecipients = &recips;
2969
2970 if (*lpdwRecipients & ~(BSM_APPLICATIONS|BSM_ALLDESKTOPS|BSM_INSTALLABLEDRIVERS|BSM_NETDRIVER|BSM_VXDS))
2971 {
2972 SetLastError(ERROR_INVALID_PARAMETER);
2973 return 0;
2974 }
2975
2976 if ( pBSMInfo && (dwflags & BSF_QUERY) )
2977 {
2978 if (pBSMInfo->cbSize != sizeof(BSMINFO))
2979 {
2980 SetLastError(ERROR_INVALID_PARAMETER);
2981 return 0;
2982 }
2983 }
2984
2985 parm.hDesk = NULL;
2986 parm.hWnd = NULL;
2987 parm.flags = dwflags;
2988 parm.recipients = *lpdwRecipients;
2989
2990 if (dwflags & BSF_LUID) parm.luid = pBSMInfo->luid;
2991
2992 if (*lpdwRecipients & BSM_APPLICATIONS)
2993 {
2994 ret = NtUserMessageCall(GetDesktopWindow(),
2995 uiMessage,
2996 wParam,
2997 lParam,
2998 (ULONG_PTR)&parm,
2999 FNID_BROADCASTSYSTEMMESSAGE,
3000 Ansi);
3001 }
3002
3003 if (!ret)
3004 {
3005 if ( pBSMInfo && (dwflags & BSF_QUERY) )
3006 {
3007 pBSMInfo->hdesk = parm.hDesk;
3008 pBSMInfo->hwnd = parm.hWnd;
3009 }
3010 }
3011 return ret;
3012 }
3013
3014 /*
3015 * @implemented
3016 */
3017 LONG
3018 WINAPI
3019 BroadcastSystemMessageA(
3020 DWORD dwFlags,
3021 LPDWORD lpdwRecipients,
3022 UINT uiMessage,
3023 WPARAM wParam,
3024 LPARAM lParam)
3025 {
3026 return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, TRUE );
3027 }
3028
3029 /*
3030 * @implemented
3031 */
3032 LONG
3033 WINAPI
3034 BroadcastSystemMessageW(
3035 DWORD dwFlags,
3036 LPDWORD lpdwRecipients,
3037 UINT uiMessage,
3038 WPARAM wParam,
3039 LPARAM lParam)
3040 {
3041 return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, FALSE );
3042 }
3043
3044 /*
3045 * @implemented
3046 */
3047 LONG
3048 WINAPI
3049 BroadcastSystemMessageExA(
3050 DWORD dwflags,
3051 LPDWORD lpdwRecipients,
3052 UINT uiMessage,
3053 WPARAM wParam,
3054 LPARAM lParam,
3055 PBSMINFO pBSMInfo)
3056 {
3057 return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, TRUE );
3058 }
3059
3060 /*
3061 * @implemented
3062 */
3063 LONG
3064 WINAPI
3065 BroadcastSystemMessageExW(
3066 DWORD dwflags,
3067 LPDWORD lpdwRecipients,
3068 UINT uiMessage,
3069 WPARAM wParam,
3070 LPARAM lParam,
3071 PBSMINFO pBSMInfo)
3072 {
3073 return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, FALSE );
3074 }
3075