1 /* $Id: message.c,v 1.33 2004/01/23 23:38:26 ekohl Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS user32.dll
5 * FILE: lib/user32/windows/message.c
7 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * 06-06-2001 CSH Created
21 GetMessageExtraInfo(VOID
)
23 return (LPARAM
)NtUserCallNoParam(NOPARAM_ROUTINE_GETMESSAGEEXTRAINFO
);
34 PUSER32_THREAD_DATA ThreadData
= User32GetThreadData();
35 return(MAKELONG(ThreadData
->LastMessage
.pt
.x
, ThreadData
->LastMessage
.pt
.y
));
45 PUSER32_THREAD_DATA ThreadData
= User32GetThreadData();
46 return(ThreadData
->LastMessage
.time
);
95 return (LPARAM
)NtUserCallOneParam((DWORD
)lParam
, ONEPARAM_ROUTINE_SETMESSAGEEXTRAINFO
);
100 MsgiAnsiToUnicodeMessage(LPMSG UnicodeMsg
, LPMSG AnsiMsg
)
102 *UnicodeMsg
= *AnsiMsg
;
103 switch (AnsiMsg
->message
)
106 case WM_ASKCBFORMATNAME
:
108 LPWSTR Buffer
= HeapAlloc(GetProcessHeap(), 0,
109 AnsiMsg
->wParam
* sizeof(WCHAR
));
114 UnicodeMsg
->lParam
= (LPARAM
)Buffer
;
118 /* AnsiMsg->lParam is string (0-terminated) */
120 case WM_WININICHANGE
:
121 case WM_DEVMODECHANGE
:
127 UNICODE_STRING UnicodeString
;
128 RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)AnsiMsg
->lParam
);
129 UnicodeMsg
->lParam
= (LPARAM
)UnicodeString
.Buffer
;
136 UNICODE_STRING UnicodeBuffer
;
139 CREATESTRUCTW cs
; /* new structure */
140 LPCWSTR lpszName
; /* allocated Name */
141 LPCWSTR lpszClass
; /* allocated Class */
143 struct s
*xs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct s
));
148 xs
->cs
= *(CREATESTRUCTW
*)AnsiMsg
->lParam
;
149 if (HIWORD(xs
->cs
.lpszName
))
151 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer
, (LPSTR
)xs
->cs
.lpszName
);
152 xs
->lpszName
= xs
->cs
.lpszName
= UnicodeBuffer
.Buffer
;
154 if (HIWORD(xs
->cs
.lpszClass
))
156 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer
, (LPSTR
)xs
->cs
.lpszClass
);
157 xs
->lpszClass
= xs
->cs
.lpszClass
= UnicodeBuffer
.Buffer
;
159 UnicodeMsg
->lParam
= (LPARAM
)xs
;
165 UNICODE_STRING UnicodeBuffer
;
166 MDICREATESTRUCTW
*cs
=
167 (MDICREATESTRUCTW
*)HeapAlloc(GetProcessHeap(), 0, sizeof(*cs
));
174 *cs
= *(MDICREATESTRUCTW
*)AnsiMsg
->lParam
;
176 if (HIWORD(cs
->szClass
))
178 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer
, (LPSTR
)cs
->szClass
);
179 cs
->szClass
= UnicodeBuffer
.Buffer
;
182 RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer
, (LPSTR
)cs
->szTitle
);
183 cs
->szTitle
= UnicodeBuffer
.Buffer
;
185 UnicodeMsg
->lParam
= (LPARAM
)cs
;
195 MsgiAnsiToUnicodeCleanup(LPMSG UnicodeMsg
, LPMSG AnsiMsg
)
197 switch (AnsiMsg
->message
)
200 case WM_ASKCBFORMATNAME
:
202 HeapFree(GetProcessHeap(), 0, (PVOID
) UnicodeMsg
->lParam
);
207 case WM_WININICHANGE
:
208 case WM_DEVMODECHANGE
:
214 UNICODE_STRING UnicodeString
;
215 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)UnicodeMsg
->lParam
);
216 RtlFreeUnicodeString(&UnicodeString
);
223 UNICODE_STRING UnicodeString
;
226 CREATESTRUCTW cs
; /* new structure */
227 LPWSTR lpszName
; /* allocated Name */
228 LPWSTR lpszClass
; /* allocated Class */
230 struct s
*xs
= (struct s
*)UnicodeMsg
->lParam
;
233 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)xs
->lpszName
);
234 RtlFreeUnicodeString(&UnicodeString
);
238 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)xs
->lpszClass
);
239 RtlFreeUnicodeString(&UnicodeString
);
241 HeapFree(GetProcessHeap(), 0, xs
);
247 UNICODE_STRING UnicodeString
;
248 MDICREATESTRUCTW
*cs
= (MDICREATESTRUCTW
*)UnicodeMsg
->lParam
;
249 if (HIWORD(cs
->szTitle
))
251 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)cs
->szTitle
);
252 RtlFreeUnicodeString(&UnicodeString
);
254 if (HIWORD(cs
->szClass
))
256 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)cs
->szClass
);
257 RtlFreeUnicodeString(&UnicodeString
);
259 HeapFree(GetProcessHeap(), 0, cs
);
268 MsgiAnsiToUnicodeReply(LPMSG UnicodeMsg
, LPMSG AnsiMsg
, LRESULT
*Result
)
270 switch (AnsiMsg
->message
)
273 case WM_ASKCBFORMATNAME
:
275 LPWSTR Buffer
= (LPWSTR
)UnicodeMsg
->lParam
;
276 LPSTR AnsiBuffer
= (LPSTR
)AnsiMsg
->lParam
;
277 if (UnicodeMsg
->wParam
> 0 &&
278 !WideCharToMultiByte(CP_ACP
, 0, Buffer
, -1,
279 AnsiBuffer
, UnicodeMsg
->wParam
, NULL
, NULL
))
281 AnsiBuffer
[UnicodeMsg
->wParam
- 1] = 0;
286 case WM_GETTEXTLENGTH
:
287 case CB_GETLBTEXTLEN
:
290 /* FIXME: There may be one DBCS char for each Unicode char */
296 MsgiAnsiToUnicodeCleanup(UnicodeMsg
, AnsiMsg
);
303 User32ConvertToAsciiMessage(UINT
* Msg
, WPARAM
* wParam
, LPARAM
* lParam
)
312 UNICODE_STRING UString
;
315 CsW
= (CREATESTRUCTW
*)(*lParam
);
316 CsA
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(CREATESTRUCTA
));
317 memcpy(CsA
, CsW
, sizeof(CREATESTRUCTW
));
319 RtlInitUnicodeString(&UString
, CsW
->lpszName
);
320 RtlUnicodeStringToAnsiString(&AString
, &UString
, TRUE
);
321 CsA
->lpszName
= AString
.Buffer
;
322 if (HIWORD((ULONG
)CsW
->lpszClass
) != 0)
324 RtlInitUnicodeString(&UString
, CsW
->lpszClass
);
325 RtlUnicodeStringToAnsiString(&AString
, &UString
, TRUE
);
326 CsA
->lpszClass
= AString
.Buffer
;
328 (*lParam
) = (LPARAM
)CsA
;
333 ANSI_STRING AnsiString
;
334 UNICODE_STRING UnicodeString
;
335 RtlInitUnicodeString(&UnicodeString
, (PWSTR
) *lParam
);
336 if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString
,
340 *lParam
= (LPARAM
) AnsiString
.Buffer
;
349 User32FreeAsciiConvertedMessage(UINT Msg
, WPARAM wParam
, LPARAM lParam
)
355 ANSI_STRING AnsiString
;
356 UNICODE_STRING UnicodeString
;
359 InString
= (LPSTR
)lParam
;
360 TempString
= RtlAllocateHeap(RtlGetProcessHeap(), 0, strlen(InString
) + 1);
361 strcpy(TempString
, InString
);
362 RtlInitAnsiString(&AnsiString
, TempString
);
363 UnicodeString
.Length
= wParam
* sizeof(WCHAR
);
364 UnicodeString
.MaximumLength
= wParam
* sizeof(WCHAR
);
365 UnicodeString
.Buffer
= (PWSTR
)lParam
;
366 if (! NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString
,
372 UnicodeString
.Buffer
[0] = L
'\0';
375 RtlFreeHeap(RtlGetProcessHeap(), 0, TempString
);
380 ANSI_STRING AnsiString
;
381 RtlInitAnsiString(&AnsiString
, (PSTR
) lParam
);
382 RtlFreeAnsiString(&AnsiString
);
390 Cs
= (CREATESTRUCTA
*)lParam
;
391 RtlFreeHeap(RtlGetProcessHeap(), 0, (LPSTR
)Cs
->lpszName
);
392 if (HIWORD((ULONG
)Cs
->lpszClass
) != 0)
394 RtlFreeHeap(RtlGetProcessHeap(), 0, (LPSTR
)Cs
->lpszClass
);
396 RtlFreeHeap(RtlGetProcessHeap(), 0, Cs
);
403 IntCallWindowProcW(BOOL IsAnsiProc
,
414 User32ConvertToAsciiMessage(&Msg
, &wParam
, &lParam
);
415 Result
= WndProc(hWnd
, Msg
, wParam
, lParam
);
416 User32FreeAsciiConvertedMessage(Msg
, wParam
, lParam
);
421 return WndProc(hWnd
, Msg
, wParam
, lParam
);
425 STATIC LRESULT FASTCALL
426 IntCallWindowProcA(BOOL IsAnsiProc
,
439 return WndProc(hWnd
, Msg
, wParam
, lParam
);
444 AnsiMsg
.message
= Msg
;
445 AnsiMsg
.wParam
= wParam
;
446 AnsiMsg
.lParam
= lParam
;
447 if (! MsgiAnsiToUnicodeMessage(&UnicodeMsg
, &AnsiMsg
))
451 Result
= WndProc(UnicodeMsg
.hwnd
, UnicodeMsg
.message
,
452 UnicodeMsg
.wParam
, UnicodeMsg
.lParam
);
453 if (! MsgiAnsiToUnicodeReply(&UnicodeMsg
, &AnsiMsg
, &Result
))
466 CallWindowProcA(WNDPROC lpPrevWndFunc
,
473 WndProcHandle wphData
;
475 IsHandle
= NtUserDereferenceWndProcHandle(lpPrevWndFunc
,&wphData
);
478 return IntCallWindowProcA(TRUE
, lpPrevWndFunc
, hWnd
, Msg
, wParam
, lParam
);
482 return IntCallWindowProcA(! wphData
.IsUnicode
, wphData
.WindowProc
,
483 hWnd
, Msg
, wParam
, lParam
);
492 CallWindowProcW(WNDPROC lpPrevWndFunc
,
499 WndProcHandle wphData
;
501 IsHandle
= NtUserDereferenceWndProcHandle(lpPrevWndFunc
,&wphData
);
504 return IntCallWindowProcW(FALSE
, lpPrevWndFunc
, hWnd
, Msg
, wParam
, lParam
);
508 return IntCallWindowProcW(! wphData
.IsUnicode
, wphData
.WindowProc
,
509 hWnd
, Msg
, wParam
, lParam
);
518 DispatchMessageA(CONST MSG
*lpmsg
)
520 return(NtUserDispatchMessage(lpmsg
));
528 DispatchMessageW(CONST MSG
*lpmsg
)
530 return(NtUserDispatchMessage((LPMSG
)lpmsg
));
538 GetMessageA(LPMSG lpMsg
,
544 PUSER32_THREAD_DATA ThreadData
= User32GetThreadData();
546 Res
= NtUserGetMessage(lpMsg
, hWnd
, wMsgFilterMin
, wMsgFilterMax
);
547 if (Res
&& lpMsg
->message
!= WM_PAINT
&& lpMsg
->message
!= WM_QUIT
)
549 ThreadData
->LastMessage
= *lpMsg
;
559 GetMessageW(LPMSG lpMsg
,
565 PUSER32_THREAD_DATA ThreadData
= User32GetThreadData();
567 Res
= NtUserGetMessage(lpMsg
, hWnd
, wMsgFilterMin
, wMsgFilterMax
);
568 if (Res
&& lpMsg
->message
!= WM_PAINT
&& lpMsg
->message
!= WM_QUIT
)
570 ThreadData
->LastMessage
= *lpMsg
;
580 PeekMessageA(LPMSG lpMsg
,
587 PUSER32_THREAD_DATA ThreadData
= User32GetThreadData();
589 Res
= NtUserPeekMessage(lpMsg
, hWnd
, wMsgFilterMin
, wMsgFilterMax
, wRemoveMsg
);
590 if (Res
&& lpMsg
->message
!= WM_PAINT
&& lpMsg
->message
!= WM_QUIT
)
592 ThreadData
->LastMessage
= *lpMsg
;
611 PUSER32_THREAD_DATA ThreadData
= User32GetThreadData();
613 Res
= NtUserPeekMessage(lpMsg
, hWnd
, wMsgFilterMin
, wMsgFilterMax
, wRemoveMsg
);
614 if (Res
&& lpMsg
->message
!= WM_PAINT
&& lpMsg
->message
!= WM_QUIT
)
616 ThreadData
->LastMessage
= *lpMsg
;
633 return NtUserPostMessage(hWnd
, Msg
, wParam
, lParam
);
648 return NtUserPostMessage(hWnd
, Msg
, wParam
, lParam
);
660 (void) NtUserPostMessage(NULL
, WM_QUIT
, nExitCode
, 0);
675 return NtUserPostThreadMessage(idThread
, Msg
, wParam
, lParam
);
690 return NtUserPostThreadMessage(idThread
, Msg
, wParam
, lParam
);
698 SendMessageW(HWND Wnd
,
703 NTUSERSENDMESSAGEINFO Info
;
706 Result
= NtUserSendMessage(Wnd
, Msg
, wParam
, lParam
, &Info
);
707 if (! Info
.HandledByKernel
)
709 /* We need to send the message ourselves */
710 Result
= IntCallWindowProcW(Info
.Ansi
, Info
.Proc
, Wnd
, Msg
, wParam
, lParam
);
721 SendMessageA(HWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
726 NTUSERSENDMESSAGEINFO Info
;
729 AnsiMsg
.message
= Msg
;
730 AnsiMsg
.wParam
= wParam
;
731 AnsiMsg
.lParam
= lParam
;
732 if (! MsgiAnsiToUnicodeMessage(&UcMsg
, &AnsiMsg
))
737 Result
= NtUserSendMessage(UcMsg
.hwnd
, UcMsg
.message
,
738 UcMsg
.wParam
, UcMsg
.lParam
, &Info
);
739 if (! Info
.HandledByKernel
)
741 /* We need to send the message ourselves */
744 /* Ansi message and Ansi window proc, that's easy. Clean up
745 the Unicode message though */
746 MsgiAnsiToUnicodeCleanup(&UcMsg
, &AnsiMsg
);
747 Result
= IntCallWindowProcA(Info
.Ansi
, Info
.Proc
, Wnd
, Msg
, wParam
, lParam
);
751 /* Unicode winproc. Although we started out with an Ansi message we
752 already converted it to Unicode for the kernel call. Reuse that
753 message to avoid another conversion */
754 Result
= IntCallWindowProcW(Info
.Ansi
, Info
.Proc
, UcMsg
.hwnd
,
755 UcMsg
.message
, UcMsg
.wParam
, UcMsg
.lParam
);
756 if (! MsgiAnsiToUnicodeReply(&UcMsg
, &AnsiMsg
, &Result
))
764 /* Message sent by kernel. Convert back to Ansi */
765 if (! MsgiAnsiToUnicodeReply(&UcMsg
, &AnsiMsg
, &Result
))
780 SendMessageCallbackA(
785 SENDASYNCPROC lpCallBack
,
788 return NtUserSendMessageCallback(
803 SendMessageCallbackW(
808 SENDASYNCPROC lpCallBack
,
811 return NtUserSendMessageCallback(
833 PDWORD_PTR lpdwResult
)
852 PDWORD_PTR lpdwResult
)
895 TranslateMessage(CONST MSG
*lpMsg
)
897 return(TranslateMessageEx((LPMSG
)lpMsg
, 0));
904 TranslateMessageEx(CONST MSG
*lpMsg
, DWORD unk
)
906 return(NtUserTranslateMessage((LPMSG
)lpMsg
, (HKL
)unk
));
917 return NtUserWaitMessage();
925 RegisterWindowMessageA(LPCSTR lpString
)
927 UNICODE_STRING String
;
931 Result
= RtlCreateUnicodeStringFromAsciiz(&String
, (PCSZ
)lpString
);
936 Atom
= NtUserRegisterWindowMessage(&String
);
937 RtlFreeUnicodeString(&String
);
946 RegisterWindowMessageW(LPCWSTR lpString
)
948 UNICODE_STRING String
;
950 RtlInitUnicodeString(&String
, lpString
);
951 return(NtUserRegisterWindowMessage(&String
));
958 SetCapture(HWND hWnd
)
960 return(NtUserSetCapture(hWnd
));
969 return(NtUserGetCapture());
978 NtUserSetCapture(NULL
);
988 RealGetQueueStatus(UINT flags
)
991 WORD changed_bits
, wake_bits
;
993 #if 0 /* wine stuff. don't know what it does... */
995 /* check for pending X events */
996 if (USER_Driver
.pMsgWaitForMultipleObjectsEx
)
997 USER_Driver
.pMsgWaitForMultipleObjectsEx( 0, NULL
, 0, 0, 0 );
1000 ret
= NtUserGetQueueStatus(TRUE
/*ClearChanges*/);
1002 changed_bits
= LOWORD(ret
);
1003 wake_bits
= HIWORD(ret
);
1005 return MAKELONG(changed_bits
& flags
, wake_bits
& flags
);
1012 BOOL STDCALL
GetInputState(VOID
)
1017 #if 0 /* wine stuff. don't know what it does... */
1019 /* check for pending X events */
1020 if (USER_Driver
.pMsgWaitForMultipleObjectsEx
)
1021 USER_Driver
.pMsgWaitForMultipleObjectsEx( 0, NULL
, 0, 0, 0 );
1024 ret
= NtUserGetQueueStatus(FALSE
/*ClearChanges*/);
1026 wake_bits
= HIWORD(ret
);
1028 return wake_bits
& (QS_KEY
| QS_MOUSEBUTTON
);
1034 BOOL STDCALL
SetMessageQueue(int cMessagesMax
)
1036 /* Function does nothing on 32 bit windows */
1039 typedef DWORD (WINAPI
* RealGetQueueStatusProc
)(UINT flags
);
1040 typedef DWORD (WINAPI
* RealMsgWaitForMultipleObjectsExProc
)(DWORD nCount
, LPHANDLE lpHandles
, DWORD dwMilliseconds
, DWORD dwWakeMask
, DWORD dwFlags
);
1042 typedef struct _USER_MESSAGE_PUMP_ADDRESSES
{
1044 //NtUserRealInternalGetMessageProc NtUserRealInternalGetMessage;
1045 //NtUserRealWaitMessageExProc NtUserRealWaitMessageEx;
1046 RealGetQueueStatusProc RealGetQueueStatus
;
1047 RealMsgWaitForMultipleObjectsExProc RealMsgWaitForMultipleObjectsEx
;
1048 } USER_MESSAGE_PUMP_ADDRESSES
, * PUSER_MESSAGE_PUMP_ADDRESSES
;
1052 RealMsgWaitForMultipleObjectsEx(
1055 DWORD dwMilliseconds
,
1059 typedef BOOL (WINAPI
* MESSAGEPUMPHOOKPROC
)(BOOL Unregistering
,PUSER_MESSAGE_PUMP_ADDRESSES MessagePumpAddresses
);
1061 RTL_CRITICAL_SECTION gcsMPH
;
1062 MESSAGEPUMPHOOKPROC gpfnInitMPH
;
1063 DWORD gcLoadMPH
= 0;
1064 USER_MESSAGE_PUMP_ADDRESSES gmph
= {sizeof(USER_MESSAGE_PUMP_ADDRESSES
),
1065 //NtUserRealInternalGetMessage,
1066 //NtUserRealInternalWaitMessageEx,
1068 RealMsgWaitForMultipleObjectsEx
1071 DWORD gfMessagePumpHook
= 0;
1073 BOOL WINAPI
IsInsideMessagePumpHook()
1075 if(!gfMessagePumpHook
)
1078 /* Since our TEB doesnt match that of real windows, testing this value is useless until we know what it does
1079 PUCHAR NtTeb = (PUCHAR)NtCurrentTeb();
1081 if(!*(PLONG*)&NtTeb[0x708])
1084 if(**(PLONG*)&NtTeb[0x708] <= 0)
1090 void WINAPI
ResetMessagePumpHook(PUSER_MESSAGE_PUMP_ADDRESSES Addresses
)
1092 Addresses
->cbSize
= sizeof(USER_MESSAGE_PUMP_ADDRESSES
);
1093 //Addresses->NtUserRealInternalGetMessage = (NtUserRealInternalGetMessageProc)NtUserRealInternalGetMessage;
1094 //Addresses->NtUserRealWaitMessageEx = (NtUserRealWaitMessageExProc)NtUserRealInternalWaitMessageEx;
1095 Addresses
->RealGetQueueStatus
= RealGetQueueStatus
;
1096 Addresses
->RealMsgWaitForMultipleObjectsEx
= RealMsgWaitForMultipleObjectsEx
;
1099 BOOL WINAPI
RegisterMessagePumpHook(MESSAGEPUMPHOOKPROC Hook
)
1101 RtlEnterCriticalSection(&gcsMPH
);
1103 SetLastError(ERROR_INVALID_PARAMETER
);
1104 RtlLeaveCriticalSection(&gcsMPH
);
1108 USER_MESSAGE_PUMP_ADDRESSES Addresses
;
1110 ResetMessagePumpHook(&Addresses
);
1111 if(!Hook(FALSE
, &Addresses
) || !Addresses
.cbSize
) {
1112 RtlLeaveCriticalSection(&gcsMPH
);
1115 memcpy(&gmph
, &Addresses
, Addresses
.cbSize
);
1117 if(gpfnInitMPH
!= Hook
) {
1118 RtlLeaveCriticalSection(&gcsMPH
);
1122 if(NtUserCallNoParam(NOPARAM_ROUTINE_INIT_MESSAGE_PUMP
)) {
1123 RtlLeaveCriticalSection(&gcsMPH
);
1127 InterlockedExchange(&gfMessagePumpHook
, 1);
1129 RtlLeaveCriticalSection(&gcsMPH
);
1133 BOOL WINAPI
UnregisterMessagePumpHook(VOID
)
1135 RtlEnterCriticalSection(&gcsMPH
);
1137 if(NtUserCallNoParam(NOPARAM_ROUTINE_UNINIT_MESSAGE_PUMP
)) {
1140 InterlockedExchange(&gfMessagePumpHook
, 0);
1141 gpfnInitMPH(TRUE
, NULL
);
1142 ResetMessagePumpHook(&gmph
);
1145 RtlLeaveCriticalSection(&gcsMPH
);
1149 RtlLeaveCriticalSection(&gcsMPH
);
1153 DWORD WINAPI
GetQueueStatus(UINT flags
)
1155 return IsInsideMessagePumpHook() ? gmph
.RealGetQueueStatus(flags
) : RealGetQueueStatus(flags
);
1158 DWORD WINAPI
MsgWaitForMultipleObjectsEx(DWORD nCount
, LPHANDLE lpHandles
, DWORD dwMilliseconds
, DWORD dwWakeMask
, DWORD dwFlags
)
1160 return IsInsideMessagePumpHook() ? gmph
.RealMsgWaitForMultipleObjectsEx(nCount
, lpHandles
,dwMilliseconds
, dwWakeMask
, dwFlags
) : RealMsgWaitForMultipleObjectsEx(nCount
, lpHandles
,dwMilliseconds
, dwWakeMask
, dwFlags
);