fixes from Wine.
[reactos.git] / reactos / lib / 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 #define NDEBUG
13 #include <debug.h>
14
15 /* DDE message exchange
16 *
17 * - Session initialization
18 * Client sends a WM_DDE_INITIATE message, usually a broadcast message. lParam of
19 * this message contains a pair of global atoms, the Application and Topic atoms.
20 * The client must destroy the atoms.
21 * Server window proc handles the WM_DDE_INITIATE message and if the Application
22 * and Topic atoms are recognized sends a WM_DDE_ACK message to the client. lParam
23 * of the reply message contains another pair of global atoms (Application and
24 * Topic again), which must be destroyed by the server.
25 *
26 * - Execute
27 * Client posts a WM_DDE_EXECUTE message to the server window. lParam of that message
28 * is a global memory handle containing the string to execute. After the command has
29 * been executed the server posts a WM_DDE_ACK message to the client, which contains
30 * a packed lParam which in turn contains that global memory handle. The client takes
31 * ownership of both the packed lParam (meaning it needs to call FreeDDElParam() on
32 * it and the global memory handle.
33 * This might work nice and easy in Win3.1, but things are more complicated for NT.
34 * Global memory handles in NT are not really global, they're still local to the
35 * process. So, what happens under the hood is that PostMessage must handle the
36 * WM_DDE_EXECUTE message specially. It will obtain the contents of the global memory
37 * area, repack that into a new structure together with the original memory handle
38 * and pass that off to the win32k. Win32k will marshall that data over to the target
39 * (server) process where it will be unpacked and stored in a newly allocated global
40 * memory area. The handle of that area will then be sent to the window proc, after
41 * storing it together with the "original" (client) handle in a table.
42 * The server will eventually post the WM_DDE_ACK response, containing the global
43 * memory handle it received. PostMessage must then lookup that memory handle (only
44 * valid in the server process) and replace it with the corresponding client memory
45 * handle. To avoid memory leaks, the server-side global memory block must be freed.
46 * Also, the WM_DDE_ACK lParam (a PackDDElParam() result) is unpacked and the
47 * individual components are handed to win32k.sys to post to the client side. Since
48 * the server side app hands over ownership of the packed lParam when it calls
49 * PostMessage(), the packed lParam needs to be freed on the server side too.
50 * When the WM_DDE_ACK message (containing the client-side global memory handle)
51 * arrives at the client side a new lParam is PackDDElParam()'ed and this is handed
52 * to the client side window proc which is expected to free/reuse it.
53 */
54
55 /* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
56 * to the memory handle, we keep track (in the server side) of all pairs of handle
57 * used (the client passes its value and the content of the memory handle), and
58 * the server stored both values (the client, and the local one, created after the
59 * content). When a ACK message is generated, the list of pair is searched for a
60 * matching pair, so that the client memory handle can be returned.
61 */
62 typedef struct tagDDEPAIR
63 {
64 HGLOBAL ClientMem;
65 HGLOBAL ServerMem;
66 } DDEPAIR, *PDDEPAIR;
67
68 static PDDEPAIR DdePairs = NULL;
69 static unsigned DdeNumAlloc = 0;
70 static unsigned DdeNumUsed = 0;
71 static CRITICAL_SECTION DdeCrst;
72
73 static BOOL FASTCALL
74 DdeAddPair(HGLOBAL ClientMem, HGLOBAL ServerMem)
75 {
76 unsigned i;
77
78 EnterCriticalSection(&DdeCrst);
79
80 /* now remember the pair of hMem on both sides */
81 if (DdeNumUsed == DdeNumAlloc)
82 {
83 #define GROWBY 4
84 PDDEPAIR New;
85 if (NULL != DdePairs)
86 {
87 New = HeapReAlloc(GetProcessHeap(), 0, DdePairs,
88 (DdeNumAlloc + GROWBY) * sizeof(DDEPAIR));
89 }
90 else
91 {
92 New = HeapAlloc(GetProcessHeap(), 0,
93 (DdeNumAlloc + GROWBY) * sizeof(DDEPAIR));
94 }
95
96 if (NULL == New)
97 {
98 LeaveCriticalSection(&DdeCrst);
99 return FALSE;
100 }
101 DdePairs = New;
102 /* zero out newly allocated part */
103 memset(&DdePairs[DdeNumAlloc], 0, GROWBY * sizeof(DDEPAIR));
104 DdeNumAlloc += GROWBY;
105 #undef GROWBY
106 }
107
108 for (i = 0; i < DdeNumAlloc; i++)
109 {
110 if (NULL == DdePairs[i].ServerMem)
111 {
112 DdePairs[i].ClientMem = ClientMem;
113 DdePairs[i].ServerMem = ServerMem;
114 DdeNumUsed++;
115 break;
116 }
117 }
118 LeaveCriticalSection(&DdeCrst);
119
120 return TRUE;
121 }
122
123 static HGLOBAL FASTCALL
124 DdeGetPair(HGLOBAL ServerMem)
125 {
126 unsigned i;
127 HGLOBAL Ret = NULL;
128
129 EnterCriticalSection(&DdeCrst);
130 for (i = 0; i < DdeNumAlloc; i++)
131 {
132 if (DdePairs[i].ServerMem == ServerMem)
133 {
134 /* free this pair */
135 DdePairs[i].ServerMem = 0;
136 DdeNumUsed--;
137 Ret = DdePairs[i].ClientMem;
138 break;
139 }
140 }
141 LeaveCriticalSection(&DdeCrst);
142
143 return Ret;
144 }
145
146 static BOOL FASTCALL
147 MsgiUMToKMMessage(PMSG UMMsg, PMSG KMMsg, BOOL Posted)
148 {
149 *KMMsg = *UMMsg;
150
151 switch (UMMsg->message)
152 {
153 case WM_DDE_ACK:
154 {
155 PKMDDELPARAM DdeLparam;
156 DdeLparam = HeapAlloc(GetProcessHeap(), 0, sizeof(KMDDELPARAM));
157 if (NULL == DdeLparam)
158 {
159 return FALSE;
160 }
161 if (Posted)
162 {
163 DdeLparam->Packed = TRUE;
164 if (! UnpackDDElParam(UMMsg->message, UMMsg->lParam,
165 &DdeLparam->Value.Packed.uiLo,
166 &DdeLparam->Value.Packed.uiHi))
167 {
168 return FALSE;
169 }
170 if (0 != HIWORD(DdeLparam->Value.Packed.uiHi))
171 {
172 /* uiHi should contain a hMem from WM_DDE_EXECUTE */
173 HGLOBAL h = DdeGetPair((HGLOBAL) DdeLparam->Value.Packed.uiHi);
174 if (NULL != h)
175 {
176 GlobalFree((HGLOBAL) DdeLparam->Value.Packed.uiHi);
177 DdeLparam->Value.Packed.uiHi = (UINT) h;
178 }
179 }
180 FreeDDElParam(UMMsg->message, UMMsg->lParam);
181 }
182 else
183 {
184 DdeLparam->Packed = FALSE;
185 DdeLparam->Value.Unpacked = UMMsg->lParam;
186 }
187 KMMsg->lParam = (LPARAM) DdeLparam;
188 }
189 break;
190
191 case WM_DDE_EXECUTE:
192 {
193 SIZE_T Size;
194 PKMDDEEXECUTEDATA KMDdeExecuteData;
195 PVOID Data;
196
197 Size = GlobalSize((HGLOBAL) UMMsg->lParam);
198 Data = GlobalLock((HGLOBAL) UMMsg->lParam);
199 if (NULL == Data)
200 {
201 SetLastError(ERROR_INVALID_HANDLE);
202 return FALSE;
203 }
204 KMDdeExecuteData = HeapAlloc(GetProcessHeap(), 0, sizeof(KMDDEEXECUTEDATA) + Size);
205 if (NULL == KMDdeExecuteData)
206 {
207 SetLastError(ERROR_OUTOFMEMORY);
208 return FALSE;
209 }
210 KMDdeExecuteData->Sender = (HWND) UMMsg->wParam;
211 KMDdeExecuteData->ClientMem = (HGLOBAL) UMMsg->lParam;
212 memcpy((PVOID) (KMDdeExecuteData + 1), Data, Size);
213 KMMsg->wParam = sizeof(KMDDEEXECUTEDATA) + Size;
214 KMMsg->lParam = (LPARAM) KMDdeExecuteData;
215 GlobalUnlock((HGLOBAL) UMMsg->lParam);
216 }
217 break;
218
219 case WM_COPYDATA:
220 {
221 PCOPYDATASTRUCT pUMCopyData = (PCOPYDATASTRUCT)UMMsg->lParam;
222 PCOPYDATASTRUCT pKMCopyData;
223
224 pKMCopyData = HeapAlloc(GetProcessHeap(), 0,
225 sizeof(COPYDATASTRUCT) + pUMCopyData->cbData);
226 if (pKMCopyData == NULL)
227 {
228 SetLastError(ERROR_OUTOFMEMORY);
229 return FALSE;
230 }
231
232 pKMCopyData->dwData = pUMCopyData->dwData;
233 pKMCopyData->cbData = pUMCopyData->cbData;
234 pKMCopyData->lpData = pKMCopyData + 1;
235
236 RtlCopyMemory(pKMCopyData + 1, pUMCopyData->lpData,
237 pUMCopyData->cbData);
238
239 KMMsg->lParam = (LPARAM)pKMCopyData;
240 }
241 break;
242
243 default:
244 break;
245 }
246
247 return TRUE;
248 }
249
250 static VOID FASTCALL
251 MsgiUMToKMCleanup(PMSG UMMsg, PMSG KMMsg)
252 {
253 switch (KMMsg->message)
254 {
255 case WM_DDE_ACK:
256 case WM_DDE_EXECUTE:
257 case WM_COPYDATA:
258 HeapFree(GetProcessHeap(), 0, (LPVOID) KMMsg->lParam);
259 break;
260 default:
261 break;
262 }
263
264 return;
265 }
266
267 static BOOL FASTCALL
268 MsgiUMToKMReply(PMSG UMMsg, PMSG KMMsg, LRESULT *Result)
269 {
270 MsgiUMToKMCleanup(UMMsg, KMMsg);
271
272 return TRUE;
273 }
274
275 static BOOL FASTCALL
276 MsgiKMToUMMessage(PMSG KMMsg, PMSG UMMsg)
277 {
278 *UMMsg = *KMMsg;
279
280 switch (UMMsg->message)
281 {
282 case WM_CREATE:
283 case WM_NCCREATE:
284 {
285 CREATESTRUCTW *Cs = (CREATESTRUCTW *) KMMsg->lParam;
286 PCHAR Class;
287 Cs->lpszName = (LPCWSTR) ((PCHAR) Cs + (DWORD_PTR) Cs->lpszName);
288 Class = (PCHAR) Cs + (DWORD_PTR) Cs->lpszClass;
289 if (L'A' == *((WCHAR *) Class))
290 {
291 Class += sizeof(WCHAR);
292 Cs->lpszClass = (LPCWSTR)(DWORD_PTR) (*((ATOM *) Class));
293 }
294 else
295 {
296 ASSERT(L'S' == *((WCHAR *) Class));
297 Class += sizeof(WCHAR);
298 Cs->lpszClass = (LPCWSTR) Class;
299 }
300 }
301 break;
302
303 case WM_DDE_ACK:
304 {
305 PKMDDELPARAM DdeLparam = (PKMDDELPARAM) KMMsg->lParam;
306 if (DdeLparam->Packed)
307 {
308 UMMsg->lParam = PackDDElParam(KMMsg->message,
309 DdeLparam->Value.Packed.uiLo,
310 DdeLparam->Value.Packed.uiHi);
311 }
312 else
313 {
314 UMMsg->lParam = DdeLparam->Value.Unpacked;
315 }
316 }
317 break;
318
319 case WM_DDE_EXECUTE:
320 {
321 PKMDDEEXECUTEDATA KMDdeExecuteData;
322 HGLOBAL GlobalData;
323 PVOID Data;
324
325 KMDdeExecuteData = (PKMDDEEXECUTEDATA) KMMsg->lParam;
326 GlobalData = GlobalAlloc(GMEM_MOVEABLE, KMMsg->wParam - sizeof(KMDDEEXECUTEDATA));
327 if (NULL == GlobalData)
328 {
329 return FALSE;
330 }
331 Data = GlobalLock(GlobalData);
332 if (NULL == Data)
333 {
334 GlobalFree(GlobalData);
335 return FALSE;
336 }
337 memcpy(Data, (PVOID) (KMDdeExecuteData + 1), KMMsg->wParam - sizeof(KMDDEEXECUTEDATA));
338 GlobalUnlock(GlobalData);
339 if (! DdeAddPair(KMDdeExecuteData->ClientMem, GlobalData))
340 {
341 GlobalFree(GlobalData);
342 return FALSE;
343 }
344 UMMsg->wParam = (WPARAM) KMDdeExecuteData->Sender;
345 UMMsg->lParam = (LPARAM) GlobalData;
346 }
347 break;
348
349 case WM_COPYDATA:
350 {
351 PCOPYDATASTRUCT pKMCopyData = (PCOPYDATASTRUCT)KMMsg->lParam;
352 pKMCopyData->lpData = pKMCopyData + 1;
353 }
354 break;
355
356 default:
357 break;
358 }
359
360 return TRUE;
361 }
362
363 static VOID FASTCALL
364 MsgiKMToUMCleanup(PMSG KMMsg, PMSG UMMsg)
365 {
366 switch (KMMsg->message)
367 {
368 case WM_DDE_EXECUTE:
369 #ifdef TODO
370 HeapFree(GetProcessHeap(), 0, (LPVOID) KMMsg->lParam);
371 GlobalUnlock((HGLOBAL) UMMsg->lParam);
372 #endif
373 break;
374 default:
375 break;
376 }
377
378 return;
379 }
380
381 static BOOL FASTCALL
382 MsgiKMToUMReply(PMSG KMMsg, PMSG UMMsg, LRESULT *Result)
383 {
384 MsgiKMToUMCleanup(KMMsg, UMMsg);
385
386 return TRUE;
387 }
388
389 static BOOL FASTCALL
390 MsgiAnsiToUnicodeMessage(LPMSG UnicodeMsg, LPMSG AnsiMsg)
391 {
392 *UnicodeMsg = *AnsiMsg;
393 switch (AnsiMsg->message)
394 {
395 case WM_GETTEXT:
396 case WM_ASKCBFORMATNAME:
397 {
398 LPWSTR Buffer = HeapAlloc(GetProcessHeap(), 0,
399 AnsiMsg->wParam * sizeof(WCHAR));
400 if (!Buffer)
401 {
402 return FALSE;
403 }
404 UnicodeMsg->lParam = (LPARAM)Buffer;
405 break;
406 }
407
408 /* AnsiMsg->lParam is string (0-terminated) */
409 case WM_SETTEXT:
410 case WM_WININICHANGE:
411 case WM_DEVMODECHANGE:
412 case CB_DIR:
413 case LB_DIR:
414 case LB_ADDFILE:
415 case EM_REPLACESEL:
416 {
417 UNICODE_STRING UnicodeString;
418 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam);
419 UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer;
420 break;
421 }
422
423 case WM_NCCREATE:
424 case WM_CREATE:
425 {
426 UNICODE_STRING UnicodeBuffer;
427 struct s
428 {
429 CREATESTRUCTW cs; /* new structure */
430 LPCWSTR lpszName; /* allocated Name */
431 LPCWSTR lpszClass; /* allocated Class */
432 };
433 struct s *xs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct s));
434 if (!xs)
435 {
436 return FALSE;
437 }
438 xs->cs = *(CREATESTRUCTW *)AnsiMsg->lParam;
439 if (HIWORD(xs->cs.lpszName))
440 {
441 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)xs->cs.lpszName);
442 xs->lpszName = xs->cs.lpszName = UnicodeBuffer.Buffer;
443 }
444 if (HIWORD(xs->cs.lpszClass))
445 {
446 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)xs->cs.lpszClass);
447 xs->lpszClass = xs->cs.lpszClass = UnicodeBuffer.Buffer;
448 }
449 UnicodeMsg->lParam = (LPARAM)xs;
450 break;
451 }
452
453 case WM_MDICREATE:
454 {
455 UNICODE_STRING UnicodeBuffer;
456 MDICREATESTRUCTW *cs =
457 (MDICREATESTRUCTW *)HeapAlloc(GetProcessHeap(), 0, sizeof(*cs));
458
459 if (!cs)
460 {
461 return FALSE;
462 }
463
464 *cs = *(MDICREATESTRUCTW *)AnsiMsg->lParam;
465
466 if (HIWORD(cs->szClass))
467 {
468 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)cs->szClass);
469 cs->szClass = UnicodeBuffer.Buffer;
470 }
471
472 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)cs->szTitle);
473 cs->szTitle = UnicodeBuffer.Buffer;
474
475 UnicodeMsg->lParam = (LPARAM)cs;
476 break;
477 }
478 }
479
480 return TRUE;
481 }
482
483
484 static BOOL FASTCALL
485 MsgiAnsiToUnicodeCleanup(LPMSG UnicodeMsg, LPMSG AnsiMsg)
486 {
487 switch (AnsiMsg->message)
488 {
489 case WM_GETTEXT:
490 case WM_ASKCBFORMATNAME:
491 {
492 HeapFree(GetProcessHeap(), 0, (PVOID) UnicodeMsg->lParam);
493 break;
494 }
495
496 case WM_SETTEXT:
497 case WM_WININICHANGE:
498 case WM_DEVMODECHANGE:
499 case CB_DIR:
500 case LB_DIR:
501 case LB_ADDFILE:
502 case EM_REPLACESEL:
503 {
504 UNICODE_STRING UnicodeString;
505 RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam);
506 RtlFreeUnicodeString(&UnicodeString);
507 break;
508 }
509
510 case WM_NCCREATE:
511 case WM_CREATE:
512 {
513 UNICODE_STRING UnicodeString;
514 struct s
515 {
516 CREATESTRUCTW cs; /* new structure */
517 LPWSTR lpszName; /* allocated Name */
518 LPWSTR lpszClass; /* allocated Class */
519 };
520 struct s *xs = (struct s *)UnicodeMsg->lParam;
521 if (xs->lpszName)
522 {
523 RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszName);
524 RtlFreeUnicodeString(&UnicodeString);
525 }
526 if (xs->lpszClass)
527 {
528 RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszClass);
529 RtlFreeUnicodeString(&UnicodeString);
530 }
531 HeapFree(GetProcessHeap(), 0, xs);
532 }
533 break;
534
535 case WM_MDICREATE:
536 {
537 UNICODE_STRING UnicodeString;
538 MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)UnicodeMsg->lParam;
539 if (HIWORD(cs->szTitle))
540 {
541 RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szTitle);
542 RtlFreeUnicodeString(&UnicodeString);
543 }
544 if (HIWORD(cs->szClass))
545 {
546 RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szClass);
547 RtlFreeUnicodeString(&UnicodeString);
548 }
549 HeapFree(GetProcessHeap(), 0, cs);
550 }
551 break;
552 }
553 return(TRUE);
554 }
555
556
557 static BOOL FASTCALL
558 MsgiAnsiToUnicodeReply(LPMSG UnicodeMsg, LPMSG AnsiMsg, LRESULT *Result)
559 {
560 switch (AnsiMsg->message)
561 {
562 case WM_GETTEXT:
563 case WM_ASKCBFORMATNAME:
564 {
565 LPWSTR Buffer = (LPWSTR)UnicodeMsg->lParam;
566 LPSTR AnsiBuffer = (LPSTR)AnsiMsg->lParam;
567 if (UnicodeMsg->wParam > 0 &&
568 !WideCharToMultiByte(CP_ACP, 0, Buffer, -1,
569 AnsiBuffer, UnicodeMsg->wParam, NULL, NULL))
570 {
571 AnsiBuffer[UnicodeMsg->wParam - 1] = 0;
572 }
573 break;
574 }
575 }
576
577 MsgiAnsiToUnicodeCleanup(UnicodeMsg, AnsiMsg);
578
579 return TRUE;
580 }
581
582
583 static BOOL FASTCALL
584 MsgiUnicodeToAnsiMessage(LPMSG AnsiMsg, LPMSG UnicodeMsg)
585 {
586 *AnsiMsg = *UnicodeMsg;
587
588 switch(UnicodeMsg->message)
589 {
590 case WM_CREATE:
591 case WM_NCCREATE:
592 {
593 CREATESTRUCTA* CsA;
594 CREATESTRUCTW* CsW;
595 UNICODE_STRING UString;
596 ANSI_STRING AString;
597 NTSTATUS Status;
598
599 CsW = (CREATESTRUCTW*)(UnicodeMsg->lParam);
600 CsA = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(CREATESTRUCTA));
601 if (NULL == CsA)
602 {
603 return FALSE;
604 }
605 memcpy(CsA, CsW, sizeof(CREATESTRUCTW));
606
607 RtlInitUnicodeString(&UString, CsW->lpszName);
608 Status = RtlUnicodeStringToAnsiString(&AString, &UString, TRUE);
609 if (! NT_SUCCESS(Status))
610 {
611 RtlFreeHeap(GetProcessHeap(), 0, CsA);
612 return FALSE;
613 }
614 CsA->lpszName = AString.Buffer;
615 if (HIWORD((ULONG)CsW->lpszClass) != 0)
616 {
617 RtlInitUnicodeString(&UString, CsW->lpszClass);
618 Status = RtlUnicodeStringToAnsiString(&AString, &UString, TRUE);
619 if (! NT_SUCCESS(Status))
620 {
621 RtlInitAnsiString(&AString, CsA->lpszName);
622 RtlFreeAnsiString(&AString);
623 RtlFreeHeap(GetProcessHeap(), 0, CsA);
624 return FALSE;
625 }
626 CsA->lpszClass = AString.Buffer;
627 }
628 AnsiMsg->lParam = (LPARAM)CsA;
629 break;
630 }
631 case WM_GETTEXT:
632 {
633 /* Ansi string might contain MBCS chars so we need 2 * the number of chars */
634 AnsiMsg->wParam = UnicodeMsg->wParam * 2;
635 AnsiMsg->lParam = (LPARAM) RtlAllocateHeap(GetProcessHeap(), 0, AnsiMsg->wParam);
636 if (NULL == (PVOID) AnsiMsg->lParam)
637 {
638 return FALSE;
639 }
640 break;
641 }
642 case WM_SETTEXT:
643 {
644 ANSI_STRING AnsiString;
645 UNICODE_STRING UnicodeString;
646 RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
647 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
648 &UnicodeString,
649 TRUE)))
650 {
651 return FALSE;
652 }
653 AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
654 break;
655 }
656 }
657
658 return TRUE;
659 }
660
661
662 static BOOL FASTCALL
663 MsgiUnicodeToAnsiCleanup(LPMSG AnsiMsg, LPMSG UnicodeMsg)
664 {
665 switch(UnicodeMsg->message)
666 {
667 case WM_GETTEXT:
668 {
669 RtlFreeHeap(GetProcessHeap(), 0, (PVOID) AnsiMsg->lParam);
670 break;
671 }
672 case WM_SETTEXT:
673 {
674 ANSI_STRING AString;
675 RtlInitAnsiString(&AString, (PSTR) AnsiMsg->lParam);
676 RtlFreeAnsiString(&AString);
677 break;
678 }
679 case WM_CREATE:
680 case WM_NCCREATE:
681 {
682 CREATESTRUCTA* Cs;
683 ANSI_STRING AString;
684
685 Cs = (CREATESTRUCTA*) AnsiMsg->lParam;
686 RtlInitAnsiString(&AString, Cs->lpszName);
687 RtlFreeAnsiString(&AString);
688 if (HIWORD((ULONG)Cs->lpszClass) != 0)
689 {
690 RtlInitAnsiString(&AString, Cs->lpszClass);
691 RtlFreeAnsiString(&AString);
692 }
693 RtlFreeHeap(GetProcessHeap(), 0, Cs);
694 break;
695 }
696 }
697
698 return TRUE;
699 }
700
701
702 static BOOL FASTCALL
703 MsgiUnicodeToAnsiReply(LPMSG AnsiMsg, LPMSG UnicodeMsg, LRESULT *Result)
704 {
705 switch (UnicodeMsg->message)
706 {
707 case WM_GETTEXT:
708 case WM_ASKCBFORMATNAME:
709 {
710 LPSTR Buffer = (LPSTR) AnsiMsg->lParam;
711 LPWSTR UBuffer = (LPWSTR) UnicodeMsg->lParam;
712 if (0 < AnsiMsg->wParam &&
713 ! MultiByteToWideChar(CP_ACP, 0, Buffer, -1, UBuffer, UnicodeMsg->wParam))
714 {
715 UBuffer[UnicodeMsg->wParam - 1] = L'\0';
716 }
717 break;
718 }
719 }
720
721 MsgiUnicodeToAnsiCleanup(AnsiMsg, UnicodeMsg);
722
723 return TRUE;
724 }
725
726 typedef struct tagMSGCONVERSION
727 {
728 BOOL InUse;
729 BOOL Ansi;
730 MSG KMMsg;
731 MSG UnicodeMsg;
732 MSG AnsiMsg;
733 PMSG FinalMsg;
734 ULONG LParamSize;
735 } MSGCONVERSION, *PMSGCONVERSION;
736
737 static PMSGCONVERSION MsgConversions = NULL;
738 static unsigned MsgConversionNumAlloc = 0;
739 static unsigned MsgConversionNumUsed = 0;
740 static CRITICAL_SECTION MsgConversionCrst;
741
742 static BOOL FASTCALL
743 MsgConversionAdd(PMSGCONVERSION Conversion)
744 {
745 unsigned i;
746
747 EnterCriticalSection(&MsgConversionCrst);
748
749 if (MsgConversionNumUsed == MsgConversionNumAlloc)
750 {
751 #define GROWBY 4
752 PMSGCONVERSION New;
753 if (NULL != MsgConversions)
754 {
755 New = HeapReAlloc(GetProcessHeap(), 0, MsgConversions,
756 (MsgConversionNumAlloc + GROWBY) * sizeof(MSGCONVERSION));
757 }
758 else
759 {
760 New = HeapAlloc(GetProcessHeap(), 0,
761 (MsgConversionNumAlloc + GROWBY) * sizeof(MSGCONVERSION));
762 }
763
764 if (NULL == New)
765 {
766 LeaveCriticalSection(&MsgConversionCrst);
767 return FALSE;
768 }
769 MsgConversions = New;
770 /* zero out newly allocated part */
771 memset(MsgConversions + MsgConversionNumAlloc, 0, GROWBY * sizeof(MSGCONVERSION));
772 MsgConversionNumAlloc += GROWBY;
773 #undef GROWBY
774 }
775
776 for (i = 0; i < MsgConversionNumAlloc; i++)
777 {
778 if (! MsgConversions[i].InUse)
779 {
780 MsgConversions[i] = *Conversion;
781 MsgConversions[i].InUse = TRUE;
782 MsgConversionNumUsed++;
783 break;
784 }
785 }
786 LeaveCriticalSection(&MsgConversionCrst);
787
788 return TRUE;
789 }
790
791 static void FASTCALL
792 MsgConversionCleanup(CONST MSG *Msg, BOOL Ansi, BOOL CheckMsgContents, LRESULT *Result)
793 {
794 BOOL Found;
795 PMSGCONVERSION Conversion;
796 LRESULT Dummy;
797
798 EnterCriticalSection(&MsgConversionCrst);
799 for (Conversion = MsgConversions;
800 Conversion < MsgConversions + MsgConversionNumAlloc;
801 Conversion++)
802 {
803 if (Conversion->InUse &&
804 ((Ansi && Conversion->Ansi) ||
805 (! Ansi && ! Conversion->Ansi)))
806 {
807 Found = (Conversion->FinalMsg == Msg);
808 if (! Found && CheckMsgContents)
809 {
810 if (Ansi)
811 {
812 Found = (0 == memcmp(Msg, &Conversion->AnsiMsg, sizeof(MSG)));
813 }
814 else
815 {
816 Found = (0 == memcmp(Msg, &Conversion->UnicodeMsg, sizeof(MSG)));
817 }
818 }
819 if (Found)
820 {
821 if (Ansi)
822 {
823 MsgiUnicodeToAnsiReply(&Conversion->AnsiMsg, &Conversion->UnicodeMsg,
824 NULL == Result ? &Dummy : Result);
825 }
826 MsgiKMToUMReply(&Conversion->KMMsg, &Conversion->UnicodeMsg,
827 NULL == Result ? &Dummy : Result);
828 if (0 != Conversion->LParamSize)
829 {
830 NtFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &Conversion->KMMsg.lParam,
831 &Conversion->LParamSize, MEM_DECOMMIT);
832 }
833 Conversion->InUse = FALSE;
834 MsgConversionNumUsed--;
835 }
836 }
837 }
838 LeaveCriticalSection(&MsgConversionCrst);
839 }
840
841 /*
842 * @implemented
843 */
844 LPARAM
845 STDCALL
846 GetMessageExtraInfo(VOID)
847 {
848 return (LPARAM)NtUserCallNoParam(NOPARAM_ROUTINE_GETMESSAGEEXTRAINFO);
849 }
850
851
852 /*
853 * @implemented
854 */
855 DWORD
856 STDCALL
857 GetMessagePos(VOID)
858 {
859 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
860 return(MAKELONG(ThreadData->LastMessage.pt.x, ThreadData->LastMessage.pt.y));
861 }
862
863
864 /*
865 * @implemented
866 */
867 LONG STDCALL
868 GetMessageTime(VOID)
869 {
870 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
871 return(ThreadData->LastMessage.time);
872 }
873
874
875 /*
876 * @unimplemented
877 */
878 BOOL
879 STDCALL
880 InSendMessage(VOID)
881 {
882 static DWORD ShowNotImplemented = TRUE;
883 if (ShowNotImplemented)
884 {
885 DbgPrint("InSendMessage is unimplemented\n");
886 ShowNotImplemented = FALSE;
887 }
888 /* return(NtUserGetThreadState(THREADSTATE_INSENDMESSAGE) != ISMEX_NOSEND); */
889 return FALSE;
890 }
891
892
893 /*
894 * @unimplemented
895 */
896 DWORD
897 STDCALL
898 InSendMessageEx(
899 LPVOID lpReserved)
900 {
901 /* return NtUserGetThreadState(THREADSTATE_INSENDMESSAGE); */
902 UNIMPLEMENTED;
903 return 0;
904 }
905
906
907 /*
908 * @unimplemented
909 */
910 BOOL
911 STDCALL
912 ReplyMessage(
913 LRESULT lResult)
914 {
915 UNIMPLEMENTED;
916 return FALSE;
917 }
918
919
920 /*
921 * @implemented
922 */
923 LPARAM
924 STDCALL
925 SetMessageExtraInfo(
926 LPARAM lParam)
927 {
928 return NtUserSetMessageExtraInfo(lParam);
929 }
930
931 LRESULT FASTCALL
932 IntCallWindowProcW(BOOL IsAnsiProc,
933 WNDPROC WndProc,
934 HWND hWnd,
935 UINT Msg,
936 WPARAM wParam,
937 LPARAM lParam)
938 {
939 MSG AnsiMsg;
940 MSG UnicodeMsg;
941 LRESULT Result;
942
943 if (IsAnsiProc)
944 {
945 UnicodeMsg.hwnd = hWnd;
946 UnicodeMsg.message = Msg;
947 UnicodeMsg.wParam = wParam;
948 UnicodeMsg.lParam = lParam;
949 if (! MsgiUnicodeToAnsiMessage(&AnsiMsg, &UnicodeMsg))
950 {
951 return FALSE;
952 }
953 Result = WndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam);
954 if (! MsgiUnicodeToAnsiReply(&AnsiMsg, &UnicodeMsg, &Result))
955 {
956 return FALSE;
957 }
958 return Result;
959 }
960 else
961 {
962 return WndProc(hWnd, Msg, wParam, lParam);
963 }
964 }
965
966 static LRESULT FASTCALL
967 IntCallWindowProcA(BOOL IsAnsiProc,
968 WNDPROC WndProc,
969 HWND hWnd,
970 UINT Msg,
971 WPARAM wParam,
972 LPARAM lParam)
973 {
974 MSG AnsiMsg;
975 MSG UnicodeMsg;
976 LRESULT Result;
977
978 if (IsAnsiProc)
979 {
980 return WndProc(hWnd, Msg, wParam, lParam);
981 }
982 else
983 {
984 AnsiMsg.hwnd = hWnd;
985 AnsiMsg.message = Msg;
986 AnsiMsg.wParam = wParam;
987 AnsiMsg.lParam = lParam;
988 if (! MsgiAnsiToUnicodeMessage(&UnicodeMsg, &AnsiMsg))
989 {
990 return FALSE;
991 }
992 Result = WndProc(UnicodeMsg.hwnd, UnicodeMsg.message,
993 UnicodeMsg.wParam, UnicodeMsg.lParam);
994 if (! MsgiAnsiToUnicodeReply(&UnicodeMsg, &AnsiMsg, &Result))
995 {
996 return FALSE;
997 }
998 return Result;
999 }
1000 }
1001
1002
1003 /*
1004 * @implemented
1005 */
1006 LRESULT STDCALL
1007 CallWindowProcA(WNDPROC lpPrevWndFunc,
1008 HWND hWnd,
1009 UINT Msg,
1010 WPARAM wParam,
1011 LPARAM lParam)
1012 {
1013 BOOL IsHandle;
1014 WndProcHandle wphData;
1015
1016 if (lpPrevWndFunc == NULL)
1017 lpPrevWndFunc = (WNDPROC)NtUserGetWindowLong(hWnd, GWL_WNDPROC, FALSE);
1018
1019 IsHandle = NtUserDereferenceWndProcHandle(lpPrevWndFunc,&wphData);
1020 if (! IsHandle)
1021 {
1022 return IntCallWindowProcA(TRUE, lpPrevWndFunc, hWnd, Msg, wParam, lParam);
1023 }
1024 else
1025 {
1026 return IntCallWindowProcA(! wphData.IsUnicode, wphData.WindowProc,
1027 hWnd, Msg, wParam, lParam);
1028 }
1029 }
1030
1031
1032 /*
1033 * @implemented
1034 */
1035 LRESULT STDCALL
1036 CallWindowProcW(WNDPROC lpPrevWndFunc,
1037 HWND hWnd,
1038 UINT Msg,
1039 WPARAM wParam,
1040 LPARAM lParam)
1041 {
1042 BOOL IsHandle;
1043 WndProcHandle wphData;
1044
1045 IsHandle = NtUserDereferenceWndProcHandle(lpPrevWndFunc,&wphData);
1046 if (! IsHandle)
1047 {
1048 return IntCallWindowProcW(FALSE, lpPrevWndFunc, hWnd, Msg, wParam, lParam);
1049 }
1050 else
1051 {
1052 return IntCallWindowProcW(! wphData.IsUnicode, wphData.WindowProc,
1053 hWnd, Msg, wParam, lParam);
1054 }
1055 }
1056
1057
1058 /*
1059 * @implemented
1060 */
1061 LRESULT STDCALL
1062 DispatchMessageA(CONST MSG *lpmsg)
1063 {
1064 NTUSERDISPATCHMESSAGEINFO Info;
1065 LRESULT Result;
1066
1067 Info.Ansi = TRUE;
1068 Info.Msg = *lpmsg;
1069 Result = NtUserDispatchMessage(&Info);
1070 if (! Info.HandledByKernel)
1071 {
1072 /* We need to send the message ourselves */
1073 Result = IntCallWindowProcA(Info.Ansi, Info.Proc, Info.Msg.hwnd,
1074 Info.Msg.message, Info.Msg.wParam, Info.Msg.lParam);
1075 }
1076 MsgConversionCleanup(lpmsg, TRUE, TRUE, &Result);
1077
1078 return Result;
1079 }
1080
1081
1082 /*
1083 * @implemented
1084 */
1085 LRESULT STDCALL
1086 DispatchMessageW(CONST MSG *lpmsg)
1087 {
1088 NTUSERDISPATCHMESSAGEINFO Info;
1089 LRESULT Result;
1090
1091 Info.Ansi = FALSE;
1092 Info.Msg = *lpmsg;
1093 Result = NtUserDispatchMessage(&Info);
1094 if (! Info.HandledByKernel)
1095 {
1096 /* We need to send the message ourselves */
1097 Result = IntCallWindowProcW(Info.Ansi, Info.Proc, Info.Msg.hwnd,
1098 Info.Msg.message, Info.Msg.wParam, Info.Msg.lParam);
1099 }
1100 MsgConversionCleanup(lpmsg, FALSE, TRUE, &Result);
1101
1102 return Result;
1103 }
1104
1105
1106 /*
1107 * @implemented
1108 */
1109 BOOL STDCALL
1110 GetMessageA(LPMSG lpMsg,
1111 HWND hWnd,
1112 UINT wMsgFilterMin,
1113 UINT wMsgFilterMax)
1114 {
1115 BOOL Res;
1116 MSGCONVERSION Conversion;
1117 NTUSERGETMESSAGEINFO Info;
1118 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
1119
1120 MsgConversionCleanup(lpMsg, TRUE, FALSE, NULL);
1121 Res = NtUserGetMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax);
1122 if (-1 == (int) Res)
1123 {
1124 return Res;
1125 }
1126 Conversion.LParamSize = Info.LParamSize;
1127 Conversion.KMMsg = Info.Msg;
1128
1129 if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg))
1130 {
1131 return (BOOL) -1;
1132 }
1133 if (! MsgiUnicodeToAnsiMessage(&Conversion.AnsiMsg, &Conversion.UnicodeMsg))
1134 {
1135 MsgiKMToUMCleanup(&Info.Msg, &Conversion.UnicodeMsg);
1136 return (BOOL) -1;
1137 }
1138 *lpMsg = Conversion.AnsiMsg;
1139 Conversion.Ansi = TRUE;
1140 Conversion.FinalMsg = lpMsg;
1141 MsgConversionAdd(&Conversion);
1142 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
1143 {
1144 ThreadData->LastMessage = Info.Msg;
1145 }
1146
1147 return Res;
1148 }
1149
1150
1151 /*
1152 * @implemented
1153 */
1154 BOOL STDCALL
1155 GetMessageW(LPMSG lpMsg,
1156 HWND hWnd,
1157 UINT wMsgFilterMin,
1158 UINT wMsgFilterMax)
1159 {
1160 BOOL Res;
1161 MSGCONVERSION Conversion;
1162 NTUSERGETMESSAGEINFO Info;
1163 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
1164
1165 MsgConversionCleanup(lpMsg, FALSE, FALSE, NULL);
1166 Res = NtUserGetMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax);
1167 if (-1 == (int) Res)
1168 {
1169 return Res;
1170 }
1171 Conversion.LParamSize = Info.LParamSize;
1172 Conversion.KMMsg = Info.Msg;
1173
1174 if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg))
1175 {
1176 return (BOOL) -1;
1177 }
1178 *lpMsg = Conversion.UnicodeMsg;
1179 Conversion.Ansi = FALSE;
1180 Conversion.FinalMsg = lpMsg;
1181 MsgConversionAdd(&Conversion);
1182 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
1183 {
1184 ThreadData->LastMessage = Info.Msg;
1185 }
1186
1187 return Res;
1188 }
1189
1190
1191 /*
1192 * @implemented
1193 */
1194 BOOL STDCALL
1195 PeekMessageA(LPMSG lpMsg,
1196 HWND hWnd,
1197 UINT wMsgFilterMin,
1198 UINT wMsgFilterMax,
1199 UINT wRemoveMsg)
1200 {
1201 BOOL Res;
1202 MSGCONVERSION Conversion;
1203 NTUSERGETMESSAGEINFO Info;
1204 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
1205
1206 MsgConversionCleanup(lpMsg, TRUE, FALSE, NULL);
1207 Res = NtUserPeekMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
1208 if (-1 == (int) Res || ! Res)
1209 {
1210 return Res;
1211 }
1212 Conversion.LParamSize = Info.LParamSize;
1213 Conversion.KMMsg = Info.Msg;
1214
1215 if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg))
1216 {
1217 return (BOOL) -1;
1218 }
1219 if (! MsgiUnicodeToAnsiMessage(&Conversion.AnsiMsg, &Conversion.UnicodeMsg))
1220 {
1221 MsgiKMToUMCleanup(&Info.Msg, &Conversion.UnicodeMsg);
1222 return (BOOL) -1;
1223 }
1224 *lpMsg = Conversion.AnsiMsg;
1225 Conversion.Ansi = TRUE;
1226 Conversion.FinalMsg = lpMsg;
1227 MsgConversionAdd(&Conversion);
1228 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
1229 {
1230 ThreadData->LastMessage = Info.Msg;
1231 }
1232
1233 return Res;
1234 }
1235
1236
1237 /*
1238 * @implemented
1239 */
1240 BOOL
1241 STDCALL
1242 PeekMessageW(
1243 LPMSG lpMsg,
1244 HWND hWnd,
1245 UINT wMsgFilterMin,
1246 UINT wMsgFilterMax,
1247 UINT wRemoveMsg)
1248 {
1249 BOOL Res;
1250 MSGCONVERSION Conversion;
1251 NTUSERGETMESSAGEINFO Info;
1252 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
1253
1254 MsgConversionCleanup(lpMsg, FALSE, FALSE, NULL);
1255 Res = NtUserPeekMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
1256 if (-1 == (int) Res || ! Res)
1257 {
1258 return Res;
1259 }
1260 Conversion.LParamSize = Info.LParamSize;
1261 Conversion.KMMsg = Info.Msg;
1262
1263 if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg))
1264 {
1265 return (BOOL) -1;
1266 }
1267 *lpMsg = Conversion.UnicodeMsg;
1268 Conversion.Ansi = FALSE;
1269 Conversion.FinalMsg = lpMsg;
1270 MsgConversionAdd(&Conversion);
1271 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
1272 {
1273 ThreadData->LastMessage = Info.Msg;
1274 }
1275
1276 return Res;
1277 }
1278
1279
1280 /*
1281 * @implemented
1282 */
1283 BOOL
1284 STDCALL
1285 PostMessageA(
1286 HWND Wnd,
1287 UINT Msg,
1288 WPARAM wParam,
1289 LPARAM lParam)
1290 {
1291 MSG AnsiMsg, UcMsg;
1292 MSG KMMsg;
1293 LRESULT Result;
1294
1295 AnsiMsg.hwnd = Wnd;
1296 AnsiMsg.message = Msg;
1297 AnsiMsg.wParam = wParam;
1298 AnsiMsg.lParam = lParam;
1299 if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg))
1300 {
1301 return FALSE;
1302 }
1303
1304 if (! MsgiUMToKMMessage(&UcMsg, &KMMsg, TRUE))
1305 {
1306 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
1307 return FALSE;
1308 }
1309 Result = NtUserPostMessage(KMMsg.hwnd, KMMsg.message,
1310 KMMsg.wParam, KMMsg.lParam);
1311 MsgiUMToKMCleanup(&UcMsg, &KMMsg);
1312 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
1313
1314 return Result;
1315 }
1316
1317
1318 /*
1319 * @implemented
1320 */
1321 BOOL
1322 STDCALL
1323 PostMessageW(
1324 HWND Wnd,
1325 UINT Msg,
1326 WPARAM wParam,
1327 LPARAM lParam)
1328 {
1329 MSG UMMsg, KMMsg;
1330 LRESULT Result;
1331
1332 UMMsg.hwnd = Wnd;
1333 UMMsg.message = Msg;
1334 UMMsg.wParam = wParam;
1335 UMMsg.lParam = lParam;
1336 if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, TRUE))
1337 {
1338 return FALSE;
1339 }
1340 Result = NtUserPostMessage(KMMsg.hwnd, KMMsg.message,
1341 KMMsg.wParam, KMMsg.lParam);
1342 MsgiUMToKMCleanup(&UMMsg, &KMMsg);
1343
1344 return Result;
1345 }
1346
1347
1348 /*
1349 * @implemented
1350 */
1351 VOID
1352 STDCALL
1353 PostQuitMessage(
1354 int nExitCode)
1355 {
1356 (void) NtUserPostMessage(NULL, WM_QUIT, nExitCode, 0);
1357 }
1358
1359
1360 /*
1361 * @implemented
1362 */
1363 BOOL
1364 STDCALL
1365 PostThreadMessageA(
1366 DWORD idThread,
1367 UINT Msg,
1368 WPARAM wParam,
1369 LPARAM lParam)
1370 {
1371 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
1372 }
1373
1374
1375 /*
1376 * @implemented
1377 */
1378 BOOL
1379 STDCALL
1380 PostThreadMessageW(
1381 DWORD idThread,
1382 UINT Msg,
1383 WPARAM wParam,
1384 LPARAM lParam)
1385 {
1386 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
1387 }
1388
1389
1390 /*
1391 * @implemented
1392 */
1393 LRESULT STDCALL
1394 SendMessageW(HWND Wnd,
1395 UINT Msg,
1396 WPARAM wParam,
1397 LPARAM lParam)
1398 {
1399 MSG UMMsg, KMMsg;
1400 NTUSERSENDMESSAGEINFO Info;
1401 LRESULT Result;
1402
1403 UMMsg.hwnd = Wnd;
1404 UMMsg.message = Msg;
1405 UMMsg.wParam = wParam;
1406 UMMsg.lParam = lParam;
1407 if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, FALSE))
1408 {
1409 return FALSE;
1410 }
1411 Info.Ansi = FALSE;
1412 Result = NtUserSendMessage(KMMsg.hwnd, KMMsg.message,
1413 KMMsg.wParam, KMMsg.lParam, &Info);
1414 if (! Info.HandledByKernel)
1415 {
1416 MsgiUMToKMCleanup(&UMMsg, &KMMsg);
1417 /* We need to send the message ourselves */
1418 Result = IntCallWindowProcW(Info.Ansi, Info.Proc, UMMsg.hwnd, UMMsg.message,
1419 UMMsg.wParam, UMMsg.lParam);
1420 }
1421 else if (! MsgiUMToKMReply(&UMMsg, &KMMsg, &Result))
1422 {
1423 return FALSE;
1424 }
1425
1426 return Result;
1427 }
1428
1429
1430 /*
1431 * @implemented
1432 */
1433 LRESULT STDCALL
1434 SendMessageA(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
1435 {
1436 MSG AnsiMsg, UcMsg;
1437 MSG KMMsg;
1438 LRESULT Result;
1439 NTUSERSENDMESSAGEINFO Info;
1440
1441 AnsiMsg.hwnd = Wnd;
1442 AnsiMsg.message = Msg;
1443 AnsiMsg.wParam = wParam;
1444 AnsiMsg.lParam = lParam;
1445 if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg))
1446 {
1447 return FALSE;
1448 }
1449
1450 if (! MsgiUMToKMMessage(&UcMsg, &KMMsg, FALSE))
1451 {
1452 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
1453 return FALSE;
1454 }
1455 Info.Ansi = TRUE;
1456 Result = NtUserSendMessage(KMMsg.hwnd, KMMsg.message,
1457 KMMsg.wParam, KMMsg.lParam, &Info);
1458 if (! Info.HandledByKernel)
1459 {
1460 /* We need to send the message ourselves */
1461 if (Info.Ansi)
1462 {
1463 /* Ansi message and Ansi window proc, that's easy. Clean up
1464 the Unicode message though */
1465 MsgiUMToKMCleanup(&UcMsg, &KMMsg);
1466 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
1467 Result = IntCallWindowProcA(Info.Ansi, Info.Proc, Wnd, Msg, wParam, lParam);
1468 }
1469 else
1470 {
1471 /* Unicode winproc. Although we started out with an Ansi message we
1472 already converted it to Unicode for the kernel call. Reuse that
1473 message to avoid another conversion */
1474 Result = IntCallWindowProcW(Info.Ansi, Info.Proc, UcMsg.hwnd,
1475 UcMsg.message, UcMsg.wParam, UcMsg.lParam);
1476 if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
1477 {
1478 return FALSE;
1479 }
1480 }
1481 }
1482 /* Message sent by kernel. Convert back to Ansi */
1483 else if (! MsgiUMToKMReply(&UcMsg, &KMMsg, &Result) ||
1484 ! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
1485 {
1486 return FALSE;
1487 }
1488
1489 return Result;
1490 }
1491
1492
1493 /*
1494 * @implemented
1495 */
1496 BOOL
1497 STDCALL
1498 SendMessageCallbackA(
1499 HWND hWnd,
1500 UINT Msg,
1501 WPARAM wParam,
1502 LPARAM lParam,
1503 SENDASYNCPROC lpCallBack,
1504 ULONG_PTR dwData)
1505 {
1506 return NtUserSendMessageCallback(
1507 hWnd,
1508 Msg,
1509 wParam,
1510 lParam,
1511 lpCallBack,
1512 dwData);
1513 }
1514
1515
1516 /*
1517 * @implemented
1518 */
1519 BOOL
1520 STDCALL
1521 SendMessageCallbackW(
1522 HWND hWnd,
1523 UINT Msg,
1524 WPARAM wParam,
1525 LPARAM lParam,
1526 SENDASYNCPROC lpCallBack,
1527 ULONG_PTR dwData)
1528 {
1529 return NtUserSendMessageCallback(
1530 hWnd,
1531 Msg,
1532 wParam,
1533 lParam,
1534 lpCallBack,
1535 dwData);
1536 }
1537
1538
1539 /*
1540 * @implemented
1541 */
1542 LRESULT
1543 STDCALL
1544 SendMessageTimeoutA(
1545 HWND hWnd,
1546 UINT Msg,
1547 WPARAM wParam,
1548 LPARAM lParam,
1549 UINT fuFlags,
1550 UINT uTimeout,
1551 PDWORD_PTR lpdwResult)
1552 {
1553 MSG AnsiMsg;
1554 MSG UcMsg;
1555 LRESULT Result;
1556 NTUSERSENDMESSAGEINFO Info;
1557
1558 AnsiMsg.hwnd = hWnd;
1559 AnsiMsg.message = Msg;
1560 AnsiMsg.wParam = wParam;
1561 AnsiMsg.lParam = lParam;
1562 if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg))
1563 {
1564 return FALSE;
1565 }
1566
1567 Info.Ansi = TRUE;
1568 Result = NtUserSendMessageTimeout(UcMsg.hwnd, UcMsg.message,
1569 UcMsg.wParam, UcMsg.lParam,
1570 fuFlags, uTimeout, (ULONG_PTR*)lpdwResult, &Info);
1571 if(!Result)
1572 {
1573 return FALSE;
1574 }
1575 if (! Info.HandledByKernel)
1576 {
1577 /* We need to send the message ourselves */
1578 if (Info.Ansi)
1579 {
1580 /* Ansi message and Ansi window proc, that's easy. Clean up
1581 the Unicode message though */
1582 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
1583 Result = IntCallWindowProcA(Info.Ansi, Info.Proc, hWnd, Msg, wParam, lParam);
1584 }
1585 else
1586 {
1587 /* Unicode winproc. Although we started out with an Ansi message we
1588 already converted it to Unicode for the kernel call. Reuse that
1589 message to avoid another conversion */
1590 Result = IntCallWindowProcW(Info.Ansi, Info.Proc, UcMsg.hwnd,
1591 UcMsg.message, UcMsg.wParam, UcMsg.lParam);
1592 if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
1593 {
1594 return FALSE;
1595 }
1596 }
1597 if(lpdwResult)
1598 *lpdwResult = Result;
1599 Result = TRUE;
1600 }
1601 else
1602 {
1603 /* Message sent by kernel. Convert back to Ansi */
1604 if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
1605 {
1606 return FALSE;
1607 }
1608 }
1609
1610 return Result;
1611 }
1612
1613
1614 /*
1615 * @implemented
1616 */
1617 LRESULT
1618 STDCALL
1619 SendMessageTimeoutW(
1620 HWND hWnd,
1621 UINT Msg,
1622 WPARAM wParam,
1623 LPARAM lParam,
1624 UINT fuFlags,
1625 UINT uTimeout,
1626 PDWORD_PTR lpdwResult)
1627 {
1628 NTUSERSENDMESSAGEINFO Info;
1629 LRESULT Result;
1630
1631 Info.Ansi = FALSE;
1632 Result = NtUserSendMessageTimeout(hWnd, Msg, wParam, lParam, fuFlags, uTimeout,
1633 lpdwResult, &Info);
1634 if (! Info.HandledByKernel)
1635 {
1636 /* We need to send the message ourselves */
1637 Result = IntCallWindowProcW(Info.Ansi, Info.Proc, hWnd, Msg, wParam, lParam);
1638 if(lpdwResult)
1639 *lpdwResult = Result;
1640 return TRUE;
1641 }
1642
1643 return Result;
1644 }
1645
1646
1647 /*
1648 * @unimplemented
1649 */
1650 BOOL
1651 STDCALL
1652 SendNotifyMessageA(
1653 HWND hWnd,
1654 UINT Msg,
1655 WPARAM wParam,
1656 LPARAM lParam)
1657 {
1658 UNIMPLEMENTED;
1659 return FALSE;
1660 }
1661
1662
1663 /*
1664 * @unimplemented
1665 */
1666 BOOL
1667 STDCALL
1668 SendNotifyMessageW(
1669 HWND hWnd,
1670 UINT Msg,
1671 WPARAM wParam,
1672 LPARAM lParam)
1673 {
1674 UNIMPLEMENTED;
1675 return FALSE;
1676 }
1677
1678
1679 /*
1680 * @implemented
1681 */
1682 BOOL STDCALL
1683 TranslateMessageEx(CONST MSG *lpMsg, DWORD unk)
1684 {
1685 return(NtUserTranslateMessage((LPMSG)lpMsg, (HKL)unk));
1686 }
1687
1688
1689 /*
1690 * @implemented
1691 */
1692 BOOL STDCALL
1693 TranslateMessage(CONST MSG *lpMsg)
1694 {
1695 return(TranslateMessageEx((LPMSG)lpMsg, 0));
1696 }
1697
1698
1699 /*
1700 * @implemented
1701 */
1702 BOOL
1703 STDCALL
1704 WaitMessage(VOID)
1705 {
1706 return NtUserWaitMessage();
1707 }
1708
1709
1710 /*
1711 * @implemented
1712 */
1713 UINT STDCALL
1714 RegisterWindowMessageA(LPCSTR lpString)
1715 {
1716 UNICODE_STRING String;
1717 BOOLEAN Result;
1718 UINT Atom;
1719
1720 Result = RtlCreateUnicodeStringFromAsciiz(&String, (PCSZ)lpString);
1721 if (!Result)
1722 {
1723 return(0);
1724 }
1725 Atom = NtUserRegisterWindowMessage(&String);
1726 RtlFreeUnicodeString(&String);
1727 return(Atom);
1728 }
1729
1730
1731 /*
1732 * @implemented
1733 */
1734 UINT STDCALL
1735 RegisterWindowMessageW(LPCWSTR lpString)
1736 {
1737 UNICODE_STRING String;
1738
1739 RtlInitUnicodeString(&String, lpString);
1740 return(NtUserRegisterWindowMessage(&String));
1741 }
1742
1743 /*
1744 * @implemented
1745 */
1746 HWND STDCALL
1747 SetCapture(HWND hWnd)
1748 {
1749 return(NtUserSetCapture(hWnd));
1750 }
1751
1752 /*
1753 * @implemented
1754 */
1755 HWND STDCALL
1756 GetCapture(VOID)
1757 {
1758 return(NtUserGetCapture());
1759 }
1760
1761 /*
1762 * @implemented
1763 */
1764 BOOL STDCALL
1765 ReleaseCapture(VOID)
1766 {
1767 NtUserSetCapture(NULL);
1768 return(TRUE);
1769 }
1770
1771
1772 /*
1773 * @unimplemented
1774 */
1775 DWORD
1776 STDCALL
1777 RealGetQueueStatus(UINT flags)
1778 {
1779 DWORD ret;
1780 WORD changed_bits, wake_bits;
1781
1782 #if 0 /* wine stuff. don't know what it does... */
1783
1784 /* check for pending X events */
1785 if (USER_Driver.pMsgWaitForMultipleObjectsEx)
1786 USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
1787 #endif
1788
1789 ret = NtUserGetQueueStatus(TRUE /*ClearChanges*/);
1790
1791 changed_bits = LOWORD(ret);
1792 wake_bits = HIWORD(ret);
1793
1794 return MAKELONG(changed_bits & flags, wake_bits & flags);
1795 }
1796
1797
1798 /*
1799 * @unimplemented
1800 */
1801 BOOL STDCALL GetInputState(VOID)
1802 {
1803 DWORD ret;
1804 WORD wake_bits;
1805
1806 #if 0 /* wine stuff. don't know what it does... */
1807
1808 /* check for pending X events */
1809 if (USER_Driver.pMsgWaitForMultipleObjectsEx)
1810 USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
1811 #endif
1812
1813 ret = NtUserGetQueueStatus(FALSE /*ClearChanges*/);
1814
1815 wake_bits = HIWORD(ret);
1816
1817 return wake_bits & (QS_KEY | QS_MOUSEBUTTON);
1818 }
1819
1820
1821 NTSTATUS STDCALL
1822 User32CallWindowProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
1823 {
1824 PWINDOWPROC_CALLBACK_ARGUMENTS CallbackArgs;
1825 MSG KMMsg, UMMsg;
1826
1827 /* Make sure we don't try to access mem beyond what we were given */
1828 if (ArgumentLength < sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
1829 {
1830 return STATUS_INFO_LENGTH_MISMATCH;
1831 }
1832
1833 CallbackArgs = (PWINDOWPROC_CALLBACK_ARGUMENTS) Arguments;
1834 KMMsg.hwnd = CallbackArgs->Wnd;
1835 KMMsg.message = CallbackArgs->Msg;
1836 KMMsg.wParam = CallbackArgs->wParam;
1837 /* Check if lParam is really a pointer and adjust it if it is */
1838 if (0 <= CallbackArgs->lParamBufferSize)
1839 {
1840 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)
1841 + CallbackArgs->lParamBufferSize)
1842 {
1843 return STATUS_INFO_LENGTH_MISMATCH;
1844 }
1845 KMMsg.lParam = (LPARAM) ((char *) CallbackArgs + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS));
1846 }
1847 else
1848 {
1849 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
1850 {
1851 return STATUS_INFO_LENGTH_MISMATCH;
1852 }
1853 KMMsg.lParam = CallbackArgs->lParam;
1854 }
1855
1856 if (WM_NCCALCSIZE == CallbackArgs->Msg && CallbackArgs->wParam)
1857 {
1858 NCCALCSIZE_PARAMS *Params = (NCCALCSIZE_PARAMS *) KMMsg.lParam;
1859 Params->lppos = (PWINDOWPOS) (Params + 1);
1860 }
1861
1862 if (! MsgiKMToUMMessage(&KMMsg, &UMMsg))
1863 {
1864 }
1865
1866 CallbackArgs->Result = IntCallWindowProcW(CallbackArgs->IsAnsiProc, CallbackArgs->Proc,
1867 UMMsg.hwnd, UMMsg.message,
1868 UMMsg.wParam, UMMsg.lParam);
1869
1870 if (! MsgiKMToUMReply(&KMMsg, &UMMsg, &CallbackArgs->Result))
1871 {
1872 }
1873
1874 return ZwCallbackReturn(CallbackArgs, ArgumentLength, STATUS_SUCCESS);
1875 }
1876
1877 /*
1878 * @implemented
1879 */
1880 BOOL STDCALL SetMessageQueue(int cMessagesMax)
1881 {
1882 /* Function does nothing on 32 bit windows */
1883 return TRUE;
1884 }
1885 typedef DWORD (WINAPI * RealGetQueueStatusProc)(UINT flags);
1886 typedef DWORD (WINAPI * RealMsgWaitForMultipleObjectsExProc)(DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags);
1887
1888 typedef struct _USER_MESSAGE_PUMP_ADDRESSES {
1889 DWORD cbSize;
1890 //NtUserRealInternalGetMessageProc NtUserRealInternalGetMessage;
1891 //NtUserRealWaitMessageExProc NtUserRealWaitMessageEx;
1892 RealGetQueueStatusProc RealGetQueueStatus;
1893 RealMsgWaitForMultipleObjectsExProc RealMsgWaitForMultipleObjectsEx;
1894 } USER_MESSAGE_PUMP_ADDRESSES, * PUSER_MESSAGE_PUMP_ADDRESSES;
1895
1896 DWORD
1897 STDCALL
1898 RealMsgWaitForMultipleObjectsEx(
1899 DWORD nCount,
1900 CONST HANDLE *pHandles,
1901 DWORD dwMilliseconds,
1902 DWORD dwWakeMask,
1903 DWORD dwFlags);
1904
1905 typedef BOOL (WINAPI * MESSAGEPUMPHOOKPROC)(BOOL Unregistering,PUSER_MESSAGE_PUMP_ADDRESSES MessagePumpAddresses);
1906
1907 CRITICAL_SECTION gcsMPH;
1908 MESSAGEPUMPHOOKPROC gpfnInitMPH;
1909 DWORD gcLoadMPH = 0;
1910 USER_MESSAGE_PUMP_ADDRESSES gmph = {sizeof(USER_MESSAGE_PUMP_ADDRESSES),
1911 //NtUserRealInternalGetMessage,
1912 //NtUserRealInternalWaitMessageEx,
1913 RealGetQueueStatus,
1914 RealMsgWaitForMultipleObjectsEx
1915 };
1916
1917 DWORD gfMessagePumpHook = 0;
1918
1919 BOOL WINAPI IsInsideMessagePumpHook()
1920 {
1921 if(!gfMessagePumpHook)
1922 return FALSE;
1923
1924 /* This code checks if we're inside SendMessage. */
1925 #if 0
1926 /* Since our TEB doesnt match that of real windows, testing this value is useless until we know what it does
1927 PUCHAR NtTeb = (PUCHAR)NtCurrentTeb();
1928
1929 if(!*(PLONG*)&NtTeb[0x708])
1930 return FALSE;
1931
1932 if(**(PLONG*)&NtTeb[0x708] <= 0)
1933 return FALSE;*/
1934 #endif
1935
1936 return TRUE;
1937 }
1938
1939 void WINAPI ResetMessagePumpHook(PUSER_MESSAGE_PUMP_ADDRESSES Addresses)
1940 {
1941 Addresses->cbSize = sizeof(USER_MESSAGE_PUMP_ADDRESSES);
1942 //Addresses->NtUserRealInternalGetMessage = (NtUserRealInternalGetMessageProc)NtUserRealInternalGetMessage;
1943 //Addresses->NtUserRealWaitMessageEx = (NtUserRealWaitMessageExProc)NtUserRealInternalWaitMessageEx;
1944 Addresses->RealGetQueueStatus = RealGetQueueStatus;
1945 Addresses->RealMsgWaitForMultipleObjectsEx = RealMsgWaitForMultipleObjectsEx;
1946 }
1947
1948 BOOL WINAPI RegisterMessagePumpHook(MESSAGEPUMPHOOKPROC Hook)
1949 {
1950 EnterCriticalSection(&gcsMPH);
1951 if(!Hook) {
1952 SetLastError(ERROR_INVALID_PARAMETER);
1953 LeaveCriticalSection(&gcsMPH);
1954 return FALSE;
1955 }
1956 if(!gcLoadMPH) {
1957 USER_MESSAGE_PUMP_ADDRESSES Addresses;
1958 gpfnInitMPH = Hook;
1959 ResetMessagePumpHook(&Addresses);
1960 if(!Hook(FALSE, &Addresses) || !Addresses.cbSize) {
1961 LeaveCriticalSection(&gcsMPH);
1962 return FALSE;
1963 }
1964 memcpy(&gmph, &Addresses, Addresses.cbSize);
1965 } else {
1966 if(gpfnInitMPH != Hook) {
1967 LeaveCriticalSection(&gcsMPH);
1968 return FALSE;
1969 }
1970 }
1971 if(NtUserCallNoParam(NOPARAM_ROUTINE_INIT_MESSAGE_PUMP)) {
1972 LeaveCriticalSection(&gcsMPH);
1973 return FALSE;
1974 }
1975 if (!gcLoadMPH++) {
1976 InterlockedExchange((PLONG)&gfMessagePumpHook, 1);
1977 }
1978 LeaveCriticalSection(&gcsMPH);
1979 return TRUE;
1980 }
1981
1982 BOOL WINAPI UnregisterMessagePumpHook(VOID)
1983 {
1984 EnterCriticalSection(&gcsMPH);
1985 if(gcLoadMPH > 0) {
1986 if(NtUserCallNoParam(NOPARAM_ROUTINE_UNINIT_MESSAGE_PUMP)) {
1987 gcLoadMPH--;
1988 if(!gcLoadMPH) {
1989 InterlockedExchange((PLONG)&gfMessagePumpHook, 0);
1990 gpfnInitMPH(TRUE, NULL);
1991 ResetMessagePumpHook(&gmph);
1992 gpfnInitMPH = 0;
1993 }
1994 LeaveCriticalSection(&gcsMPH);
1995 return TRUE;
1996 }
1997 }
1998 LeaveCriticalSection(&gcsMPH);
1999 return FALSE;
2000 }
2001
2002 DWORD WINAPI GetQueueStatus(UINT flags)
2003 {
2004 return IsInsideMessagePumpHook() ? gmph.RealGetQueueStatus(flags) : RealGetQueueStatus(flags);
2005 }
2006
2007 /**
2008 * @name RealMsgWaitForMultipleObjectsEx
2009 *
2010 * Wait either for either message arrival or for one of the passed events
2011 * to be signalled.
2012 *
2013 * @param nCount
2014 * Number of handles in the pHandles array.
2015 * @param pHandles
2016 * Handles of events to wait for.
2017 * @param dwMilliseconds
2018 * Timeout interval.
2019 * @param dwWakeMask
2020 * Mask specifying on which message events we should wakeup.
2021 * @param dwFlags
2022 * Wait type (see MWMO_* constants).
2023 *
2024 * @implemented
2025 */
2026
2027 DWORD STDCALL
2028 RealMsgWaitForMultipleObjectsEx(
2029 DWORD nCount,
2030 const HANDLE *pHandles,
2031 DWORD dwMilliseconds,
2032 DWORD dwWakeMask,
2033 DWORD dwFlags)
2034 {
2035 LPHANDLE RealHandles;
2036 HANDLE MessageQueueHandle;
2037 DWORD Result;
2038
2039 if (dwFlags & ~(MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE))
2040 {
2041 SetLastError(ERROR_INVALID_PARAMETER);
2042 return WAIT_FAILED;
2043 }
2044
2045 /*
2046 if (dwFlags & MWMO_INPUTAVAILABLE)
2047 {
2048 RealGetQueueStatus(dwWakeMask);
2049 }
2050 */
2051
2052 MessageQueueHandle = NtUserMsqSetWakeMask(dwWakeMask);
2053 if (MessageQueueHandle == NULL)
2054 {
2055 SetLastError(0); /* ? */
2056 return WAIT_FAILED;
2057 }
2058
2059 RealHandles = HeapAlloc(GetProcessHeap(), 0, (nCount + 1) * sizeof(HANDLE));
2060 if (RealHandles == NULL)
2061 {
2062 NtUserMsqClearWakeMask();
2063 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2064 return WAIT_FAILED;
2065 }
2066
2067 RtlCopyMemory(RealHandles, pHandles, nCount * sizeof(HANDLE));
2068 RealHandles[nCount] = MessageQueueHandle;
2069
2070 Result = WaitForMultipleObjectsEx(nCount + 1, RealHandles,
2071 dwFlags & MWMO_WAITALL,
2072 dwMilliseconds, dwFlags & MWMO_ALERTABLE);
2073
2074 HeapFree(GetProcessHeap(), 0, RealHandles);
2075 NtUserMsqClearWakeMask();
2076
2077 return Result;
2078 }
2079
2080 /*
2081 * @implemented
2082 */
2083 DWORD WINAPI
2084 MsgWaitForMultipleObjectsEx(
2085 DWORD nCount,
2086 CONST HANDLE *lpHandles,
2087 DWORD dwMilliseconds,
2088 DWORD dwWakeMask,
2089 DWORD dwFlags)
2090 {
2091 return IsInsideMessagePumpHook() ? gmph.RealMsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds, dwWakeMask, dwFlags) : RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags);
2092 }
2093
2094 /*
2095 * @implemented
2096 */
2097 DWORD STDCALL
2098 MsgWaitForMultipleObjects(
2099 DWORD nCount,
2100 CONST HANDLE *lpHandles,
2101 BOOL fWaitAll,
2102 DWORD dwMilliseconds,
2103 DWORD dwWakeMask)
2104 {
2105 return MsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds,
2106 dwWakeMask, fWaitAll ? MWMO_WAITALL : 0);
2107 }
2108
2109
2110 BOOL FASTCALL MessageInit()
2111 {
2112 InitializeCriticalSection(&DdeCrst);
2113 InitializeCriticalSection(&MsgConversionCrst);
2114
2115 return TRUE;
2116 }
2117
2118 /***********************************************************************
2119 * map_wparam_AtoW
2120 *
2121 * Convert the wparam of an ASCII message to Unicode.
2122 */
2123 static WPARAM
2124 map_wparam_AtoW( UINT message, WPARAM wparam )
2125 {
2126 switch(message)
2127 {
2128 case WM_CHARTOITEM:
2129 case EM_SETPASSWORDCHAR:
2130 case WM_CHAR:
2131 case WM_DEADCHAR:
2132 case WM_SYSCHAR:
2133 case WM_SYSDEADCHAR:
2134 case WM_MENUCHAR:
2135 {
2136 char ch[2];
2137 WCHAR wch[2];
2138 ch[0] = (wparam & 0xff);
2139 ch[1] = (wparam >> 8);
2140 MultiByteToWideChar(CP_ACP, 0, ch, 2, wch, 2);
2141 wparam = MAKEWPARAM(wch[0], wch[1]);
2142 }
2143 break;
2144 case WM_IME_CHAR:
2145 {
2146 char ch[2];
2147 WCHAR wch;
2148 ch[0] = (wparam >> 8);
2149 ch[1] = (wparam & 0xff);
2150 if (ch[0]) MultiByteToWideChar(CP_ACP, 0, ch, 2, &wch, 1);
2151 else MultiByteToWideChar(CP_ACP, 0, &ch[1], 1, &wch, 1);
2152 wparam = MAKEWPARAM( wch, HIWORD(wparam) );
2153 }
2154 break;
2155 }
2156 return wparam;
2157 }
2158
2159 /*
2160 * @implemented
2161 */
2162 BOOL WINAPI
2163 IsDialogMessageA( HWND hwndDlg, LPMSG pmsg )
2164 {
2165 MSG msg = *pmsg;
2166 msg.wParam = map_wparam_AtoW( msg.message, msg.wParam );
2167 return IsDialogMessageW( hwndDlg, &msg );
2168 }