X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Flib%2Fuser32%2Fwindows%2Fmessage.c;h=31693089148afcb0d5e9bdeb3940f2e127b9d4fe;hp=26b950d2365813edb1f01ac9413eef8b0d860b7b;hb=edda3b622fc1fd1de1e781d09b3366d13a3c8a82;hpb=f1694d4913c084ab959759dc9ff81bdaafd46fb8 diff --git a/reactos/lib/user32/windows/message.c b/reactos/lib/user32/windows/message.c index 26b950d2365..31693089148 100644 --- a/reactos/lib/user32/windows/message.c +++ b/reactos/lib/user32/windows/message.c @@ -1,5 +1,4 @@ -/* $Id: message.c,v 1.5 2002/05/06 22:20:31 dwelch Exp $ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS user32.dll * FILE: lib/user32/windows/message.c @@ -8,76 +7,1237 @@ * UPDATE HISTORY: * 06-06-2001 CSH Created */ -#include + #include +#define NDEBUG #include +/* DDE message exchange + * + * - Session initialization + * Client sends a WM_DDE_INITIATE message, usually a broadcast message. lParam of + * this message contains a pair of global atoms, the Application and Topic atoms. + * The client must destroy the atoms. + * Server window proc handles the WM_DDE_INITIATE message and if the Application + * and Topic atoms are recognized sends a WM_DDE_ACK message to the client. lParam + * of the reply message contains another pair of global atoms (Application and + * Topic again), which must be destroyed by the server. + * + * - Execute + * Client posts a WM_DDE_EXECUTE message to the server window. lParam of that message + * is a global memory handle containing the string to execute. After the command has + * been executed the server posts a WM_DDE_ACK message to the client, which contains + * a packed lParam which in turn contains that global memory handle. The client takes + * ownership of both the packed lParam (meaning it needs to call FreeDDElParam() on + * it and the global memory handle. + * This might work nice and easy in Win3.1, but things are more complicated for NT. + * Global memory handles in NT are not really global, they're still local to the + * process. So, what happens under the hood is that PostMessage must handle the + * WM_DDE_EXECUTE message specially. It will obtain the contents of the global memory + * area, repack that into a new structure together with the original memory handle + * and pass that off to the win32k. Win32k will marshall that data over to the target + * (server) process where it will be unpacked and stored in a newly allocated global + * memory area. The handle of that area will then be sent to the window proc, after + * storing it together with the "original" (client) handle in a table. + * The server will eventually post the WM_DDE_ACK response, containing the global + * memory handle it received. PostMessage must then lookup that memory handle (only + * valid in the server process) and replace it with the corresponding client memory + * handle. To avoid memory leaks, the server-side global memory block must be freed. + * Also, the WM_DDE_ACK lParam (a PackDDElParam() result) is unpacked and the + * individual components are handed to win32k.sys to post to the client side. Since + * the server side app hands over ownership of the packed lParam when it calls + * PostMessage(), the packed lParam needs to be freed on the server side too. + * When the WM_DDE_ACK message (containing the client-side global memory handle) + * arrives at the client side a new lParam is PackDDElParam()'ed and this is handed + * to the client side window proc which is expected to free/reuse it. + */ + +/* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle + * to the memory handle, we keep track (in the server side) of all pairs of handle + * used (the client passes its value and the content of the memory handle), and + * the server stored both values (the client, and the local one, created after the + * content). When a ACK message is generated, the list of pair is searched for a + * matching pair, so that the client memory handle can be returned. + */ +typedef struct tagDDEPAIR +{ + HGLOBAL ClientMem; + HGLOBAL ServerMem; +} DDEPAIR, *PDDEPAIR; + +static PDDEPAIR DdePairs = NULL; +static unsigned DdeNumAlloc = 0; +static unsigned DdeNumUsed = 0; +static CRITICAL_SECTION DdeCrst; -LPMSG -MsgiAnsiToUnicodeMessage( - LPMSG AnsiMsg, - LPMSG UnicodeMsg) +static BOOL FASTCALL +DdeAddPair(HGLOBAL ClientMem, HGLOBAL ServerMem) { - /* FIXME: Convert */ - RtlMoveMemory(UnicodeMsg, AnsiMsg, sizeof(MSG)); + unsigned i; - return UnicodeMsg; + EnterCriticalSection(&DdeCrst); + + /* now remember the pair of hMem on both sides */ + if (DdeNumUsed == DdeNumAlloc) + { +#define GROWBY 4 + PDDEPAIR New; + if (NULL != DdePairs) + { + New = HeapReAlloc(GetProcessHeap(), 0, DdePairs, + (DdeNumAlloc + GROWBY) * sizeof(DDEPAIR)); + } + else + { + New = HeapAlloc(GetProcessHeap(), 0, + (DdeNumAlloc + GROWBY) * sizeof(DDEPAIR)); + } + + if (NULL == New) + { + LeaveCriticalSection(&DdeCrst); + return FALSE; + } + DdePairs = New; + /* zero out newly allocated part */ + memset(&DdePairs[DdeNumAlloc], 0, GROWBY * sizeof(DDEPAIR)); + DdeNumAlloc += GROWBY; +#undef GROWBY + } + + for (i = 0; i < DdeNumAlloc; i++) + { + if (NULL == DdePairs[i].ServerMem) + { + DdePairs[i].ClientMem = ClientMem; + DdePairs[i].ServerMem = ServerMem; + DdeNumUsed++; + break; + } + } + LeaveCriticalSection(&DdeCrst); + + return TRUE; } +static HGLOBAL FASTCALL +DdeGetPair(HGLOBAL ServerMem) +{ + unsigned i; + HGLOBAL Ret = NULL; -LRESULT + EnterCriticalSection(&DdeCrst); + for (i = 0; i < DdeNumAlloc; i++) + { + if (DdePairs[i].ServerMem == ServerMem) + { + /* free this pair */ + DdePairs[i].ServerMem = 0; + DdeNumUsed--; + Ret = DdePairs[i].ClientMem; + break; + } + } + LeaveCriticalSection(&DdeCrst); + + return Ret; +} + +static BOOL FASTCALL +MsgiUMToKMMessage(PMSG UMMsg, PMSG KMMsg, BOOL Posted) +{ + *KMMsg = *UMMsg; + + switch (UMMsg->message) + { + case WM_DDE_ACK: + { + PKMDDELPARAM DdeLparam; + DdeLparam = HeapAlloc(GetProcessHeap(), 0, sizeof(KMDDELPARAM)); + if (NULL == DdeLparam) + { + return FALSE; + } + if (Posted) + { + DdeLparam->Packed = TRUE; + if (! UnpackDDElParam(UMMsg->message, UMMsg->lParam, + &DdeLparam->Value.Packed.uiLo, + &DdeLparam->Value.Packed.uiHi)) + { + return FALSE; + } + if (0 != HIWORD(DdeLparam->Value.Packed.uiHi)) + { + /* uiHi should contain a hMem from WM_DDE_EXECUTE */ + HGLOBAL h = DdeGetPair((HGLOBAL) DdeLparam->Value.Packed.uiHi); + if (NULL != h) + { + GlobalFree((HGLOBAL) DdeLparam->Value.Packed.uiHi); + DdeLparam->Value.Packed.uiHi = (UINT) h; + } + } + FreeDDElParam(UMMsg->message, UMMsg->lParam); + } + else + { + DdeLparam->Packed = FALSE; + DdeLparam->Value.Unpacked = UMMsg->lParam; + } + KMMsg->lParam = (LPARAM) DdeLparam; + } + break; + + case WM_DDE_EXECUTE: + { + SIZE_T Size; + PKMDDEEXECUTEDATA KMDdeExecuteData; + PVOID Data; + + Size = GlobalSize((HGLOBAL) UMMsg->lParam); + Data = GlobalLock((HGLOBAL) UMMsg->lParam); + if (NULL == Data) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + KMDdeExecuteData = HeapAlloc(GetProcessHeap(), 0, sizeof(KMDDEEXECUTEDATA) + Size); + if (NULL == KMDdeExecuteData) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + KMDdeExecuteData->Sender = (HWND) UMMsg->wParam; + KMDdeExecuteData->ClientMem = (HGLOBAL) UMMsg->lParam; + memcpy((PVOID) (KMDdeExecuteData + 1), Data, Size); + KMMsg->wParam = sizeof(KMDDEEXECUTEDATA) + Size; + KMMsg->lParam = (LPARAM) KMDdeExecuteData; + GlobalUnlock((HGLOBAL) UMMsg->lParam); + } + break; + + case WM_COPYDATA: + { + PCOPYDATASTRUCT pUMCopyData = (PCOPYDATASTRUCT)UMMsg->lParam; + PCOPYDATASTRUCT pKMCopyData; + + pKMCopyData = HeapAlloc(GetProcessHeap(), 0, + sizeof(COPYDATASTRUCT) + pUMCopyData->cbData); + if (pKMCopyData == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + pKMCopyData->dwData = pUMCopyData->dwData; + pKMCopyData->cbData = pUMCopyData->cbData; + pKMCopyData->lpData = pKMCopyData + 1; + + RtlCopyMemory(pKMCopyData + 1, pUMCopyData->lpData, + pUMCopyData->cbData); + + KMMsg->lParam = (LPARAM)pKMCopyData; + } + break; + + default: + break; + } + + return TRUE; +} + +static VOID FASTCALL +MsgiUMToKMCleanup(PMSG UMMsg, PMSG KMMsg) +{ + switch (KMMsg->message) + { + case WM_DDE_ACK: + case WM_DDE_EXECUTE: + case WM_COPYDATA: + HeapFree(GetProcessHeap(), 0, (LPVOID) KMMsg->lParam); + break; + default: + break; + } + + return; +} + +static BOOL FASTCALL +MsgiUMToKMReply(PMSG UMMsg, PMSG KMMsg, LRESULT *Result) +{ + MsgiUMToKMCleanup(UMMsg, KMMsg); + + return TRUE; +} + +static BOOL FASTCALL +MsgiKMToUMMessage(PMSG KMMsg, PMSG UMMsg) +{ + *UMMsg = *KMMsg; + + switch (UMMsg->message) + { + case WM_CREATE: + case WM_NCCREATE: + { + CREATESTRUCTW *Cs = (CREATESTRUCTW *) KMMsg->lParam; + PCHAR Class; + Cs->lpszName = (LPCWSTR) ((PCHAR) Cs + (DWORD_PTR) Cs->lpszName); + Class = (PCHAR) Cs + (DWORD_PTR) Cs->lpszClass; + if (L'A' == *((WCHAR *) Class)) + { + Class += sizeof(WCHAR); + Cs->lpszClass = (LPCWSTR)(DWORD_PTR) (*((ATOM *) Class)); + } + else + { + ASSERT(L'S' == *((WCHAR *) Class)); + Class += sizeof(WCHAR); + Cs->lpszClass = (LPCWSTR) Class; + } + } + break; + + case WM_DDE_ACK: + { + PKMDDELPARAM DdeLparam = (PKMDDELPARAM) KMMsg->lParam; + if (DdeLparam->Packed) + { + UMMsg->lParam = PackDDElParam(KMMsg->message, + DdeLparam->Value.Packed.uiLo, + DdeLparam->Value.Packed.uiHi); + } + else + { + UMMsg->lParam = DdeLparam->Value.Unpacked; + } + } + break; + + case WM_DDE_EXECUTE: + { + PKMDDEEXECUTEDATA KMDdeExecuteData; + HGLOBAL GlobalData; + PVOID Data; + + KMDdeExecuteData = (PKMDDEEXECUTEDATA) KMMsg->lParam; + GlobalData = GlobalAlloc(GMEM_MOVEABLE, KMMsg->wParam - sizeof(KMDDEEXECUTEDATA)); + if (NULL == GlobalData) + { + return FALSE; + } + Data = GlobalLock(GlobalData); + if (NULL == Data) + { + GlobalFree(GlobalData); + return FALSE; + } + memcpy(Data, (PVOID) (KMDdeExecuteData + 1), KMMsg->wParam - sizeof(KMDDEEXECUTEDATA)); + GlobalUnlock(GlobalData); + if (! DdeAddPair(KMDdeExecuteData->ClientMem, GlobalData)) + { + GlobalFree(GlobalData); + return FALSE; + } + UMMsg->wParam = (WPARAM) KMDdeExecuteData->Sender; + UMMsg->lParam = (LPARAM) GlobalData; + } + break; + + case WM_COPYDATA: + { + PCOPYDATASTRUCT pKMCopyData = (PCOPYDATASTRUCT)KMMsg->lParam; + pKMCopyData->lpData = pKMCopyData + 1; + } + break; + + default: + break; + } + + return TRUE; +} + +static VOID FASTCALL +MsgiKMToUMCleanup(PMSG KMMsg, PMSG UMMsg) +{ + switch (KMMsg->message) + { + case WM_DDE_EXECUTE: +#ifdef TODO + HeapFree(GetProcessHeap(), 0, (LPVOID) KMMsg->lParam); + GlobalUnlock((HGLOBAL) UMMsg->lParam); +#endif + break; + default: + break; + } + + return; +} + +static BOOL FASTCALL +MsgiKMToUMReply(PMSG KMMsg, PMSG UMMsg, LRESULT *Result) +{ + MsgiKMToUMCleanup(KMMsg, UMMsg); + + return TRUE; +} + +static BOOL FASTCALL +MsgiAnsiToUnicodeMessage(LPMSG UnicodeMsg, LPMSG AnsiMsg) +{ + *UnicodeMsg = *AnsiMsg; + switch (AnsiMsg->message) + { + case WM_GETTEXT: + case WM_ASKCBFORMATNAME: + { + LPWSTR Buffer = HeapAlloc(GetProcessHeap(), 0, + AnsiMsg->wParam * sizeof(WCHAR)); + if (!Buffer) + { + return FALSE; + } + UnicodeMsg->lParam = (LPARAM)Buffer; + break; + } + + /* AnsiMsg->lParam is string (0-terminated) */ + case WM_SETTEXT: + case WM_WININICHANGE: + case WM_DEVMODECHANGE: + case CB_DIR: + case LB_DIR: + case LB_ADDFILE: + case EM_REPLACESEL: + { + UNICODE_STRING UnicodeString; + RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam); + UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer; + break; + } + + case WM_NCCREATE: + case WM_CREATE: + { + UNICODE_STRING UnicodeBuffer; + struct s + { + CREATESTRUCTW cs; /* new structure */ + LPCWSTR lpszName; /* allocated Name */ + LPCWSTR lpszClass; /* allocated Class */ + }; + struct s *xs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct s)); + if (!xs) + { + return FALSE; + } + xs->cs = *(CREATESTRUCTW *)AnsiMsg->lParam; + if (HIWORD(xs->cs.lpszName)) + { + RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)xs->cs.lpszName); + xs->lpszName = xs->cs.lpszName = UnicodeBuffer.Buffer; + } + if (HIWORD(xs->cs.lpszClass)) + { + RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)xs->cs.lpszClass); + xs->lpszClass = xs->cs.lpszClass = UnicodeBuffer.Buffer; + } + UnicodeMsg->lParam = (LPARAM)xs; + break; + } + + case WM_MDICREATE: + { + UNICODE_STRING UnicodeBuffer; + MDICREATESTRUCTW *cs = + (MDICREATESTRUCTW *)HeapAlloc(GetProcessHeap(), 0, sizeof(*cs)); + + if (!cs) + { + return FALSE; + } + + *cs = *(MDICREATESTRUCTW *)AnsiMsg->lParam; + + if (HIWORD(cs->szClass)) + { + RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)cs->szClass); + cs->szClass = UnicodeBuffer.Buffer; + } + + RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)cs->szTitle); + cs->szTitle = UnicodeBuffer.Buffer; + + UnicodeMsg->lParam = (LPARAM)cs; + break; + } + } + + return TRUE; +} + + +static BOOL FASTCALL +MsgiAnsiToUnicodeCleanup(LPMSG UnicodeMsg, LPMSG AnsiMsg) +{ + switch (AnsiMsg->message) + { + case WM_GETTEXT: + case WM_ASKCBFORMATNAME: + { + HeapFree(GetProcessHeap(), 0, (PVOID) UnicodeMsg->lParam); + break; + } + + case WM_SETTEXT: + case WM_WININICHANGE: + case WM_DEVMODECHANGE: + case CB_DIR: + case LB_DIR: + case LB_ADDFILE: + case EM_REPLACESEL: + { + UNICODE_STRING UnicodeString; + RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam); + RtlFreeUnicodeString(&UnicodeString); + break; + } + + case WM_NCCREATE: + case WM_CREATE: + { + UNICODE_STRING UnicodeString; + struct s + { + CREATESTRUCTW cs; /* new structure */ + LPWSTR lpszName; /* allocated Name */ + LPWSTR lpszClass; /* allocated Class */ + }; + struct s *xs = (struct s *)UnicodeMsg->lParam; + if (xs->lpszName) + { + RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszName); + RtlFreeUnicodeString(&UnicodeString); + } + if (xs->lpszClass) + { + RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszClass); + RtlFreeUnicodeString(&UnicodeString); + } + HeapFree(GetProcessHeap(), 0, xs); + } + break; + + case WM_MDICREATE: + { + UNICODE_STRING UnicodeString; + MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)UnicodeMsg->lParam; + if (HIWORD(cs->szTitle)) + { + RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szTitle); + RtlFreeUnicodeString(&UnicodeString); + } + if (HIWORD(cs->szClass)) + { + RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szClass); + RtlFreeUnicodeString(&UnicodeString); + } + HeapFree(GetProcessHeap(), 0, cs); + } + break; + } + return(TRUE); +} + + +static BOOL FASTCALL +MsgiAnsiToUnicodeReply(LPMSG UnicodeMsg, LPMSG AnsiMsg, LRESULT *Result) +{ + switch (AnsiMsg->message) + { + case WM_GETTEXT: + case WM_ASKCBFORMATNAME: + { + LPWSTR Buffer = (LPWSTR)UnicodeMsg->lParam; + LPSTR AnsiBuffer = (LPSTR)AnsiMsg->lParam; + if (UnicodeMsg->wParam > 0 && + !WideCharToMultiByte(CP_ACP, 0, Buffer, -1, + AnsiBuffer, UnicodeMsg->wParam, NULL, NULL)) + { + AnsiBuffer[UnicodeMsg->wParam - 1] = 0; + } + break; + } + } + + MsgiAnsiToUnicodeCleanup(UnicodeMsg, AnsiMsg); + + return TRUE; +} + + +static BOOL FASTCALL +MsgiUnicodeToAnsiMessage(LPMSG AnsiMsg, LPMSG UnicodeMsg) +{ + *AnsiMsg = *UnicodeMsg; + + switch(UnicodeMsg->message) + { + case WM_CREATE: + case WM_NCCREATE: + { + CREATESTRUCTA* CsA; + CREATESTRUCTW* CsW; + UNICODE_STRING UString; + ANSI_STRING AString; + NTSTATUS Status; + + CsW = (CREATESTRUCTW*)(UnicodeMsg->lParam); + CsA = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(CREATESTRUCTA)); + if (NULL == CsA) + { + return FALSE; + } + memcpy(CsA, CsW, sizeof(CREATESTRUCTW)); + + RtlInitUnicodeString(&UString, CsW->lpszName); + Status = RtlUnicodeStringToAnsiString(&AString, &UString, TRUE); + if (! NT_SUCCESS(Status)) + { + RtlFreeHeap(GetProcessHeap(), 0, CsA); + return FALSE; + } + CsA->lpszName = AString.Buffer; + if (HIWORD((ULONG)CsW->lpszClass) != 0) + { + RtlInitUnicodeString(&UString, CsW->lpszClass); + Status = RtlUnicodeStringToAnsiString(&AString, &UString, TRUE); + if (! NT_SUCCESS(Status)) + { + RtlInitAnsiString(&AString, CsA->lpszName); + RtlFreeAnsiString(&AString); + RtlFreeHeap(GetProcessHeap(), 0, CsA); + return FALSE; + } + CsA->lpszClass = AString.Buffer; + } + AnsiMsg->lParam = (LPARAM)CsA; + break; + } + case WM_GETTEXT: + { + /* Ansi string might contain MBCS chars so we need 2 * the number of chars */ + AnsiMsg->wParam = UnicodeMsg->wParam * 2; + AnsiMsg->lParam = (LPARAM) RtlAllocateHeap(GetProcessHeap(), 0, AnsiMsg->wParam); + if (NULL == (PVOID) AnsiMsg->lParam) + { + return FALSE; + } + break; + } + case WM_SETTEXT: + { + ANSI_STRING AnsiString; + UNICODE_STRING UnicodeString; + RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam); + if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString, + &UnicodeString, + TRUE))) + { + return FALSE; + } + AnsiMsg->lParam = (LPARAM) AnsiString.Buffer; + break; + } + } + + return TRUE; +} + + +static BOOL FASTCALL +MsgiUnicodeToAnsiCleanup(LPMSG AnsiMsg, LPMSG UnicodeMsg) +{ + switch(UnicodeMsg->message) + { + case WM_GETTEXT: + { + RtlFreeHeap(GetProcessHeap(), 0, (PVOID) AnsiMsg->lParam); + break; + } + case WM_SETTEXT: + { + ANSI_STRING AString; + RtlInitAnsiString(&AString, (PSTR) AnsiMsg->lParam); + RtlFreeAnsiString(&AString); + break; + } + case WM_CREATE: + case WM_NCCREATE: + { + CREATESTRUCTA* Cs; + ANSI_STRING AString; + + Cs = (CREATESTRUCTA*) AnsiMsg->lParam; + RtlInitAnsiString(&AString, Cs->lpszName); + RtlFreeAnsiString(&AString); + if (HIWORD((ULONG)Cs->lpszClass) != 0) + { + RtlInitAnsiString(&AString, Cs->lpszClass); + RtlFreeAnsiString(&AString); + } + RtlFreeHeap(GetProcessHeap(), 0, Cs); + break; + } + } + + return TRUE; +} + + +static BOOL FASTCALL +MsgiUnicodeToAnsiReply(LPMSG AnsiMsg, LPMSG UnicodeMsg, LRESULT *Result) +{ + switch (UnicodeMsg->message) + { + case WM_GETTEXT: + case WM_ASKCBFORMATNAME: + { + LPSTR Buffer = (LPSTR) AnsiMsg->lParam; + LPWSTR UBuffer = (LPWSTR) UnicodeMsg->lParam; + if (0 < AnsiMsg->wParam && + ! MultiByteToWideChar(CP_ACP, 0, Buffer, -1, UBuffer, UnicodeMsg->wParam)) + { + UBuffer[UnicodeMsg->wParam - 1] = L'\0'; + } + break; + } + } + + MsgiUnicodeToAnsiCleanup(AnsiMsg, UnicodeMsg); + + return TRUE; +} + +typedef struct tagMSGCONVERSION +{ + BOOL InUse; + BOOL Ansi; + MSG KMMsg; + MSG UnicodeMsg; + MSG AnsiMsg; + PMSG FinalMsg; + ULONG LParamSize; +} MSGCONVERSION, *PMSGCONVERSION; + +static PMSGCONVERSION MsgConversions = NULL; +static unsigned MsgConversionNumAlloc = 0; +static unsigned MsgConversionNumUsed = 0; +static CRITICAL_SECTION MsgConversionCrst; + +static BOOL FASTCALL +MsgConversionAdd(PMSGCONVERSION Conversion) +{ + unsigned i; + + EnterCriticalSection(&MsgConversionCrst); + + if (MsgConversionNumUsed == MsgConversionNumAlloc) + { +#define GROWBY 4 + PMSGCONVERSION New; + if (NULL != MsgConversions) + { + New = HeapReAlloc(GetProcessHeap(), 0, MsgConversions, + (MsgConversionNumAlloc + GROWBY) * sizeof(MSGCONVERSION)); + } + else + { + New = HeapAlloc(GetProcessHeap(), 0, + (MsgConversionNumAlloc + GROWBY) * sizeof(MSGCONVERSION)); + } + + if (NULL == New) + { + LeaveCriticalSection(&MsgConversionCrst); + return FALSE; + } + MsgConversions = New; + /* zero out newly allocated part */ + memset(MsgConversions + MsgConversionNumAlloc, 0, GROWBY * sizeof(MSGCONVERSION)); + MsgConversionNumAlloc += GROWBY; +#undef GROWBY + } + + for (i = 0; i < MsgConversionNumAlloc; i++) + { + if (! MsgConversions[i].InUse) + { + MsgConversions[i] = *Conversion; + MsgConversions[i].InUse = TRUE; + MsgConversionNumUsed++; + break; + } + } + LeaveCriticalSection(&MsgConversionCrst); + + return TRUE; +} + +static void FASTCALL +MsgConversionCleanup(CONST MSG *Msg, BOOL Ansi, BOOL CheckMsgContents, LRESULT *Result) +{ + BOOL Found; + PMSGCONVERSION Conversion; + LRESULT Dummy; + + EnterCriticalSection(&MsgConversionCrst); + for (Conversion = MsgConversions; + Conversion < MsgConversions + MsgConversionNumAlloc; + Conversion++) + { + if (Conversion->InUse && + ((Ansi && Conversion->Ansi) || + (! Ansi && ! Conversion->Ansi))) + { + Found = (Conversion->FinalMsg == Msg); + if (! Found && CheckMsgContents) + { + if (Ansi) + { + Found = (0 == memcmp(Msg, &Conversion->AnsiMsg, sizeof(MSG))); + } + else + { + Found = (0 == memcmp(Msg, &Conversion->UnicodeMsg, sizeof(MSG))); + } + } + if (Found) + { + if (Ansi) + { + MsgiUnicodeToAnsiReply(&Conversion->AnsiMsg, &Conversion->UnicodeMsg, + NULL == Result ? &Dummy : Result); + } + MsgiKMToUMReply(&Conversion->KMMsg, &Conversion->UnicodeMsg, + NULL == Result ? &Dummy : Result); + if (0 != Conversion->LParamSize) + { + NtFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &Conversion->KMMsg.lParam, + &Conversion->LParamSize, MEM_DECOMMIT); + } + Conversion->InUse = FALSE; + MsgConversionNumUsed--; + } + } + } + LeaveCriticalSection(&MsgConversionCrst); +} + +/* + * @implemented + */ +LPARAM STDCALL -DispatchMessageA( - CONST MSG *lpmsg) +GetMessageExtraInfo(VOID) { - MSG Msg; + return (LPARAM)NtUserCallNoParam(NOPARAM_ROUTINE_GETMESSAGEEXTRAINFO); +} + - return NtUserDispatchMessage(MsgiAnsiToUnicodeMessage((LPMSG)lpmsg, &Msg)); +/* + * @implemented + */ +DWORD +STDCALL +GetMessagePos(VOID) +{ + PUSER32_THREAD_DATA ThreadData = User32GetThreadData(); + return(MAKELONG(ThreadData->LastMessage.pt.x, ThreadData->LastMessage.pt.y)); } -LRESULT + +/* + * @implemented + */ +LONG STDCALL +GetMessageTime(VOID) +{ + PUSER32_THREAD_DATA ThreadData = User32GetThreadData(); + return(ThreadData->LastMessage.time); +} + + +/* + * @unimplemented + */ +BOOL STDCALL -DispatchMessageW( - CONST MSG *lpmsg) +InSendMessage(VOID) { - return NtUserDispatchMessage((LPMSG)lpmsg); + static DWORD ShowNotImplemented = TRUE; + if (ShowNotImplemented) + { + DbgPrint("InSendMessage is unimplemented\n"); + ShowNotImplemented = FALSE; + } + /* return(NtUserGetThreadState(THREADSTATE_INSENDMESSAGE) != ISMEX_NOSEND); */ + return FALSE; } -WINBOOL + +/* + * @unimplemented + */ +DWORD STDCALL -GetMessageA( - LPMSG lpMsg, - HWND hWnd, - UINT wMsgFilterMin, - UINT wMsgFilterMax) +InSendMessageEx( + LPVOID lpReserved) +{ + /* return NtUserGetThreadState(THREADSTATE_INSENDMESSAGE); */ + UNIMPLEMENTED; + return 0; +} + + +/* + * @unimplemented + */ +BOOL +STDCALL +ReplyMessage( + LRESULT lResult) +{ + UNIMPLEMENTED; + return FALSE; +} + + +/* + * @implemented + */ +LPARAM +STDCALL +SetMessageExtraInfo( + LPARAM lParam) +{ + return NtUserSetMessageExtraInfo(lParam); +} + +LRESULT FASTCALL +IntCallWindowProcW(BOOL IsAnsiProc, + WNDPROC WndProc, + HWND hWnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam) +{ + MSG AnsiMsg; + MSG UnicodeMsg; + LRESULT Result; + + if (IsAnsiProc) + { + UnicodeMsg.hwnd = hWnd; + UnicodeMsg.message = Msg; + UnicodeMsg.wParam = wParam; + UnicodeMsg.lParam = lParam; + if (! MsgiUnicodeToAnsiMessage(&AnsiMsg, &UnicodeMsg)) + { + return FALSE; + } + Result = WndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam); + if (! MsgiUnicodeToAnsiReply(&AnsiMsg, &UnicodeMsg, &Result)) + { + return FALSE; + } + return Result; + } + else + { + return WndProc(hWnd, Msg, wParam, lParam); + } +} + +static LRESULT FASTCALL +IntCallWindowProcA(BOOL IsAnsiProc, + WNDPROC WndProc, + HWND hWnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam) +{ + MSG AnsiMsg; + MSG UnicodeMsg; + LRESULT Result; + + if (IsAnsiProc) + { + return WndProc(hWnd, Msg, wParam, lParam); + } + else + { + AnsiMsg.hwnd = hWnd; + AnsiMsg.message = Msg; + AnsiMsg.wParam = wParam; + AnsiMsg.lParam = lParam; + if (! MsgiAnsiToUnicodeMessage(&UnicodeMsg, &AnsiMsg)) + { + return FALSE; + } + Result = WndProc(UnicodeMsg.hwnd, UnicodeMsg.message, + UnicodeMsg.wParam, UnicodeMsg.lParam); + if (! MsgiAnsiToUnicodeReply(&UnicodeMsg, &AnsiMsg, &Result)) + { + return FALSE; + } + return Result; + } +} + + +/* + * @implemented + */ +LRESULT STDCALL +CallWindowProcA(WNDPROC lpPrevWndFunc, + HWND hWnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam) +{ + BOOL IsHandle; + WndProcHandle wphData; + + if (lpPrevWndFunc == NULL) + lpPrevWndFunc = (WNDPROC)NtUserGetWindowLong(hWnd, GWL_WNDPROC, FALSE); + + IsHandle = NtUserDereferenceWndProcHandle(lpPrevWndFunc,&wphData); + if (! IsHandle) + { + return IntCallWindowProcA(TRUE, lpPrevWndFunc, hWnd, Msg, wParam, lParam); + } + else + { + return IntCallWindowProcA(! wphData.IsUnicode, wphData.WindowProc, + hWnd, Msg, wParam, lParam); + } +} + + +/* + * @implemented + */ +LRESULT STDCALL +CallWindowProcW(WNDPROC lpPrevWndFunc, + HWND hWnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam) +{ + BOOL IsHandle; + WndProcHandle wphData; + + IsHandle = NtUserDereferenceWndProcHandle(lpPrevWndFunc,&wphData); + if (! IsHandle) + { + return IntCallWindowProcW(FALSE, lpPrevWndFunc, hWnd, Msg, wParam, lParam); + } + else + { + return IntCallWindowProcW(! wphData.IsUnicode, wphData.WindowProc, + hWnd, Msg, wParam, lParam); + } +} + + +/* + * @implemented + */ +LRESULT STDCALL +DispatchMessageA(CONST MSG *lpmsg) +{ + NTUSERDISPATCHMESSAGEINFO Info; + LRESULT Result; + + Info.Ansi = TRUE; + Info.Msg = *lpmsg; + Result = NtUserDispatchMessage(&Info); + if (! Info.HandledByKernel) + { + /* We need to send the message ourselves */ + Result = IntCallWindowProcA(Info.Ansi, Info.Proc, Info.Msg.hwnd, + Info.Msg.message, Info.Msg.wParam, Info.Msg.lParam); + } + MsgConversionCleanup(lpmsg, TRUE, TRUE, &Result); + + return Result; +} + + +/* + * @implemented + */ +LRESULT STDCALL +DispatchMessageW(CONST MSG *lpmsg) +{ + NTUSERDISPATCHMESSAGEINFO Info; + LRESULT Result; + + Info.Ansi = FALSE; + Info.Msg = *lpmsg; + Result = NtUserDispatchMessage(&Info); + if (! Info.HandledByKernel) + { + /* We need to send the message ourselves */ + Result = IntCallWindowProcW(Info.Ansi, Info.Proc, Info.Msg.hwnd, + Info.Msg.message, Info.Msg.wParam, Info.Msg.lParam); + } + MsgConversionCleanup(lpmsg, FALSE, TRUE, &Result); + + return Result; +} + + +/* + * @implemented + */ +BOOL STDCALL +GetMessageA(LPMSG lpMsg, + HWND hWnd, + UINT wMsgFilterMin, + UINT wMsgFilterMax) { - return NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); + BOOL Res; + MSGCONVERSION Conversion; + NTUSERGETMESSAGEINFO Info; + PUSER32_THREAD_DATA ThreadData = User32GetThreadData(); + + MsgConversionCleanup(lpMsg, TRUE, FALSE, NULL); + Res = NtUserGetMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax); + if (-1 == (int) Res) + { + return Res; + } + Conversion.LParamSize = Info.LParamSize; + Conversion.KMMsg = Info.Msg; + + if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg)) + { + return (BOOL) -1; + } + if (! MsgiUnicodeToAnsiMessage(&Conversion.AnsiMsg, &Conversion.UnicodeMsg)) + { + MsgiKMToUMCleanup(&Info.Msg, &Conversion.UnicodeMsg); + return (BOOL) -1; + } + *lpMsg = Conversion.AnsiMsg; + Conversion.Ansi = TRUE; + Conversion.FinalMsg = lpMsg; + MsgConversionAdd(&Conversion); + if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT) + { + ThreadData->LastMessage = Info.Msg; + } + + return Res; } -WINBOOL -STDCALL -GetMessageW( - LPMSG lpMsg, - HWND hWnd, - UINT wMsgFilterMin, - UINT wMsgFilterMax) -{ - return NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); + +/* + * @implemented + */ +BOOL STDCALL +GetMessageW(LPMSG lpMsg, + HWND hWnd, + UINT wMsgFilterMin, + UINT wMsgFilterMax) +{ + BOOL Res; + MSGCONVERSION Conversion; + NTUSERGETMESSAGEINFO Info; + PUSER32_THREAD_DATA ThreadData = User32GetThreadData(); + + MsgConversionCleanup(lpMsg, FALSE, FALSE, NULL); + Res = NtUserGetMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax); + if (-1 == (int) Res) + { + return Res; + } + Conversion.LParamSize = Info.LParamSize; + Conversion.KMMsg = Info.Msg; + + if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg)) + { + return (BOOL) -1; + } + *lpMsg = Conversion.UnicodeMsg; + Conversion.Ansi = FALSE; + Conversion.FinalMsg = lpMsg; + MsgConversionAdd(&Conversion); + if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT) + { + ThreadData->LastMessage = Info.Msg; + } + + return Res; +} + + +/* + * @implemented + */ +BOOL STDCALL +PeekMessageA(LPMSG lpMsg, + HWND hWnd, + UINT wMsgFilterMin, + UINT wMsgFilterMax, + UINT wRemoveMsg) +{ + BOOL Res; + MSGCONVERSION Conversion; + NTUSERGETMESSAGEINFO Info; + PUSER32_THREAD_DATA ThreadData = User32GetThreadData(); + + MsgConversionCleanup(lpMsg, TRUE, FALSE, NULL); + Res = NtUserPeekMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); + if (-1 == (int) Res || ! Res) + { + return Res; + } + Conversion.LParamSize = Info.LParamSize; + Conversion.KMMsg = Info.Msg; + + if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg)) + { + return (BOOL) -1; + } + if (! MsgiUnicodeToAnsiMessage(&Conversion.AnsiMsg, &Conversion.UnicodeMsg)) + { + MsgiKMToUMCleanup(&Info.Msg, &Conversion.UnicodeMsg); + return (BOOL) -1; + } + *lpMsg = Conversion.AnsiMsg; + Conversion.Ansi = TRUE; + Conversion.FinalMsg = lpMsg; + MsgConversionAdd(&Conversion); + if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT) + { + ThreadData->LastMessage = Info.Msg; + } + + return Res; } -WINBOOL -STDCALL -PeekMessageA( - LPMSG lpMsg, - HWND hWnd, - UINT wMsgFilterMin, - UINT wMsgFilterMax, - UINT wRemoveMsg) -{ - return NtUserPeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); -} -WINBOOL +/* + * @implemented + */ +BOOL STDCALL PeekMessageW( LPMSG lpMsg, @@ -86,39 +1246,121 @@ PeekMessageW( UINT wMsgFilterMax, UINT wRemoveMsg) { - return NtUserPeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); + BOOL Res; + MSGCONVERSION Conversion; + NTUSERGETMESSAGEINFO Info; + PUSER32_THREAD_DATA ThreadData = User32GetThreadData(); + + MsgConversionCleanup(lpMsg, FALSE, FALSE, NULL); + Res = NtUserPeekMessage(&Info, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); + if (-1 == (int) Res || ! Res) + { + return Res; + } + Conversion.LParamSize = Info.LParamSize; + Conversion.KMMsg = Info.Msg; + + if (! MsgiKMToUMMessage(&Conversion.KMMsg, &Conversion.UnicodeMsg)) + { + return (BOOL) -1; + } + *lpMsg = Conversion.UnicodeMsg; + Conversion.Ansi = FALSE; + Conversion.FinalMsg = lpMsg; + MsgConversionAdd(&Conversion); + if (Res && lpMsg->message != WM_PAINT && lpMsg->message != WM_QUIT) + { + ThreadData->LastMessage = Info.Msg; + } + + return Res; } -WINBOOL + +/* + * @implemented + */ +BOOL STDCALL PostMessageA( - HWND hWnd, + HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) { - return NtUserPostMessage(hWnd, Msg, wParam, lParam); + MSG AnsiMsg, UcMsg; + MSG KMMsg; + LRESULT Result; + + AnsiMsg.hwnd = Wnd; + AnsiMsg.message = Msg; + AnsiMsg.wParam = wParam; + AnsiMsg.lParam = lParam; + if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg)) + { + return FALSE; + } + + if (! MsgiUMToKMMessage(&UcMsg, &KMMsg, TRUE)) + { + MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg); + return FALSE; + } + Result = NtUserPostMessage(KMMsg.hwnd, KMMsg.message, + KMMsg.wParam, KMMsg.lParam); + MsgiUMToKMCleanup(&UcMsg, &KMMsg); + MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg); + + return Result; } -WINBOOL + +/* + * @implemented + */ +BOOL STDCALL PostMessageW( - HWND hWnd, + HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) { - return NtUserPostMessage(hWnd, Msg, wParam, lParam); + MSG UMMsg, KMMsg; + LRESULT Result; + + UMMsg.hwnd = Wnd; + UMMsg.message = Msg; + UMMsg.wParam = wParam; + UMMsg.lParam = lParam; + if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, TRUE)) + { + return FALSE; + } + Result = NtUserPostMessage(KMMsg.hwnd, KMMsg.message, + KMMsg.wParam, KMMsg.lParam); + MsgiUMToKMCleanup(&UMMsg, &KMMsg); + + return Result; } + +/* + * @implemented + */ VOID STDCALL PostQuitMessage( int nExitCode) { + (void) NtUserPostMessage(NULL, WM_QUIT, nExitCode, 0); } -WINBOOL + +/* + * @implemented + */ +BOOL STDCALL PostThreadMessageA( DWORD idThread, @@ -129,7 +1371,11 @@ PostThreadMessageA( return NtUserPostThreadMessage(idThread, Msg, wParam, lParam); } -WINBOOL + +/* + * @implemented + */ +BOOL STDCALL PostThreadMessageW( DWORD idThread, @@ -140,18 +1386,114 @@ PostThreadMessageW( return NtUserPostThreadMessage(idThread, Msg, wParam, lParam); } -LRESULT -STDCALL -SendMessageA( - HWND hWnd, - UINT Msg, - WPARAM wParam, - LPARAM lParam) + +/* + * @implemented + */ +LRESULT STDCALL +SendMessageW(HWND Wnd, + UINT Msg, + WPARAM wParam, + LPARAM lParam) +{ + MSG UMMsg, KMMsg; + NTUSERSENDMESSAGEINFO Info; + LRESULT Result; + + UMMsg.hwnd = Wnd; + UMMsg.message = Msg; + UMMsg.wParam = wParam; + UMMsg.lParam = lParam; + if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, FALSE)) + { + return FALSE; + } + Info.Ansi = FALSE; + Result = NtUserSendMessage(KMMsg.hwnd, KMMsg.message, + KMMsg.wParam, KMMsg.lParam, &Info); + if (! Info.HandledByKernel) + { + MsgiUMToKMCleanup(&UMMsg, &KMMsg); + /* We need to send the message ourselves */ + Result = IntCallWindowProcW(Info.Ansi, Info.Proc, UMMsg.hwnd, UMMsg.message, + UMMsg.wParam, UMMsg.lParam); + } + else if (! MsgiUMToKMReply(&UMMsg, &KMMsg, &Result)) + { + return FALSE; + } + + return Result; +} + + +/* + * @implemented + */ +LRESULT STDCALL +SendMessageA(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) { - return (LRESULT)0; + MSG AnsiMsg, UcMsg; + MSG KMMsg; + LRESULT Result; + NTUSERSENDMESSAGEINFO Info; + + AnsiMsg.hwnd = Wnd; + AnsiMsg.message = Msg; + AnsiMsg.wParam = wParam; + AnsiMsg.lParam = lParam; + if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg)) + { + return FALSE; + } + + if (! MsgiUMToKMMessage(&UcMsg, &KMMsg, FALSE)) + { + MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg); + return FALSE; + } + Info.Ansi = TRUE; + Result = NtUserSendMessage(KMMsg.hwnd, KMMsg.message, + KMMsg.wParam, KMMsg.lParam, &Info); + if (! Info.HandledByKernel) + { + /* We need to send the message ourselves */ + if (Info.Ansi) + { + /* Ansi message and Ansi window proc, that's easy. Clean up + the Unicode message though */ + MsgiUMToKMCleanup(&UcMsg, &KMMsg); + MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg); + Result = IntCallWindowProcA(Info.Ansi, Info.Proc, Wnd, Msg, wParam, lParam); + } + else + { + /* Unicode winproc. Although we started out with an Ansi message we + already converted it to Unicode for the kernel call. Reuse that + message to avoid another conversion */ + Result = IntCallWindowProcW(Info.Ansi, Info.Proc, UcMsg.hwnd, + UcMsg.message, UcMsg.wParam, UcMsg.lParam); + if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result)) + { + return FALSE; + } + } + } + /* Message sent by kernel. Convert back to Ansi */ + else if (! MsgiUMToKMReply(&UcMsg, &KMMsg, &Result) || + ! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result)) + { + return FALSE; + } + + return Result; } -WINBOOL + +/* + * @implemented + */ +BOOL STDCALL SendMessageCallbackA( HWND hWnd, @@ -170,7 +1512,11 @@ SendMessageCallbackA( dwData); } -WINBOOL + +/* + * @implemented + */ +BOOL STDCALL SendMessageCallbackW( HWND hWnd, @@ -189,6 +1535,10 @@ SendMessageCallbackW( dwData); } + +/* + * @implemented + */ LRESULT STDCALL SendMessageTimeoutA( @@ -200,9 +1550,70 @@ SendMessageTimeoutA( UINT uTimeout, PDWORD_PTR lpdwResult) { - return (LRESULT)0; + MSG AnsiMsg; + MSG UcMsg; + LRESULT Result; + NTUSERSENDMESSAGEINFO Info; + + AnsiMsg.hwnd = hWnd; + AnsiMsg.message = Msg; + AnsiMsg.wParam = wParam; + AnsiMsg.lParam = lParam; + if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg)) + { + return FALSE; + } + + Info.Ansi = TRUE; + Result = NtUserSendMessageTimeout(UcMsg.hwnd, UcMsg.message, + UcMsg.wParam, UcMsg.lParam, + fuFlags, uTimeout, (ULONG_PTR*)lpdwResult, &Info); + if(!Result) + { + return FALSE; + } + if (! Info.HandledByKernel) + { + /* We need to send the message ourselves */ + if (Info.Ansi) + { + /* Ansi message and Ansi window proc, that's easy. Clean up + the Unicode message though */ + MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg); + Result = IntCallWindowProcA(Info.Ansi, Info.Proc, hWnd, Msg, wParam, lParam); + } + else + { + /* Unicode winproc. Although we started out with an Ansi message we + already converted it to Unicode for the kernel call. Reuse that + message to avoid another conversion */ + Result = IntCallWindowProcW(Info.Ansi, Info.Proc, UcMsg.hwnd, + UcMsg.message, UcMsg.wParam, UcMsg.lParam); + if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result)) + { + return FALSE; + } + } + if(lpdwResult) + *lpdwResult = Result; + Result = TRUE; + } + else + { + /* Message sent by kernel. Convert back to Ansi */ + if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result)) + { + return FALSE; + } + } + + return Result; } + +/* + * @implemented + */ LRESULT STDCALL SendMessageTimeoutW( @@ -214,22 +1625,29 @@ SendMessageTimeoutW( UINT uTimeout, PDWORD_PTR lpdwResult) { - return (LRESULT)0; -} + NTUSERSENDMESSAGEINFO Info; + LRESULT Result; + Info.Ansi = FALSE; + Result = NtUserSendMessageTimeout(hWnd, Msg, wParam, lParam, fuFlags, uTimeout, + lpdwResult, &Info); + if (! Info.HandledByKernel) + { + /* We need to send the message ourselves */ + Result = IntCallWindowProcW(Info.Ansi, Info.Proc, hWnd, Msg, wParam, lParam); + if(lpdwResult) + *lpdwResult = Result; + return TRUE; + } -LRESULT -STDCALL -SendMessageW( - HWND hWnd, - UINT Msg, - WPARAM wParam, - LPARAM lParam) -{ - return (LRESULT)0; + return Result; } -WINBOOL + +/* + * @unimplemented + */ +BOOL STDCALL SendNotifyMessageA( HWND hWnd, @@ -237,10 +1655,15 @@ SendNotifyMessageA( WPARAM wParam, LPARAM lParam) { + UNIMPLEMENTED; return FALSE; } -WINBOOL + +/* + * @unimplemented + */ +BOOL STDCALL SendNotifyMessageW( HWND hWnd, @@ -248,24 +1671,45 @@ SendNotifyMessageW( WPARAM wParam, LPARAM lParam) { + UNIMPLEMENTED; return FALSE; } -WINBOOL -STDCALL -TranslateMessage( - CONST MSG *lpMsg) + +/* + * @implemented + */ +BOOL STDCALL +TranslateMessageEx(CONST MSG *lpMsg, DWORD unk) +{ + return(NtUserTranslateMessage((LPMSG)lpMsg, (HKL)unk)); +} + + +/* + * @implemented + */ +BOOL STDCALL +TranslateMessage(CONST MSG *lpMsg) { - return NtUserTranslateMessage((LPMSG)lpMsg, 0); + return(TranslateMessageEx((LPMSG)lpMsg, 0)); } -WINBOOL + +/* + * @implemented + */ +BOOL STDCALL WaitMessage(VOID) { - return FALSE; + return NtUserWaitMessage(); } + +/* + * @implemented + */ UINT STDCALL RegisterWindowMessageA(LPCSTR lpString) { @@ -273,21 +1717,460 @@ RegisterWindowMessageA(LPCSTR lpString) BOOLEAN Result; UINT Atom; - Result = RtlCreateUnicodeStringFromAsciiz(&String, lpString); + Result = RtlCreateUnicodeStringFromAsciiz(&String, (PCSZ)lpString); if (!Result) { return(0); } - Atom = RegisterWindowMessageW(String.Buffer); + Atom = NtUserRegisterWindowMessage(&String); RtlFreeUnicodeString(&String); return(Atom); } + +/* + * @implemented + */ UINT STDCALL RegisterWindowMessageW(LPCWSTR lpString) { - return(NtUserRegisterWindowMessage(lpString)); + UNICODE_STRING String; + + RtlInitUnicodeString(&String, lpString); + return(NtUserRegisterWindowMessage(&String)); +} + +/* + * @implemented + */ +HWND STDCALL +SetCapture(HWND hWnd) +{ + return(NtUserSetCapture(hWnd)); +} + +/* + * @implemented + */ +HWND STDCALL +GetCapture(VOID) +{ + return(NtUserGetCapture()); +} + +/* + * @implemented + */ +BOOL STDCALL +ReleaseCapture(VOID) +{ + NtUserSetCapture(NULL); + return(TRUE); +} + + +/* + * @unimplemented + */ +DWORD +STDCALL +RealGetQueueStatus(UINT flags) +{ + DWORD ret; + WORD changed_bits, wake_bits; + +#if 0 /* wine stuff. don't know what it does... */ + + /* check for pending X events */ + if (USER_Driver.pMsgWaitForMultipleObjectsEx) + USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 ); +#endif + + ret = NtUserGetQueueStatus(TRUE /*ClearChanges*/); + + changed_bits = LOWORD(ret); + wake_bits = HIWORD(ret); + + return MAKELONG(changed_bits & flags, wake_bits & flags); +} + + +/* + * @unimplemented + */ +BOOL STDCALL GetInputState(VOID) +{ + DWORD ret; + WORD wake_bits; + +#if 0 /* wine stuff. don't know what it does... */ + + /* check for pending X events */ + if (USER_Driver.pMsgWaitForMultipleObjectsEx) + USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 ); +#endif + + ret = NtUserGetQueueStatus(FALSE /*ClearChanges*/); + + wake_bits = HIWORD(ret); + + return wake_bits & (QS_KEY | QS_MOUSEBUTTON); +} + + +NTSTATUS STDCALL +User32CallWindowProcFromKernel(PVOID Arguments, ULONG ArgumentLength) +{ + PWINDOWPROC_CALLBACK_ARGUMENTS CallbackArgs; + MSG KMMsg, UMMsg; + + /* Make sure we don't try to access mem beyond what we were given */ + if (ArgumentLength < sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + + CallbackArgs = (PWINDOWPROC_CALLBACK_ARGUMENTS) Arguments; + KMMsg.hwnd = CallbackArgs->Wnd; + KMMsg.message = CallbackArgs->Msg; + KMMsg.wParam = CallbackArgs->wParam; + /* Check if lParam is really a pointer and adjust it if it is */ + if (0 <= CallbackArgs->lParamBufferSize) + { + if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS) + + CallbackArgs->lParamBufferSize) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + KMMsg.lParam = (LPARAM) ((char *) CallbackArgs + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)); + } + else + { + if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + KMMsg.lParam = CallbackArgs->lParam; + } + + if (WM_NCCALCSIZE == CallbackArgs->Msg && CallbackArgs->wParam) + { + NCCALCSIZE_PARAMS *Params = (NCCALCSIZE_PARAMS *) KMMsg.lParam; + Params->lppos = (PWINDOWPOS) (Params + 1); + } + + if (! MsgiKMToUMMessage(&KMMsg, &UMMsg)) + { + } + + CallbackArgs->Result = IntCallWindowProcW(CallbackArgs->IsAnsiProc, CallbackArgs->Proc, + UMMsg.hwnd, UMMsg.message, + UMMsg.wParam, UMMsg.lParam); + + if (! MsgiKMToUMReply(&KMMsg, &UMMsg, &CallbackArgs->Result)) + { + } + + return ZwCallbackReturn(CallbackArgs, ArgumentLength, STATUS_SUCCESS); +} + +/* + * @implemented + */ +BOOL STDCALL SetMessageQueue(int cMessagesMax) +{ + /* Function does nothing on 32 bit windows */ + return TRUE; +} +typedef DWORD (WINAPI * RealGetQueueStatusProc)(UINT flags); +typedef DWORD (WINAPI * RealMsgWaitForMultipleObjectsExProc)(DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags); + +typedef struct _USER_MESSAGE_PUMP_ADDRESSES { + DWORD cbSize; + //NtUserRealInternalGetMessageProc NtUserRealInternalGetMessage; + //NtUserRealWaitMessageExProc NtUserRealWaitMessageEx; + RealGetQueueStatusProc RealGetQueueStatus; + RealMsgWaitForMultipleObjectsExProc RealMsgWaitForMultipleObjectsEx; +} USER_MESSAGE_PUMP_ADDRESSES, * PUSER_MESSAGE_PUMP_ADDRESSES; + +DWORD +STDCALL +RealMsgWaitForMultipleObjectsEx( + DWORD nCount, + CONST HANDLE *pHandles, + DWORD dwMilliseconds, + DWORD dwWakeMask, + DWORD dwFlags); + +typedef BOOL (WINAPI * MESSAGEPUMPHOOKPROC)(BOOL Unregistering,PUSER_MESSAGE_PUMP_ADDRESSES MessagePumpAddresses); + +CRITICAL_SECTION gcsMPH; +MESSAGEPUMPHOOKPROC gpfnInitMPH; +DWORD gcLoadMPH = 0; +USER_MESSAGE_PUMP_ADDRESSES gmph = {sizeof(USER_MESSAGE_PUMP_ADDRESSES), + //NtUserRealInternalGetMessage, + //NtUserRealInternalWaitMessageEx, + RealGetQueueStatus, + RealMsgWaitForMultipleObjectsEx +}; + +DWORD gfMessagePumpHook = 0; + +BOOL WINAPI IsInsideMessagePumpHook() +{ + if(!gfMessagePumpHook) + return FALSE; + + /* This code checks if we're inside SendMessage. */ +#if 0 + /* Since our TEB doesnt match that of real windows, testing this value is useless until we know what it does + PUCHAR NtTeb = (PUCHAR)NtCurrentTeb(); + + if(!*(PLONG*)&NtTeb[0x708]) + return FALSE; + + if(**(PLONG*)&NtTeb[0x708] <= 0) + return FALSE;*/ +#endif + + return TRUE; +} + +void WINAPI ResetMessagePumpHook(PUSER_MESSAGE_PUMP_ADDRESSES Addresses) +{ + Addresses->cbSize = sizeof(USER_MESSAGE_PUMP_ADDRESSES); + //Addresses->NtUserRealInternalGetMessage = (NtUserRealInternalGetMessageProc)NtUserRealInternalGetMessage; + //Addresses->NtUserRealWaitMessageEx = (NtUserRealWaitMessageExProc)NtUserRealInternalWaitMessageEx; + Addresses->RealGetQueueStatus = RealGetQueueStatus; + Addresses->RealMsgWaitForMultipleObjectsEx = RealMsgWaitForMultipleObjectsEx; +} + +BOOL WINAPI RegisterMessagePumpHook(MESSAGEPUMPHOOKPROC Hook) +{ + EnterCriticalSection(&gcsMPH); + if(!Hook) { + SetLastError(ERROR_INVALID_PARAMETER); + LeaveCriticalSection(&gcsMPH); + return FALSE; + } + if(!gcLoadMPH) { + USER_MESSAGE_PUMP_ADDRESSES Addresses; + gpfnInitMPH = Hook; + ResetMessagePumpHook(&Addresses); + if(!Hook(FALSE, &Addresses) || !Addresses.cbSize) { + LeaveCriticalSection(&gcsMPH); + return FALSE; + } + memcpy(&gmph, &Addresses, Addresses.cbSize); + } else { + if(gpfnInitMPH != Hook) { + LeaveCriticalSection(&gcsMPH); + return FALSE; + } + } + if(NtUserCallNoParam(NOPARAM_ROUTINE_INIT_MESSAGE_PUMP)) { + LeaveCriticalSection(&gcsMPH); + return FALSE; + } + if (!gcLoadMPH++) { + InterlockedExchange((PLONG)&gfMessagePumpHook, 1); + } + LeaveCriticalSection(&gcsMPH); + return TRUE; +} + +BOOL WINAPI UnregisterMessagePumpHook(VOID) +{ + EnterCriticalSection(&gcsMPH); + if(gcLoadMPH > 0) { + if(NtUserCallNoParam(NOPARAM_ROUTINE_UNINIT_MESSAGE_PUMP)) { + gcLoadMPH--; + if(!gcLoadMPH) { + InterlockedExchange((PLONG)&gfMessagePumpHook, 0); + gpfnInitMPH(TRUE, NULL); + ResetMessagePumpHook(&gmph); + gpfnInitMPH = 0; + } + LeaveCriticalSection(&gcsMPH); + return TRUE; + } + } + LeaveCriticalSection(&gcsMPH); + return FALSE; +} + +DWORD WINAPI GetQueueStatus(UINT flags) +{ + return IsInsideMessagePumpHook() ? gmph.RealGetQueueStatus(flags) : RealGetQueueStatus(flags); +} + +/** + * @name RealMsgWaitForMultipleObjectsEx + * + * Wait either for either message arrival or for one of the passed events + * to be signalled. + * + * @param nCount + * Number of handles in the pHandles array. + * @param pHandles + * Handles of events to wait for. + * @param dwMilliseconds + * Timeout interval. + * @param dwWakeMask + * Mask specifying on which message events we should wakeup. + * @param dwFlags + * Wait type (see MWMO_* constants). + * + * @implemented + */ + +DWORD STDCALL +RealMsgWaitForMultipleObjectsEx( + DWORD nCount, + const HANDLE *pHandles, + DWORD dwMilliseconds, + DWORD dwWakeMask, + DWORD dwFlags) +{ + LPHANDLE RealHandles; + HANDLE MessageQueueHandle; + DWORD Result; + + if (dwFlags & ~(MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return WAIT_FAILED; + } + +/* + if (dwFlags & MWMO_INPUTAVAILABLE) + { + RealGetQueueStatus(dwWakeMask); + } + */ + + MessageQueueHandle = NtUserMsqSetWakeMask(dwWakeMask); + if (MessageQueueHandle == NULL) + { + SetLastError(0); /* ? */ + return WAIT_FAILED; + } + + RealHandles = HeapAlloc(GetProcessHeap(), 0, (nCount + 1) * sizeof(HANDLE)); + if (RealHandles == NULL) + { + NtUserMsqClearWakeMask(); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return WAIT_FAILED; + } + + RtlCopyMemory(RealHandles, pHandles, nCount * sizeof(HANDLE)); + RealHandles[nCount] = MessageQueueHandle; + + Result = WaitForMultipleObjectsEx(nCount + 1, RealHandles, + dwFlags & MWMO_WAITALL, + dwMilliseconds, dwFlags & MWMO_ALERTABLE); + + HeapFree(GetProcessHeap(), 0, RealHandles); + NtUserMsqClearWakeMask(); + + return Result; +} + +/* + * @implemented + */ +DWORD WINAPI +MsgWaitForMultipleObjectsEx( + DWORD nCount, + CONST HANDLE *lpHandles, + DWORD dwMilliseconds, + DWORD dwWakeMask, + DWORD dwFlags) +{ + return IsInsideMessagePumpHook() ? gmph.RealMsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds, dwWakeMask, dwFlags) : RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags); +} + +/* + * @implemented + */ +DWORD STDCALL +MsgWaitForMultipleObjects( + DWORD nCount, + CONST HANDLE *lpHandles, + BOOL fWaitAll, + DWORD dwMilliseconds, + DWORD dwWakeMask) +{ + return MsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds, + dwWakeMask, fWaitAll ? MWMO_WAITALL : 0); +} + + +BOOL FASTCALL MessageInit(VOID) +{ + InitializeCriticalSection(&DdeCrst); + InitializeCriticalSection(&MsgConversionCrst); + InitializeCriticalSection(&gcsMPH); + + return TRUE; } +VOID FASTCALL MessageCleanup(VOID) +{ + DeleteCriticalSection(&DdeCrst); + DeleteCriticalSection(&MsgConversionCrst); + DeleteCriticalSection(&gcsMPH); +} + +/*********************************************************************** + * map_wparam_AtoW + * + * Convert the wparam of an ASCII message to Unicode. + */ +static WPARAM +map_wparam_AtoW( UINT message, WPARAM wparam ) +{ + switch(message) + { + case WM_CHARTOITEM: + case EM_SETPASSWORDCHAR: + case WM_CHAR: + case WM_DEADCHAR: + case WM_SYSCHAR: + case WM_SYSDEADCHAR: + case WM_MENUCHAR: + { + char ch[2]; + WCHAR wch[2]; + ch[0] = (wparam & 0xff); + ch[1] = (wparam >> 8); + MultiByteToWideChar(CP_ACP, 0, ch, 2, wch, 2); + wparam = MAKEWPARAM(wch[0], wch[1]); + } + break; + case WM_IME_CHAR: + { + char ch[2]; + WCHAR wch; + ch[0] = (wparam >> 8); + ch[1] = (wparam & 0xff); + if (ch[0]) MultiByteToWideChar(CP_ACP, 0, ch, 2, &wch, 1); + else MultiByteToWideChar(CP_ACP, 0, &ch[1], 1, &wch, 1); + wparam = MAKEWPARAM( wch, HIWORD(wparam) ); + } + break; + } + return wparam; +} -/* EOF */ +/* + * @implemented + */ +BOOL WINAPI +IsDialogMessageA( HWND hwndDlg, LPMSG pmsg ) +{ + MSG msg = *pmsg; + msg.wParam = map_wparam_AtoW( msg.message, msg.wParam ); + return IsDialogMessageW( hwndDlg, &msg ); +}