first attempt to implement SendMessageTimeout()
[reactos.git] / reactos / lib / user32 / windows / message.c
1 /* $Id: message.c,v 1.36 2004/03/11 14:47:43 weiden Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS user32.dll
5 * FILE: lib/user32/windows/message.c
6 * PURPOSE: Messages
7 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * UPDATE HISTORY:
9 * 06-06-2001 CSH Created
10 */
11 #include <windows.h>
12 #include <user32.h>
13 #include <string.h>
14 #include <debug.h>
15
16 /*
17 * @implemented
18 */
19 LPARAM
20 STDCALL
21 GetMessageExtraInfo(VOID)
22 {
23 return (LPARAM)NtUserCallNoParam(NOPARAM_ROUTINE_GETMESSAGEEXTRAINFO);
24 }
25
26
27 /*
28 * @implemented
29 */
30 DWORD
31 STDCALL
32 GetMessagePos(VOID)
33 {
34 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
35 return(MAKELONG(ThreadData->LastMessage.pt.x, ThreadData->LastMessage.pt.y));
36 }
37
38
39 /*
40 * @implemented
41 */
42 LONG STDCALL
43 GetMessageTime(VOID)
44 {
45 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
46 return(ThreadData->LastMessage.time);
47 }
48
49
50 /*
51 * @unimplemented
52 */
53 BOOL
54 STDCALL
55 InSendMessage(VOID)
56 {
57 /* return(NtUserGetThreadState(THREADSTATE_INSENDMESSAGE) != ISMEX_NOSEND); */
58 UNIMPLEMENTED;
59 return FALSE;
60 }
61
62
63 /*
64 * @unimplemented
65 */
66 DWORD
67 STDCALL
68 InSendMessageEx(
69 LPVOID lpReserved)
70 {
71 /* return NtUserGetThreadState(THREADSTATE_INSENDMESSAGE); */
72 UNIMPLEMENTED;
73 return 0;
74 }
75
76
77 /*
78 * @unimplemented
79 */
80 BOOL
81 STDCALL
82 ReplyMessage(
83 LRESULT lResult)
84 {
85 UNIMPLEMENTED;
86 return FALSE;
87 }
88
89
90 /*
91 * @implemented
92 */
93 LPARAM
94 STDCALL
95 SetMessageExtraInfo(
96 LPARAM lParam)
97 {
98 return NtUserSetMessageExtraInfo(lParam);
99 }
100
101
102 BOOL
103 MsgiAnsiToUnicodeMessage(LPMSG UnicodeMsg, LPMSG AnsiMsg)
104 {
105 *UnicodeMsg = *AnsiMsg;
106 switch (AnsiMsg->message)
107 {
108 case WM_GETTEXT:
109 case WM_ASKCBFORMATNAME:
110 {
111 LPWSTR Buffer = HeapAlloc(GetProcessHeap(), 0,
112 AnsiMsg->wParam * sizeof(WCHAR));
113 if (!Buffer)
114 {
115 return FALSE;
116 }
117 UnicodeMsg->lParam = (LPARAM)Buffer;
118 break;
119 }
120
121 /* AnsiMsg->lParam is string (0-terminated) */
122 case WM_SETTEXT:
123 case WM_WININICHANGE:
124 case WM_DEVMODECHANGE:
125 case CB_DIR:
126 case LB_DIR:
127 case LB_ADDFILE:
128 case EM_REPLACESEL:
129 {
130 UNICODE_STRING UnicodeString;
131 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam);
132 UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer;
133 break;
134 }
135
136 case WM_NCCREATE:
137 case WM_CREATE:
138 {
139 UNICODE_STRING UnicodeBuffer;
140 struct s
141 {
142 CREATESTRUCTW cs; /* new structure */
143 LPCWSTR lpszName; /* allocated Name */
144 LPCWSTR lpszClass; /* allocated Class */
145 };
146 struct s *xs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct s));
147 if (!xs)
148 {
149 return FALSE;
150 }
151 xs->cs = *(CREATESTRUCTW *)AnsiMsg->lParam;
152 if (HIWORD(xs->cs.lpszName))
153 {
154 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)xs->cs.lpszName);
155 xs->lpszName = xs->cs.lpszName = UnicodeBuffer.Buffer;
156 }
157 if (HIWORD(xs->cs.lpszClass))
158 {
159 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)xs->cs.lpszClass);
160 xs->lpszClass = xs->cs.lpszClass = UnicodeBuffer.Buffer;
161 }
162 UnicodeMsg->lParam = (LPARAM)xs;
163 break;
164 }
165
166 case WM_MDICREATE:
167 {
168 UNICODE_STRING UnicodeBuffer;
169 MDICREATESTRUCTW *cs =
170 (MDICREATESTRUCTW *)HeapAlloc(GetProcessHeap(), 0, sizeof(*cs));
171
172 if (!cs)
173 {
174 return FALSE;
175 }
176
177 *cs = *(MDICREATESTRUCTW *)AnsiMsg->lParam;
178
179 if (HIWORD(cs->szClass))
180 {
181 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)cs->szClass);
182 cs->szClass = UnicodeBuffer.Buffer;
183 }
184
185 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)cs->szTitle);
186 cs->szTitle = UnicodeBuffer.Buffer;
187
188 UnicodeMsg->lParam = (LPARAM)cs;
189 break;
190 }
191 }
192
193 return TRUE;
194 }
195
196
197 BOOL
198 MsgiAnsiToUnicodeCleanup(LPMSG UnicodeMsg, LPMSG AnsiMsg)
199 {
200 switch (AnsiMsg->message)
201 {
202 case WM_GETTEXT:
203 case WM_ASKCBFORMATNAME:
204 {
205 HeapFree(GetProcessHeap(), 0, (PVOID) UnicodeMsg->lParam);
206 break;
207 }
208
209 case WM_SETTEXT:
210 case WM_WININICHANGE:
211 case WM_DEVMODECHANGE:
212 case CB_DIR:
213 case LB_DIR:
214 case LB_ADDFILE:
215 case EM_REPLACESEL:
216 {
217 UNICODE_STRING UnicodeString;
218 RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam);
219 RtlFreeUnicodeString(&UnicodeString);
220 break;
221 }
222
223 case WM_NCCREATE:
224 case WM_CREATE:
225 {
226 UNICODE_STRING UnicodeString;
227 struct s
228 {
229 CREATESTRUCTW cs; /* new structure */
230 LPWSTR lpszName; /* allocated Name */
231 LPWSTR lpszClass; /* allocated Class */
232 };
233 struct s *xs = (struct s *)UnicodeMsg->lParam;
234 if (xs->lpszName)
235 {
236 RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszName);
237 RtlFreeUnicodeString(&UnicodeString);
238 }
239 if (xs->lpszClass)
240 {
241 RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszClass);
242 RtlFreeUnicodeString(&UnicodeString);
243 }
244 HeapFree(GetProcessHeap(), 0, xs);
245 }
246 break;
247
248 case WM_MDICREATE:
249 {
250 UNICODE_STRING UnicodeString;
251 MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)UnicodeMsg->lParam;
252 if (HIWORD(cs->szTitle))
253 {
254 RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szTitle);
255 RtlFreeUnicodeString(&UnicodeString);
256 }
257 if (HIWORD(cs->szClass))
258 {
259 RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szClass);
260 RtlFreeUnicodeString(&UnicodeString);
261 }
262 HeapFree(GetProcessHeap(), 0, cs);
263 }
264 break;
265 }
266 return(TRUE);
267 }
268
269
270 BOOL
271 MsgiAnsiToUnicodeReply(LPMSG UnicodeMsg, LPMSG AnsiMsg, LRESULT *Result)
272 {
273 switch (AnsiMsg->message)
274 {
275 case WM_GETTEXT:
276 case WM_ASKCBFORMATNAME:
277 {
278 LPWSTR Buffer = (LPWSTR)UnicodeMsg->lParam;
279 LPSTR AnsiBuffer = (LPSTR)AnsiMsg->lParam;
280 if (UnicodeMsg->wParam > 0 &&
281 !WideCharToMultiByte(CP_ACP, 0, Buffer, -1,
282 AnsiBuffer, UnicodeMsg->wParam, NULL, NULL))
283 {
284 AnsiBuffer[UnicodeMsg->wParam - 1] = 0;
285 }
286 break;
287 }
288
289 case WM_GETTEXTLENGTH:
290 case CB_GETLBTEXTLEN:
291 case LB_GETTEXTLEN:
292 {
293 /* FIXME: There may be one DBCS char for each Unicode char */
294 *Result *= 2;
295 break;
296 }
297 }
298
299 MsgiAnsiToUnicodeCleanup(UnicodeMsg, AnsiMsg);
300
301 return TRUE;
302 }
303
304
305 VOID STATIC
306 User32ConvertToAsciiMessage(UINT* Msg, WPARAM* wParam, LPARAM* lParam)
307 {
308 switch((*Msg))
309 {
310 case WM_CREATE:
311 case WM_NCCREATE:
312 {
313 CREATESTRUCTA* CsA;
314 CREATESTRUCTW* CsW;
315 UNICODE_STRING UString;
316 ANSI_STRING AString;
317
318 CsW = (CREATESTRUCTW*)(*lParam);
319 CsA = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(CREATESTRUCTA));
320 memcpy(CsA, CsW, sizeof(CREATESTRUCTW));
321
322 RtlInitUnicodeString(&UString, CsW->lpszName);
323 RtlUnicodeStringToAnsiString(&AString, &UString, TRUE);
324 CsA->lpszName = AString.Buffer;
325 if (HIWORD((ULONG)CsW->lpszClass) != 0)
326 {
327 RtlInitUnicodeString(&UString, CsW->lpszClass);
328 RtlUnicodeStringToAnsiString(&AString, &UString, TRUE);
329 CsA->lpszClass = AString.Buffer;
330 }
331 (*lParam) = (LPARAM)CsA;
332 break;
333 }
334 case WM_SETTEXT:
335 {
336 ANSI_STRING AnsiString;
337 UNICODE_STRING UnicodeString;
338 RtlInitUnicodeString(&UnicodeString, (PWSTR) *lParam);
339 if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
340 &UnicodeString,
341 TRUE)))
342 {
343 *lParam = (LPARAM) AnsiString.Buffer;
344 }
345 break;
346 }
347 }
348 }
349
350
351 VOID STATIC
352 User32FreeAsciiConvertedMessage(UINT Msg, WPARAM wParam, LPARAM lParam)
353 {
354 switch(Msg)
355 {
356 case WM_GETTEXT:
357 {
358 ANSI_STRING AnsiString;
359 UNICODE_STRING UnicodeString;
360 LPSTR TempString;
361 LPSTR InString;
362 InString = (LPSTR)lParam;
363 TempString = RtlAllocateHeap(RtlGetProcessHeap(), 0, strlen(InString) + 1);
364 strcpy(TempString, InString);
365 RtlInitAnsiString(&AnsiString, TempString);
366 UnicodeString.Length = wParam * sizeof(WCHAR);
367 UnicodeString.MaximumLength = wParam * sizeof(WCHAR);
368 UnicodeString.Buffer = (PWSTR)lParam;
369 if (! NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString,
370 &AnsiString,
371 FALSE)))
372 {
373 if (1 <= wParam)
374 {
375 UnicodeString.Buffer[0] = L'\0';
376 }
377 }
378 RtlFreeHeap(RtlGetProcessHeap(), 0, TempString);
379 break;
380 }
381 case WM_SETTEXT:
382 {
383 ANSI_STRING AnsiString;
384 RtlInitAnsiString(&AnsiString, (PSTR) lParam);
385 RtlFreeAnsiString(&AnsiString);
386 break;
387 }
388 case WM_CREATE:
389 case WM_NCCREATE:
390 {
391 CREATESTRUCTA* Cs;
392
393 Cs = (CREATESTRUCTA*)lParam;
394 RtlFreeHeap(RtlGetProcessHeap(), 0, (LPSTR)Cs->lpszName);
395 if (HIWORD((ULONG)Cs->lpszClass) != 0)
396 {
397 RtlFreeHeap(RtlGetProcessHeap(), 0, (LPSTR)Cs->lpszClass);
398 }
399 RtlFreeHeap(RtlGetProcessHeap(), 0, Cs);
400 break;
401 }
402 }
403 }
404
405 LRESULT FASTCALL
406 IntCallWindowProcW(BOOL IsAnsiProc,
407 WNDPROC WndProc,
408 HWND hWnd,
409 UINT Msg,
410 WPARAM wParam,
411 LPARAM lParam)
412 {
413 LRESULT Result;
414
415 if (IsAnsiProc)
416 {
417 User32ConvertToAsciiMessage(&Msg, &wParam, &lParam);
418 Result = WndProc(hWnd, Msg, wParam, lParam);
419 User32FreeAsciiConvertedMessage(Msg, wParam, lParam);
420 return Result;
421 }
422 else
423 {
424 return WndProc(hWnd, Msg, wParam, lParam);
425 }
426 }
427
428 STATIC LRESULT FASTCALL
429 IntCallWindowProcA(BOOL IsAnsiProc,
430 WNDPROC WndProc,
431 HWND hWnd,
432 UINT Msg,
433 WPARAM wParam,
434 LPARAM lParam)
435 {
436 MSG AnsiMsg;
437 MSG UnicodeMsg;
438 LRESULT Result;
439
440 if (IsAnsiProc)
441 {
442 return WndProc(hWnd, Msg, wParam, lParam);
443 }
444 else
445 {
446 AnsiMsg.hwnd = hWnd;
447 AnsiMsg.message = Msg;
448 AnsiMsg.wParam = wParam;
449 AnsiMsg.lParam = lParam;
450 if (! MsgiAnsiToUnicodeMessage(&UnicodeMsg, &AnsiMsg))
451 {
452 return FALSE;
453 }
454 Result = WndProc(UnicodeMsg.hwnd, UnicodeMsg.message,
455 UnicodeMsg.wParam, UnicodeMsg.lParam);
456 if (! MsgiAnsiToUnicodeReply(&UnicodeMsg, &AnsiMsg, &Result))
457 {
458 return FALSE;
459 }
460 return Result;
461 }
462 }
463
464
465 /*
466 * @implemented
467 */
468 LRESULT STDCALL
469 CallWindowProcA(WNDPROC lpPrevWndFunc,
470 HWND hWnd,
471 UINT Msg,
472 WPARAM wParam,
473 LPARAM lParam)
474 {
475 BOOL IsHandle;
476 WndProcHandle wphData;
477
478 IsHandle = NtUserDereferenceWndProcHandle(lpPrevWndFunc,&wphData);
479 if (! IsHandle)
480 {
481 return IntCallWindowProcA(TRUE, lpPrevWndFunc, hWnd, Msg, wParam, lParam);
482 }
483 else
484 {
485 return IntCallWindowProcA(! wphData.IsUnicode, wphData.WindowProc,
486 hWnd, Msg, wParam, lParam);
487 }
488 }
489
490
491 /*
492 * @implemented
493 */
494 LRESULT STDCALL
495 CallWindowProcW(WNDPROC lpPrevWndFunc,
496 HWND hWnd,
497 UINT Msg,
498 WPARAM wParam,
499 LPARAM lParam)
500 {
501 BOOL IsHandle;
502 WndProcHandle wphData;
503
504 IsHandle = NtUserDereferenceWndProcHandle(lpPrevWndFunc,&wphData);
505 if (! IsHandle)
506 {
507 return IntCallWindowProcW(FALSE, lpPrevWndFunc, hWnd, Msg, wParam, lParam);
508 }
509 else
510 {
511 return IntCallWindowProcW(! wphData.IsUnicode, wphData.WindowProc,
512 hWnd, Msg, wParam, lParam);
513 }
514 }
515
516
517 /*
518 * @implemented
519 */
520 LRESULT STDCALL
521 DispatchMessageA(CONST MSG *lpmsg)
522 {
523 return(NtUserDispatchMessage(lpmsg));
524 }
525
526
527 /*
528 * @implemented
529 */
530 LRESULT STDCALL
531 DispatchMessageW(CONST MSG *lpmsg)
532 {
533 return(NtUserDispatchMessage((LPMSG)lpmsg));
534 }
535
536
537 /*
538 * @implemented
539 */
540 BOOL STDCALL
541 GetMessageA(LPMSG lpMsg,
542 HWND hWnd,
543 UINT wMsgFilterMin,
544 UINT wMsgFilterMax)
545 {
546 BOOL Res;
547 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
548
549 Res = NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
550 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
551 {
552 ThreadData->LastMessage = *lpMsg;
553 }
554 return(Res);
555 }
556
557
558 /*
559 * @implemented
560 */
561 BOOL STDCALL
562 GetMessageW(LPMSG lpMsg,
563 HWND hWnd,
564 UINT wMsgFilterMin,
565 UINT wMsgFilterMax)
566 {
567 BOOL Res;
568 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
569
570 Res = NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
571 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
572 {
573 ThreadData->LastMessage = *lpMsg;
574 }
575 return(Res);
576 }
577
578
579 /*
580 * @implemented
581 */
582 BOOL STDCALL
583 PeekMessageA(LPMSG lpMsg,
584 HWND hWnd,
585 UINT wMsgFilterMin,
586 UINT wMsgFilterMax,
587 UINT wRemoveMsg)
588 {
589 BOOL Res;
590 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
591
592 Res = NtUserPeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
593 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
594 {
595 ThreadData->LastMessage = *lpMsg;
596 }
597 return(Res);
598 }
599
600
601 /*
602 * @implemented
603 */
604 BOOL
605 STDCALL
606 PeekMessageW(
607 LPMSG lpMsg,
608 HWND hWnd,
609 UINT wMsgFilterMin,
610 UINT wMsgFilterMax,
611 UINT wRemoveMsg)
612 {
613 BOOL Res;
614 PUSER32_THREAD_DATA ThreadData = User32GetThreadData();
615
616 Res = NtUserPeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
617 if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT)
618 {
619 ThreadData->LastMessage = *lpMsg;
620 }
621 return(Res);
622 }
623
624
625 /*
626 * @implemented
627 */
628 BOOL
629 STDCALL
630 PostMessageA(
631 HWND hWnd,
632 UINT Msg,
633 WPARAM wParam,
634 LPARAM lParam)
635 {
636 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
637 }
638
639
640 /*
641 * @implemented
642 */
643 BOOL
644 STDCALL
645 PostMessageW(
646 HWND hWnd,
647 UINT Msg,
648 WPARAM wParam,
649 LPARAM lParam)
650 {
651 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
652 }
653
654
655 /*
656 * @implemented
657 */
658 VOID
659 STDCALL
660 PostQuitMessage(
661 int nExitCode)
662 {
663 (void) NtUserPostMessage(NULL, WM_QUIT, nExitCode, 0);
664 }
665
666
667 /*
668 * @implemented
669 */
670 BOOL
671 STDCALL
672 PostThreadMessageA(
673 DWORD idThread,
674 UINT Msg,
675 WPARAM wParam,
676 LPARAM lParam)
677 {
678 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
679 }
680
681
682 /*
683 * @implemented
684 */
685 BOOL
686 STDCALL
687 PostThreadMessageW(
688 DWORD idThread,
689 UINT Msg,
690 WPARAM wParam,
691 LPARAM lParam)
692 {
693 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
694 }
695
696
697 /*
698 * @implemented
699 */
700 LRESULT STDCALL
701 SendMessageW(HWND Wnd,
702 UINT Msg,
703 WPARAM wParam,
704 LPARAM lParam)
705 {
706 NTUSERSENDMESSAGEINFO Info;
707 LRESULT Result;
708
709 Info.Ansi = FALSE;
710 Result = NtUserSendMessage(Wnd, Msg, wParam, lParam, &Info);
711 if (! Info.HandledByKernel)
712 {
713 /* We need to send the message ourselves */
714 Result = IntCallWindowProcW(Info.Ansi, Info.Proc, Wnd, Msg, wParam, lParam);
715 }
716
717 return Result;
718 }
719
720
721 /*
722 * @implemented
723 */
724 LRESULT STDCALL
725 SendMessageA(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
726 {
727 MSG AnsiMsg;
728 MSG UcMsg;
729 LRESULT Result;
730 NTUSERSENDMESSAGEINFO Info;
731
732 AnsiMsg.hwnd = Wnd;
733 AnsiMsg.message = Msg;
734 AnsiMsg.wParam = wParam;
735 AnsiMsg.lParam = lParam;
736 if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg))
737 {
738 return FALSE;
739 }
740
741 Info.Ansi = TRUE;
742 Result = NtUserSendMessage(UcMsg.hwnd, UcMsg.message,
743 UcMsg.wParam, UcMsg.lParam, &Info);
744 if (! Info.HandledByKernel)
745 {
746 /* We need to send the message ourselves */
747 if (Info.Ansi)
748 {
749 /* Ansi message and Ansi window proc, that's easy. Clean up
750 the Unicode message though */
751 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
752 Result = IntCallWindowProcA(Info.Ansi, Info.Proc, Wnd, Msg, wParam, lParam);
753 }
754 else
755 {
756 /* Unicode winproc. Although we started out with an Ansi message we
757 already converted it to Unicode for the kernel call. Reuse that
758 message to avoid another conversion */
759 Result = IntCallWindowProcW(Info.Ansi, Info.Proc, UcMsg.hwnd,
760 UcMsg.message, UcMsg.wParam, UcMsg.lParam);
761 if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
762 {
763 return FALSE;
764 }
765 }
766 }
767 else
768 {
769 /* Message sent by kernel. Convert back to Ansi */
770 if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
771 {
772 return FALSE;
773 }
774 }
775
776 return Result;
777 }
778
779
780 /*
781 * @implemented
782 */
783 BOOL
784 STDCALL
785 SendMessageCallbackA(
786 HWND hWnd,
787 UINT Msg,
788 WPARAM wParam,
789 LPARAM lParam,
790 SENDASYNCPROC lpCallBack,
791 ULONG_PTR dwData)
792 {
793 return NtUserSendMessageCallback(
794 hWnd,
795 Msg,
796 wParam,
797 lParam,
798 lpCallBack,
799 dwData);
800 }
801
802
803 /*
804 * @implemented
805 */
806 BOOL
807 STDCALL
808 SendMessageCallbackW(
809 HWND hWnd,
810 UINT Msg,
811 WPARAM wParam,
812 LPARAM lParam,
813 SENDASYNCPROC lpCallBack,
814 ULONG_PTR dwData)
815 {
816 return NtUserSendMessageCallback(
817 hWnd,
818 Msg,
819 wParam,
820 lParam,
821 lpCallBack,
822 dwData);
823 }
824
825
826 /*
827 * @implemented
828 */
829 LRESULT
830 STDCALL
831 SendMessageTimeoutA(
832 HWND hWnd,
833 UINT Msg,
834 WPARAM wParam,
835 LPARAM lParam,
836 UINT fuFlags,
837 UINT uTimeout,
838 PDWORD_PTR lpdwResult)
839 {
840 MSG AnsiMsg;
841 MSG UcMsg;
842 LRESULT Result;
843 NTUSERSENDMESSAGEINFO Info;
844
845 AnsiMsg.hwnd = hWnd;
846 AnsiMsg.message = Msg;
847 AnsiMsg.wParam = wParam;
848 AnsiMsg.lParam = lParam;
849 if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg))
850 {
851 return FALSE;
852 }
853
854 Info.Ansi = TRUE;
855 Result = NtUserSendMessageTimeout(UcMsg.hwnd, UcMsg.message,
856 UcMsg.wParam, UcMsg.lParam,
857 fuFlags, uTimeout, (ULONG_PTR*)lpdwResult, &Info);
858 if(!Result)
859 {
860 return FALSE;
861 }
862 if (! Info.HandledByKernel)
863 {
864 /* We need to send the message ourselves */
865 if (Info.Ansi)
866 {
867 /* Ansi message and Ansi window proc, that's easy. Clean up
868 the Unicode message though */
869 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
870 Result = IntCallWindowProcA(Info.Ansi, Info.Proc, hWnd, Msg, wParam, lParam);
871 }
872 else
873 {
874 /* Unicode winproc. Although we started out with an Ansi message we
875 already converted it to Unicode for the kernel call. Reuse that
876 message to avoid another conversion */
877 Result = IntCallWindowProcW(Info.Ansi, Info.Proc, UcMsg.hwnd,
878 UcMsg.message, UcMsg.wParam, UcMsg.lParam);
879 if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
880 {
881 return FALSE;
882 }
883 }
884 if(lpdwResult)
885 *lpdwResult = Result;
886 Result = TRUE;
887 }
888 else
889 {
890 /* Message sent by kernel. Convert back to Ansi */
891 if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
892 {
893 return FALSE;
894 }
895 }
896
897 return Result;
898 }
899
900
901 /*
902 * @implemented
903 */
904 LRESULT
905 STDCALL
906 SendMessageTimeoutW(
907 HWND hWnd,
908 UINT Msg,
909 WPARAM wParam,
910 LPARAM lParam,
911 UINT fuFlags,
912 UINT uTimeout,
913 PDWORD_PTR lpdwResult)
914 {
915 NTUSERSENDMESSAGEINFO Info;
916 LRESULT Result;
917
918 Info.Ansi = FALSE;
919 Result = NtUserSendMessageTimeout(hWnd, Msg, wParam, lParam, fuFlags, uTimeout,
920 lpdwResult, &Info);
921 if (! Info.HandledByKernel)
922 {
923 /* We need to send the message ourselves */
924 Result = IntCallWindowProcW(Info.Ansi, Info.Proc, hWnd, Msg, wParam, lParam);
925 if(lpdwResult)
926 *lpdwResult = Result;
927 return TRUE;
928 }
929
930 return Result;
931 }
932
933
934 /*
935 * @unimplemented
936 */
937 BOOL
938 STDCALL
939 SendNotifyMessageA(
940 HWND hWnd,
941 UINT Msg,
942 WPARAM wParam,
943 LPARAM lParam)
944 {
945 UNIMPLEMENTED;
946 return FALSE;
947 }
948
949
950 /*
951 * @unimplemented
952 */
953 BOOL
954 STDCALL
955 SendNotifyMessageW(
956 HWND hWnd,
957 UINT Msg,
958 WPARAM wParam,
959 LPARAM lParam)
960 {
961 UNIMPLEMENTED;
962 return FALSE;
963 }
964
965
966 /*
967 * @implemented
968 */
969 BOOL STDCALL
970 TranslateMessage(CONST MSG *lpMsg)
971 {
972 return(TranslateMessageEx((LPMSG)lpMsg, 0));
973 }
974
975 /*
976 * @implemented
977 */
978 BOOL STDCALL
979 TranslateMessageEx(CONST MSG *lpMsg, DWORD unk)
980 {
981 return(NtUserTranslateMessage((LPMSG)lpMsg, (HKL)unk));
982 }
983
984
985 /*
986 * @implemented
987 */
988 BOOL
989 STDCALL
990 WaitMessage(VOID)
991 {
992 return NtUserWaitMessage();
993 }
994
995
996 /*
997 * @implemented
998 */
999 UINT STDCALL
1000 RegisterWindowMessageA(LPCSTR lpString)
1001 {
1002 UNICODE_STRING String;
1003 BOOLEAN Result;
1004 UINT Atom;
1005
1006 Result = RtlCreateUnicodeStringFromAsciiz(&String, (PCSZ)lpString);
1007 if (!Result)
1008 {
1009 return(0);
1010 }
1011 Atom = NtUserRegisterWindowMessage(&String);
1012 RtlFreeUnicodeString(&String);
1013 return(Atom);
1014 }
1015
1016
1017 /*
1018 * @implemented
1019 */
1020 UINT STDCALL
1021 RegisterWindowMessageW(LPCWSTR lpString)
1022 {
1023 UNICODE_STRING String;
1024
1025 RtlInitUnicodeString(&String, lpString);
1026 return(NtUserRegisterWindowMessage(&String));
1027 }
1028
1029 /*
1030 * @implemented
1031 */
1032 HWND STDCALL
1033 SetCapture(HWND hWnd)
1034 {
1035 return(NtUserSetCapture(hWnd));
1036 }
1037
1038 /*
1039 * @implemented
1040 */
1041 HWND STDCALL
1042 GetCapture(VOID)
1043 {
1044 return(NtUserGetCapture());
1045 }
1046
1047 /*
1048 * @implemented
1049 */
1050 BOOL STDCALL
1051 ReleaseCapture(VOID)
1052 {
1053 NtUserSetCapture(NULL);
1054 return(TRUE);
1055 }
1056
1057
1058 /*
1059 * @unimplemented
1060 */
1061 DWORD
1062 STDCALL
1063 RealGetQueueStatus(UINT flags)
1064 {
1065 DWORD ret;
1066 WORD changed_bits, wake_bits;
1067
1068 #if 0 /* wine stuff. don't know what it does... */
1069
1070 /* check for pending X events */
1071 if (USER_Driver.pMsgWaitForMultipleObjectsEx)
1072 USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
1073 #endif
1074
1075 ret = NtUserGetQueueStatus(TRUE /*ClearChanges*/);
1076
1077 changed_bits = LOWORD(ret);
1078 wake_bits = HIWORD(ret);
1079
1080 return MAKELONG(changed_bits & flags, wake_bits & flags);
1081 }
1082
1083
1084 /*
1085 * @unimplemented
1086 */
1087 BOOL STDCALL GetInputState(VOID)
1088 {
1089 DWORD ret;
1090 WORD wake_bits;
1091
1092 #if 0 /* wine stuff. don't know what it does... */
1093
1094 /* check for pending X events */
1095 if (USER_Driver.pMsgWaitForMultipleObjectsEx)
1096 USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
1097 #endif
1098
1099 ret = NtUserGetQueueStatus(FALSE /*ClearChanges*/);
1100
1101 wake_bits = HIWORD(ret);
1102
1103 return wake_bits & (QS_KEY | QS_MOUSEBUTTON);
1104 }
1105
1106 /*
1107 * @implemented
1108 */
1109 BOOL STDCALL SetMessageQueue(int cMessagesMax)
1110 {
1111 /* Function does nothing on 32 bit windows */
1112 return TRUE;
1113 }
1114 typedef DWORD (WINAPI * RealGetQueueStatusProc)(UINT flags);
1115 typedef DWORD (WINAPI * RealMsgWaitForMultipleObjectsExProc)(DWORD nCount, LPHANDLE lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags);
1116
1117 typedef struct _USER_MESSAGE_PUMP_ADDRESSES {
1118 DWORD cbSize;
1119 //NtUserRealInternalGetMessageProc NtUserRealInternalGetMessage;
1120 //NtUserRealWaitMessageExProc NtUserRealWaitMessageEx;
1121 RealGetQueueStatusProc RealGetQueueStatus;
1122 RealMsgWaitForMultipleObjectsExProc RealMsgWaitForMultipleObjectsEx;
1123 } USER_MESSAGE_PUMP_ADDRESSES, * PUSER_MESSAGE_PUMP_ADDRESSES;
1124
1125 DWORD
1126 STDCALL
1127 RealMsgWaitForMultipleObjectsEx(
1128 DWORD nCount,
1129 LPHANDLE pHandles,
1130 DWORD dwMilliseconds,
1131 DWORD dwWakeMask,
1132 DWORD dwFlags);
1133
1134 typedef BOOL (WINAPI * MESSAGEPUMPHOOKPROC)(BOOL Unregistering,PUSER_MESSAGE_PUMP_ADDRESSES MessagePumpAddresses);
1135
1136 RTL_CRITICAL_SECTION gcsMPH;
1137 MESSAGEPUMPHOOKPROC gpfnInitMPH;
1138 DWORD gcLoadMPH = 0;
1139 USER_MESSAGE_PUMP_ADDRESSES gmph = {sizeof(USER_MESSAGE_PUMP_ADDRESSES),
1140 //NtUserRealInternalGetMessage,
1141 //NtUserRealInternalWaitMessageEx,
1142 RealGetQueueStatus,
1143 RealMsgWaitForMultipleObjectsEx
1144 };
1145
1146 DWORD gfMessagePumpHook = 0;
1147
1148 BOOL WINAPI IsInsideMessagePumpHook()
1149 {
1150 if(!gfMessagePumpHook)
1151 return FALSE;
1152
1153 /* Since our TEB doesnt match that of real windows, testing this value is useless until we know what it does
1154 PUCHAR NtTeb = (PUCHAR)NtCurrentTeb();
1155
1156 if(!*(PLONG*)&NtTeb[0x708])
1157 return FALSE;
1158
1159 if(**(PLONG*)&NtTeb[0x708] <= 0)
1160 return FALSE;*/
1161
1162 return TRUE;
1163 }
1164
1165 void WINAPI ResetMessagePumpHook(PUSER_MESSAGE_PUMP_ADDRESSES Addresses)
1166 {
1167 Addresses->cbSize = sizeof(USER_MESSAGE_PUMP_ADDRESSES);
1168 //Addresses->NtUserRealInternalGetMessage = (NtUserRealInternalGetMessageProc)NtUserRealInternalGetMessage;
1169 //Addresses->NtUserRealWaitMessageEx = (NtUserRealWaitMessageExProc)NtUserRealInternalWaitMessageEx;
1170 Addresses->RealGetQueueStatus = RealGetQueueStatus;
1171 Addresses->RealMsgWaitForMultipleObjectsEx = RealMsgWaitForMultipleObjectsEx;
1172 }
1173
1174 BOOL WINAPI RegisterMessagePumpHook(MESSAGEPUMPHOOKPROC Hook)
1175 {
1176 RtlEnterCriticalSection(&gcsMPH);
1177 if(!Hook) {
1178 SetLastError(ERROR_INVALID_PARAMETER);
1179 RtlLeaveCriticalSection(&gcsMPH);
1180 return FALSE;
1181 }
1182 if(!gcLoadMPH) {
1183 USER_MESSAGE_PUMP_ADDRESSES Addresses;
1184 gpfnInitMPH = Hook;
1185 ResetMessagePumpHook(&Addresses);
1186 if(!Hook(FALSE, &Addresses) || !Addresses.cbSize) {
1187 RtlLeaveCriticalSection(&gcsMPH);
1188 return FALSE;
1189 }
1190 memcpy(&gmph, &Addresses, Addresses.cbSize);
1191 } else {
1192 if(gpfnInitMPH != Hook) {
1193 RtlLeaveCriticalSection(&gcsMPH);
1194 return FALSE;
1195 }
1196 }
1197 if(NtUserCallNoParam(NOPARAM_ROUTINE_INIT_MESSAGE_PUMP)) {
1198 RtlLeaveCriticalSection(&gcsMPH);
1199 return FALSE;
1200 }
1201 if (!gcLoadMPH++) {
1202 InterlockedExchange(&gfMessagePumpHook, 1);
1203 }
1204 RtlLeaveCriticalSection(&gcsMPH);
1205 return TRUE;
1206 }
1207
1208 BOOL WINAPI UnregisterMessagePumpHook(VOID)
1209 {
1210 RtlEnterCriticalSection(&gcsMPH);
1211 if(gcLoadMPH > 0) {
1212 if(NtUserCallNoParam(NOPARAM_ROUTINE_UNINIT_MESSAGE_PUMP)) {
1213 gcLoadMPH--;
1214 if(!gcLoadMPH) {
1215 InterlockedExchange(&gfMessagePumpHook, 0);
1216 gpfnInitMPH(TRUE, NULL);
1217 ResetMessagePumpHook(&gmph);
1218 gpfnInitMPH = 0;
1219 }
1220 RtlLeaveCriticalSection(&gcsMPH);
1221 return TRUE;
1222 }
1223 }
1224 RtlLeaveCriticalSection(&gcsMPH);
1225 return FALSE;
1226 }
1227
1228 DWORD WINAPI GetQueueStatus(UINT flags)
1229 {
1230 return IsInsideMessagePumpHook() ? gmph.RealGetQueueStatus(flags) : RealGetQueueStatus(flags);
1231 }
1232
1233 DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD nCount, LPHANDLE lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags)
1234 {
1235 return IsInsideMessagePumpHook() ? gmph.RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags) : RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags);
1236 }