📄 message.c
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS user32.dll
* FILE: lib/user32/windows/message.c
* PURPOSE: Messages
* PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* UPDATE HISTORY:
* 06-06-2001 CSH Created
*/
#include <user32.h>
#include <wine/debug.h>
/* 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;
static BOOL FASTCALL
DdeAddPair(HGLOBAL ClientMem, HGLOBAL ServerMem)
{
unsigned i;
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;
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:
{
goto ConvertLParamString;
}
case LB_ADDSTRING:
case LB_ADDSTRING_LOWER:
case LB_ADDSTRING_UPPER:
case LB_INSERTSTRING:
case LB_INSERTSTRING_UPPER:
case LB_INSERTSTRING_LOWER:
case LB_FINDSTRING:
case LB_FINDSTRINGEXACT:
case LB_SELECTSTRING:
{
DWORD dwStyle = GetWindowLongW(AnsiMsg->hwnd, GWL_STYLE);
if (!(dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) &&
(dwStyle & LBS_HASSTRINGS))
{
goto ConvertLParamString;
}
break;
}
case CB_ADDSTRING:
case CB_INSERTSTRING:
case CB_FINDSTRING:
case CB_FINDSTRINGEXACT:
case CB_SELECTSTRING:
{
DWORD dwStyle = GetWindowLongW(AnsiMsg->hwnd, GWL_STYLE);
if (!(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
(dwStyle & CBS_HASSTRINGS))
{
UNICODE_STRING UnicodeString;
ConvertLParamString:
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 (!IS_INTRESOURCE(xs->cs.lpszName))
{
RtlCreateUnicodeStringFromAsciiz(&UnicodeBuffer, (LPSTR)xs->cs.lpszName);
xs->lpszName = xs->cs.lpszName = UnicodeBuffer.Buffer;
}
if (!IS_ATOM(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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -