Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2014 lines
86 KiB

/*++
Copyright (c) 2000-2001, Microsoft Corporation All rights reserved.
Module Name:
usermsgs.c
APIs found in this file:
GodotDoCallback
GodotTransmitMessage
GodotReceiveMessage
GodotDispatchMessage
Helper functions
MapCatureMessage
TransmitHelper
This function does not currently handle ANSI caller to a UNICODE window.
All other calls are handled properly.
CONSIDER: To fully implement the capture window stuff, we would
need to support these callback functions:
capErrorCallback
capStatusCallback
Revision History:
6 Feb 2001 v-michka Created.
--*/
#include "precomp.h"
// Internal MFC messages
#define WM_SETMESSAGESTRING 0x0362 // wParam = nIDS (or 0),
// lParam = lpszOther (or NULL)
// Must dynamically link to "BroadcastSystemMessage" because it
// does not exist as "BroadcastSystemMessageA" on all platforms.
typedef BOOL (__stdcall *PFNbsma) (DWORD, LPDWORD, UINT, WPARAM, LPARAM);
static PFNbsma s_pfnBSMA;
// forward declares
LRESULT TransmitHelper(MESSAGETYPES mt, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam,
WNDPROC lpPrevWndFunc, SENDASYNCPROC lpCallBack, ULONG_PTR dwData,
UINT fuFlags, UINT uTimeout, PDWORD_PTR lpdwResult);
/*-------------------------------
MapCaptureMessage
Simple function that maps one message type to
another (A->W and W->A) for video captures
-------------------------------*/
UINT MapCaptureMessage(UINT uMsg)
{
if(uMsg >= WM_CAP_UNICODE_START)
return(uMsg - WM_CAP_UNICODE_START);
else
return(uMsg + WM_CAP_UNICODE_START);
}
/*-------------------------------
GodotDoCallback
Our global wrapper around callback functions; all callbacks that need random
conversions done go through this proc. Note that all callers will be Unicode
windows so we do not have to check for this here.
-------------------------------*/
LRESULT GodotDoCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, WNDPROC lpfn, BOOL fUniSrc, FAUXPROCTYPE fpt)
{
LRESULT RetVal = 0;
BOOL fUniDst;
fUniDst = (! DoesProcExpectAnsi(hWnd, lpfn, fpt));
if(!fUniDst && !fUniSrc)
{
// Call through via CallWindowProcA with no conversion
// Note that this is the only place in this entire function where we use
// CallWindowProc, since either the user or the system is expecting ANSI.
// Note that on Win9x, the base wndproc can be a thunked function sitting
// in USER.EXE; only CallWindowProcA can manage that sort of detail.
return(CallWindowProcA(lpfn, hWnd, uMsg, wParam, lParam));
}
else if(fUniDst && fUniSrc)
{
// Pure Unicode: Call directly, no conversion needed
// Note that we do not currently use this!!!
return((* lpfn)(hWnd, uMsg, wParam, lParam));
}
else if(!fUniDst && fUniSrc)
{
// We need to convert from Unicode to ANSI, so use
// our own GodotTransmitMessage to do the work.
return(GodotTransmitMessage(mtCallWindowProc, hWnd, uMsg, wParam, lParam, lpfn, 0, 0, 0, 0, 0));
}
else // (fUniDst && !fUniSrc)
{
switch(uMsg)
{
case WM_CHAR:
case EM_SETPASSWORDCHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case WM_MENUCHAR:
if(FDBCS_CPG(g_acp))
{
WPARAM wParamW = 0;
static CHAR s_ch[3] = "\0";
// We have to go through all this nonsense because DBCS characters
// arrive one byte at a time. Most of this code is never used because
// DBCS chars OUGHT to be handled by WM_IME_CHAR below.
if(!s_ch[0])
{
// No lead byte already waiting for trail byte
s_ch[0] = *(char *)wParam;
if(IsDBCSLeadByteEx(g_acp, *(char *)wParam))
{
// This is a lead byte. Save it and wait for trail byte
RetVal = FALSE;
}
// Not a DBCS character. Convert to Unicode.
MultiByteToWideChar(g_acp, 0, s_ch, 1, (WCHAR *)&wParamW, 1);
// Reset to indicate no Lead byte waiting
s_ch[0] = 0 ;
RetVal = TRUE;
}
else
{
// Have lead byte, wParam should contain the trail byte
s_ch[1] = *(char *)wParam;
// Convert both bytes into one Unicode character
MultiByteToWideChar(g_acp, 0, s_ch, 2, (WCHAR *)&wParamW, 1);
// Reset to non-waiting state
s_ch[0] = 0;
RetVal = TRUE;
}
break;
}
// Not a DBCS system, so fall through here
case WM_IME_CHAR:
case WM_IME_COMPOSITION:
{
WPARAM wParamW = 0;
MultiByteToWideChar(g_acp, 0, (CHAR *)&wParam, g_mcs, (WCHAR *)&wParamW, 1);
RetVal = (* lpfn)(hWnd, uMsg, wParamW, lParam);
WideCharToMultiByte(g_acp, 0, (WCHAR *)&wParamW, 1, (CHAR *)&wParam, g_mcs, NULL, NULL);
break;
}
case WM_CHARTOITEM:
{
// Mask off the hiword bits, convert, then stick the hiword bits back on.
WPARAM wParamW = 0;
WPARAM wpT = wParam & 0xFFFF;
MultiByteToWideChar(g_acp, 0, (CHAR *)&wpT, g_mcs, (WCHAR *)&wParamW, 1);
RetVal = (* lpfn)(hWnd, uMsg, wParamW, lParam);
WideCharToMultiByte(g_acp, 0, (WCHAR *)&wParamW, 1, (CHAR *)&wpT, g_mcs, NULL, NULL);
wParam = MAKELONG(LOWORD(wpT),HIWORD(wParam));
break;
}
case (WM_USER + 25): // might be WM_CAP_FILE_SAVEDIBA
case (WM_USER + 23): // might be WM_CAP_FILE_SAVEASA
case (WM_USER + 66): // might be WM_CAP_SET_MCI_DEVICEA
case (WM_USER + 80): // might be WM_CAP_PAL_OPENA
case (WM_USER + 81): // might be WM_CAP_PAL_SAVEA
case (WM_USER + 20): // might be WM_CAP_FILE_SET_CAPTURE_FILEA
if(!IsCaptureWindow(hWnd))
{
// The numbers are right, but its not a capture window, so
// do not convert. Instead, just pass as is.
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
}
else
{
// No memory? If the alloc fails, we eat the results.
LPARAM lParamW;
ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
RetVal = (* lpfn)(hWnd, MapCaptureMessage(uMsg), wParam, lParamW);
if(ar == arAlloc)
GodotHeapFree((LPWSTR)lParamW);
}
break;
case CB_ADDSTRING:
case CB_DIR:
case CB_FINDSTRING:
case CB_FINDSTRINGEXACT:
case CB_INSERTSTRING:
case CB_SELECTSTRING:
{
LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
if(((styl & CBS_OWNERDRAWFIXED) ||
(styl & CBS_OWNERDRAWVARIABLE)) &&
(!(styl & CBS_HASSTRINGS)))
{
// Owner draw combo box which does not have strings stored
// (See Windows Bugs # 356304 for details here)
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
}
else
{
// No memory? If the alloc fails, we eat the results.
LPARAM lParamW;
ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
if(ar == arAlloc)
GodotHeapFree((LPWSTR)lParamW);
}
}
break;
case LB_ADDSTRING:
case LB_ADDFILE:
case LB_DIR:
case LB_FINDSTRING:
case LB_FINDSTRINGEXACT:
case LB_INSERTSTRING:
case LB_SELECTSTRING:
{
LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
if(((styl & LBS_OWNERDRAWFIXED) ||
(styl & LBS_OWNERDRAWVARIABLE)) &&
(!(styl & LBS_HASSTRINGS)))
{
// Owner draw listbox which does not have strings stored
// (See Windows Bugs # 356304 for details here)
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
}
else
{
// No memory? If the alloc fails, we eat the results.
LPARAM lParamW;
ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
if(ar == arAlloc)
GodotHeapFree((LPWSTR)lParamW);
}
break;
}
case EM_REPLACESEL:
case WM_SETTEXT:
case WM_DEVMODECHANGE:
case WM_SETTINGCHANGE:
case WM_SETMESSAGESTRING: // MFC internal msg
{
// No memory? If the alloc fails, we eat the results.
LPARAM lParamW;
ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
if(ar == arAlloc)
GodotHeapFree((LPWSTR)lParamW);
break;
}
case WM_DDE_EXECUTE:
// wParam is the client window hWnd, lParam is the command LPTSTR.
// Only convert lParam if both client and server windows are Unicode
if(GetUnicodeWindowProp((HWND)hWnd) && GetUnicodeWindowProp((HWND)wParam))
{
// No memory? If the alloc fails, we eat the results.
LPARAM lParamW;
ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
if(ar == arAlloc)
GodotHeapFree((LPWSTR)lParamW);
}
else
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
break;
case EM_GETLINE:
{
// lParam is a pointer to the buffer that receives a copy of the line. Before
// sending the message, set the first word of this buffer to the size, in TCHARs,
// of the buffer. For ANSI text, this is the number of bytes; for Unicode text,
// this is the numer of characters. The size in the first word is overwritten by
// the copied line.
size_t cchlParam = (WORD)lParam + 1;
LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(cchlParam * sizeof(WCHAR));
if(RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW))
{
RetVal = WideCharToMultiByte(g_acp,
0,
(LPWSTR)lParamW,
RetVal + 1,
(LPSTR)lParam,
cchlParam,
NULL,
NULL);
if(RetVal)
RetVal--;
}
else
{
if((LPSTR)lParam)
*((LPSTR)lParam) = '\0';
}
if(lParamW)
GodotHeapFree((LPWSTR)lParamW);
}
case LB_GETTEXT:
{
// lParam is a pointer to the buffer that will receive the string; it is type
// LPTSTR which is subsequently cast to an LPARAM. The buffer must have sufficient
// space for the string and a terminating null character. An LB_GETTEXTLEN message
// can be sent before the LB_GETTEXT message to retrieve the length, in TCHARs, of
// the string.
size_t cchlParam = SendMessageA(hWnd, LB_GETTEXTLEN, wParam, 0) + 1;
LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(cchlParam * sizeof(WCHAR));
if(RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW))
{
RetVal = WideCharToMultiByte(g_acp,
0,
(LPWSTR)lParamW,
RetVal + 1,
(LPSTR)lParam,
cchlParam,
NULL,
NULL);
if(RetVal)
RetVal--;
}
else
{
if((LPSTR)lParam)
*((LPSTR)lParam) = '\0';
}
if(lParamW)
GodotHeapFree((LPWSTR)lParamW);
break;
}
case CB_GETLBTEXT:
{
// lParam is a pointer to the buffer that will receive the string; it is type
// LPTSTR which is subsequently cast to an LPARAM. The buffer must have sufficient
// space for the string and a terminating null character. An CB_GETLBTEXTLEN message
// can be sent before the CB_GETLBTEXT message to retrieve the length, in TCHARs, of
// the string.
size_t cchlParam = SendMessageA(hWnd, CB_GETLBTEXTLEN, wParam, 0) + 1;
LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(cchlParam * sizeof(WCHAR));
if((RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW)) && lParamW)
{
RetVal = WideCharToMultiByte(g_acp,
0,
(LPWSTR)lParamW,
RetVal + 1,
(LPSTR)lParam,
cchlParam,
NULL,
NULL);
if(RetVal)
RetVal--;
}
else
{
if((LPSTR)lParam)
*((LPSTR)lParam) = '\0';
}
if(lParamW)
GodotHeapFree((LPWSTR)lParamW);
break;
}
case (WM_USER + 67): // might be WM_CAP_GET_MCI_DEVICEA
case (WM_USER + 12): // might be WM_CAP_DRIVER_GET_NAMEA
case (WM_USER + 13): // might be WM_CAP_DRIVER_GET_VERSIONA
case (WM_USER + 21): // might be WM_CAP_FILE_GET_CAPTURE_FILEA
if(!IsCaptureWindow(hWnd))
{
// The numbers are right, but its not a capture window, so
// do not convert. Instead, just pass as is.
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
break;
}
// If we are still here, then it is a capture message.
// So lets map it and fall through.
uMsg = MapCaptureMessage(uMsg);
case WM_GETTEXT:
case WM_ASKCBFORMATNAME:
{
// wParam specifies the buffer size of the string lParam (includes the terminating null).
LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc((UINT)wParam * sizeof(WCHAR));
if(RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW))
{
RetVal = WideCharToMultiByte(g_acp,
0,
(LPWSTR)lParamW,
RetVal + 1,
(LPSTR)lParam,
(UINT)wParam,
NULL,
NULL);
if(RetVal)
RetVal--;
}
else
{
if((LPSTR)lParam)
*((LPSTR)lParam) = '\0';
}
if(lParamW)
GodotHeapFree((LPWSTR)lParamW);
break;
}
case (WM_USER + 1):
if(IsFontDialog(hWnd))
{
// This is a WM_CHOOSEFONT_GETLOGFONT msg
LPARAM lParamW = (LPARAM)(LPLOGFONTW)GodotHeapAlloc(sizeof(LOGFONTW));
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
LogFontAfromW((LPLOGFONTA)lParam, (LPLOGFONTW)lParamW);
if(lParamW)
GodotHeapFree((LPWSTR)lParamW);
}
else
{
// This would be one of the common control msgs we do not handle
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
break;
}
break;
case (WM_USER + 100):
if(IsNewFileOpenDialog(hWnd))
{
// This is a CDM_GETSPEC msg
LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(wParam * sizeof(WCHAR));
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
WideCharToMultiByte(g_acp, 0,
(LPWSTR)lParamW, wParam,
(LPSTR)lParam, wParam,
NULL, NULL);
RetVal = lstrlenA( (LPSTR)lParam);
if(lParamW)
GodotHeapFree((LPWSTR)lParamW);
}
else
{
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
}
break;
case (WM_USER + 101):
if(IsFontDialog(hWnd))
{
// This is a WM_CHOOSEFONT_SETLOGFONT msg
LPARAM lParamW = (LPARAM)(LPLOGFONTW)GodotHeapAlloc(sizeof(LOGFONTW));
LogFontWfromA((LPLOGFONTW)lParamW, (LPLOGFONTA)lParam);
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
if(lParamW)
GodotHeapFree((LPLOGFONTW)lParamW);
}
else if(IsNewFileOpenDialog(hWnd))
{
// This is a CDM_GETFILEPATH msg
LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(wParam * sizeof(WCHAR));
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
WideCharToMultiByte(g_acp, 0,
(LPWSTR)lParamW, wParam,
(LPSTR)lParam, wParam,
NULL, NULL);
RetVal = lstrlenA( (LPSTR)lParam);
if(lParamW)
GodotHeapFree((LPWSTR)lParamW);
}
else
{
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
}
break;
case (WM_USER + 102):
if(IsFontDialog(hWnd))
{
// This is a WM_CHOOSEFONT_SETFLAGS msg
// The docs claim that lParam has a CHOOSEFONT struct but the code shows
// that it only has the Flags in it, so pass it as is
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
}
else if(IsNewFileOpenDialog(hWnd))
{
// This is a CDM_GETFOLDERPATH
// lParam is a buffer for the path of the open folder
LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(wParam * sizeof(WCHAR));
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
WideCharToMultiByte(g_acp, 0,
(LPWSTR)lParamW, wParam,
(LPSTR)lParam, wParam,
NULL, NULL);
RetVal = lstrlenA( (LPSTR)lParam);
if(lParamW)
GodotHeapFree((LPWSTR)lParamW);
}
else
{
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
}
break;
case (WM_USER + 104):
if(IsNewFileOpenDialog(hWnd))
{
// This is a CDM_SETCONTROLTEXT message
// lParam is the control text (wParam is the control ID)
// No memory? If the alloc fails, we eat the results.
LPARAM lParamW;
WPARAM wParamW;
ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
wParamW = gwcslen((LPWSTR)lParamW);
RetVal = (* lpfn)(hWnd, uMsg, wParamW, lParamW);
if(ar == arAlloc)
GodotHeapFree((LPWSTR)lParamW);
}
else
{
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
}
break;
case (WM_USER + 106):
if(IsNewFileOpenDialog(hWnd))
{
// This is a CDM_SETDEFEXT message
// lParam is the extension
// No memory? If the alloc fails, we eat the results.
LPARAM lParamW;
WPARAM wParamW;
ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
wParamW = gwcslen((LPWSTR)lParamW);
RetVal = (* lpfn)(hWnd, uMsg, wParamW, lParamW);
if(ar == arAlloc)
GodotHeapFree((LPWSTR)lParamW);
}
else
{
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
}
break;
case WM_CREATE:
case WM_NCCREATE:
{
LPCREATESTRUCTA lpcsA = (LPCREATESTRUCTA)lParam;
CREATESTRUCTW cs;
ALLOCRETURN arName = arNoAlloc;
ALLOCRETURN arClass = arNoAlloc;
ZeroMemory(&cs, sizeof(CREATESTRUCTW));
cs.lpCreateParams = lpcsA->lpCreateParams;
cs.hInstance = lpcsA->hInstance;
cs.hMenu = lpcsA->hMenu;
cs.hwndParent = lpcsA->hwndParent;
cs.cy = lpcsA->cy;
cs.cx = lpcsA->cx;
cs.y = lpcsA->y;
cs.x = lpcsA->x;
cs.style = lpcsA->style;
cs.dwExStyle = lpcsA->dwExStyle;
arName = GodotToUnicodeOnHeap(lpcsA->lpszName, &(LPWSTR)(cs.lpszName));
arClass = GodotToUnicodeOnHeap(lpcsA->lpszClass, &(LPWSTR)(cs.lpszClass));
RetVal = (* lpfn)(hWnd, uMsg, wParam, (LPARAM)&cs);
// Free up strings if we allocated any
if(arName==arAlloc)
GodotHeapFree((LPWSTR)(cs.lpszName));
if(arClass==arAlloc)
GodotHeapFree((LPWSTR)(cs.lpszClass));
break;
}
case WM_MDICREATE:
{
// wParam is not used, lParam is a pointer to an MDICREATESTRUCT structure containing
// information that the system uses to create the MDI child window.
LPMDICREATESTRUCTA lpmcsiA = (LPMDICREATESTRUCTA)lParam;
MDICREATESTRUCTW mcsi;
ALLOCRETURN arTitle = arNoAlloc;
ALLOCRETURN arClass = arNoAlloc;
ZeroMemory(&mcsi, sizeof(MDICREATESTRUCTW));
mcsi.hOwner = lpmcsiA->hOwner;
mcsi.x = lpmcsiA->x;
mcsi.y = lpmcsiA->y;
mcsi.cx = lpmcsiA->cx;
mcsi.cy = lpmcsiA->cy;
mcsi.style = lpmcsiA->style;
mcsi.lParam = lpmcsiA->lParam;
arTitle = GodotToUnicodeOnHeap(lpmcsiA->szTitle, &(LPWSTR)(mcsi.szTitle));
arClass = GodotToUnicodeOnHeap(lpmcsiA->szClass, &(LPWSTR)(mcsi.szClass));
RetVal = (* lpfn)(hWnd, uMsg, wParam, (LPARAM)&mcsi);
// Free up strings if we allocated any
if(arTitle==arAlloc)
GodotHeapFree((LPWSTR)(mcsi.szTitle));
if(arClass==arAlloc)
GodotHeapFree((LPWSTR)(mcsi.szClass));
break;
}
case WM_DEVICECHANGE:
{
switch(wParam)
{
case DBT_CUSTOMEVENT:
case DBT_DEVICEARRIVAL:
case DBT_DEVICEQUERYREMOVE:
case DBT_DEVICEQUERYREMOVEFAILED:
case DBT_DEVICEREMOVECOMPLETE:
case DBT_DEVICEREMOVEPENDING:
case DBT_DEVICETYPESPECIFIC:
{
// lParam contains info about the device. We interrogate it as if it were
// a PDEV_BROADCAST_HDR in order to find out what it really is, then convert
// as needed
if (((PDEV_BROADCAST_HDR)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
PDEV_BROADCAST_DEVICEINTERFACE_A pdbdia = (PDEV_BROADCAST_DEVICEINTERFACE_A)lParam;
DEV_BROADCAST_DEVICEINTERFACE_W dbdi;
ALLOCRETURN arName = arNoAlloc;
ZeroMemory(&dbdi, sizeof(DEV_BROADCAST_DEVICEINTERFACE_W));
dbdi.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_W);
dbdi.dbcc_devicetype = pdbdia->dbcc_devicetype;
dbdi.dbcc_reserved = pdbdia->dbcc_reserved;
dbdi.dbcc_classguid = pdbdia->dbcc_classguid;
arName = GodotToUnicodeOnHeap(pdbdia->dbcc_name, *(LPWSTR**)(dbdi.dbcc_name));
RetVal = (* lpfn)(hWnd, uMsg, wParam, (LPARAM)&dbdi);
if(arName==arAlloc)
GodotHeapFree(dbdi.dbcc_name);
}
else if(((PDEV_BROADCAST_HDR)lParam)->dbch_devicetype == DBT_DEVTYP_PORT)
{
PDEV_BROADCAST_PORT_A pdbpa = (PDEV_BROADCAST_PORT_A)lParam;
DEV_BROADCAST_PORT_W dbp;
ALLOCRETURN arName = arNoAlloc;
ZeroMemory(&dbp, sizeof(DEV_BROADCAST_PORT_W));
dbp.dbcp_size = sizeof(DEV_BROADCAST_PORT_W);
dbp.dbcp_devicetype = pdbpa->dbcp_devicetype;
dbp.dbcp_reserved = pdbpa->dbcp_reserved;
arName = GodotToUnicodeOnHeap(pdbpa->dbcp_name, *(LPWSTR**)(dbp.dbcp_name));
RetVal = (* lpfn)(hWnd, uMsg, wParam, (LPARAM)&dbp);
if(arName==arAlloc)
GodotHeapFree(dbp.dbcp_name);
}
else
{
// No changes needed! There are no strings in the other structures.
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
}
break;
}
case DBT_USERDEFINED:
// No UNICODE string in this one, so fall through
default:
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
break;
}
break;
}
default:
{
// Lets get our registered messages, if we haven't yet.
if(!msgHELPMSGSTRING)
msgHELPMSGSTRING = RegisterWindowMessage(HELPMSGSTRINGA);
if(!msgFINDMSGSTRING)
msgFINDMSGSTRING = RegisterWindowMessage(FINDMSGSTRINGA);
if((uMsg == msgHELPMSGSTRING) &&
(((LPOPENFILENAMEA)lParam)->lStructSize == OPENFILENAME_SIZE_VERSION_400A))
{
WCHAR drive[_MAX_DRIVE];
WCHAR dir[_MAX_DIR];
WCHAR file[_MAX_FNAME];
LPOPENFILENAMEA lpofnA = (LPOPENFILENAMEA)lParam;
OPENFILENAMEW ofn;
ALLOCRETURN arCustomFilter = arNoAlloc;
ALLOCRETURN arFile = arNoAlloc;
ALLOCRETURN arFileTitle = arNoAlloc;
// lParam is an LPOPENFILENAMEA to be converted. Copy all the
// members that the user might expect.
ZeroMemory(&ofn, OPENFILENAME_SIZE_VERSION_400W);
ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
arCustomFilter = GodotToUnicodeCpgCchOnHeap(lpofnA->lpstrCustomFilter,
lpofnA->nMaxCustFilter,
&ofn.lpstrCustomFilter,
g_acp);
ofn.nMaxCustFilter = gwcslen(ofn.lpstrCustomFilter);
ofn.nFilterIndex = lpofnA->nFilterIndex;
ofn.nMaxFile = lpofnA->nMaxFile * sizeof(WCHAR);
arFile = GodotToUnicodeCpgCchOnHeap(lpofnA->lpstrFile,
lpofnA->nMaxFile,
&ofn.lpstrFile,
g_acp);
ofn.nMaxFile = gwcslen(ofn.lpstrFile);
arFileTitle = GodotToUnicodeCpgCchOnHeap(lpofnA->lpstrFileTitle,
lpofnA->nMaxFileTitle,
&ofn.lpstrFileTitle,
g_acp);
ofn.nMaxFileTitle = gwcslen(ofn.lpstrFileTitle);
ofn.Flags = lpofnA->Flags;
// nFileOffset and nFileExtension are to provide info about the
// file name and extension location in lpstrFile, but there is
// no reasonable way to get it from the return so we just recalc
gwsplitpath(ofn.lpstrFile, drive, dir, file, NULL);
ofn.nFileOffset = (gwcslen(drive) + gwcslen(dir));
ofn.nFileExtension = ofn.nFileOffset + gwcslen(file);
RetVal = (*lpfn)(hWnd, uMsg, wParam, (LPARAM)&ofn);
// Free up some memory if we allocated any
if(arCustomFilter==arAlloc)
GodotHeapFree(ofn.lpstrCustomFilter);
if(arFile==arAlloc)
GodotHeapFree(ofn.lpstrFile);
if(arFileTitle==arAlloc)
GodotHeapFree(ofn.lpstrFileTitle);
}
else if(((uMsg == msgFINDMSGSTRING) || (uMsg == msgHELPMSGSTRING)) &&
((((LPFINDREPLACEW)lParam)->lStructSize) == sizeof(FINDREPLACEA)))
{
LPFINDREPLACEW lpfr = (LPFINDREPLACEW)lParam;
// lParam is an LPFINDREPLACEW that we passed on through.
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
if((lpfr->Flags & FR_DIALOGTERM) &&
((lpfr->lpfnHook == &FRHookProcFind) || (lpfr->lpfnHook == &FRHookProcReplace)))
{
// Now handle our cleanup. I do not think this should
// be needed, but it can't hurt to do it just in case.
LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE);
// They are destroying the dialog, so unhook ourselves
// and clean up the dialog (if we have not done it yet).
if(lpfr->lpfnHook == &FRHookProcFind)
{
// Find dialog, not yet cleaned up
lpfr->lpfnHook = lpgti->pfnFindText;
if(lpfr->lpfnHook == NULL)
lpfr->Flags &= ~FR_ENABLEHOOK;
}
else if(lpfr->lpfnHook == &FRHookProcReplace)
{
// Replace dialog, not yet cleaned up
lpfr->lpfnHook = lpgti->pfnReplaceText;
if(lpfr->lpfnHook == NULL)
lpfr->Flags &= ~FR_ENABLEHOOK;
}
}
}
else if((uMsg == msgHELPMSGSTRING) &&
((LPCHOOSEFONTA)lParam)->lStructSize == sizeof(CHOOSEFONTA))
{
LPCHOOSEFONTA lpcfA = (LPCHOOSEFONTA)lParam;
CHOOSEFONTW cf;
LPARAM lParamW;
ALLOCRETURN ar = arNoAlloc;
// lParam is an LPCHOOSEFONTA to be converted. Copy all the
// members that the user might expect.
ZeroMemory(&cf, sizeof(CHOOSEFONTW));
cf.lStructSize = sizeof(CHOOSEFONTW);
cf.hDC = lpcfA->hDC;
LogFontWfromA(cf.lpLogFont, lpcfA->lpLogFont);
cf.iPointSize = lpcfA->iPointSize;
cf.Flags = lpcfA->Flags;
cf.rgbColors = lpcfA->rgbColors;
cf.lCustData = lpcfA->lCustData;
cf.nFontType = lpcfA->nFontType;
cf.nSizeMin = lpcfA->nSizeMin;
cf.nSizeMax = lpcfA->nSizeMax;
ar = GodotToUnicodeOnHeap(lpcfA->lpszStyle, &(cf.lpszStyle));
lParamW = (LPARAM)&cf;
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
if(ar==arAlloc)
GodotHeapFree((LPWSTR)cf.lpszStyle);
}
else
{
// No translation needed, as far as we know.
RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
}
break;
}
}
return(RetVal);
}
}
/*-------------------------------
GodotTransmitMessage
Our global wrapper for sending out messages (SendMessage, et. al.).
Its fundamental purpose:
1) Convert back to Ansi, as expected
2) Call the function as specified by mt
3) Convert to Unicode, as expected
-------------------------------*/
LRESULT GodotTransmitMessage(
MESSAGETYPES mt, // Type of message function
HWND hWnd, // handle to window - overloaded for thread id in PostThreadMessage
UINT Msg, // message
WPARAM wParamW, // first message parameter
LPARAM lParamW, // second message parameter
WNDPROC lpPrevWndFunc, // pointer to previous procedure - overloaded for multiple hook procs
SENDASYNCPROC lpCallBack, // callback function
ULONG_PTR dwData, // application-defined value - overloaded for DefFrameProc as second hWnd
UINT fuFlags, // send options -- overloaded for BroadcastSystemMessages as dwFlags
UINT uTimeout, // time-out duration
PDWORD_PTR lpdwResult // retval for synch. -- overloaded BroadcastSystemMessages lpdwRecipients
)
{
LRESULT retval = 0;
WPARAM wParam = 0;
LPARAM lParam = 0;
size_t cchlParam;
// Some flags we will need for our message handling
BOOL fUnicodeProc = (! DoesProcExpectAnsi(hWnd, lpPrevWndFunc, fptUnknown));
/*
fUnicodeProc == Does the wndproc being called expect Unicode messages?
*/
if((!fUnicodeProc) && (mt==mtCallWindowProcA) ||
(fUnicodeProc) && ((mt==mtCallWindowProc)))
{
// The wndproc either expects ANSI and the caller has used one of the ANSI
// functions or it expects Unicode and they have used CallWindowProcW. In
// these cases, we do no conversions here
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
}
else
{
switch(Msg)
{
case WM_CHAR:
case EM_SETPASSWORDCHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case WM_MENUCHAR:
// All these messages require the wParamW to be converted from Unicode
wParam = 0;
WideCharToMultiByte(g_acp, 0, (WCHAR *)&wParamW, 1, (char *)&wParam, g_mcs, NULL, NULL);
if(FDBCS_CPG(g_acp))
{
if(!wParam)
{
retval = TransmitHelper(mt, hWnd, Msg, wParam, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
break;
}
else if(IsDBCSLeadByte(*(char *)(LOBYTE(wParam))))
{
// Ok, its a DBCS code page and wParam contains a DBCS character.
// we must send two WM_CHAR messages, one with each byte in it
char sz[2];
sz[0] = *(char *)LOBYTE(wParam);
sz[1] = *(char *)HIBYTE(wParam);
retval = TransmitHelper(mt, hWnd, Msg, (WPARAM)&sz[0], lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
if(retval==0)
{
// The first byte was handled, so send the second byte
retval = TransmitHelper(mt, hWnd, Msg, (WPARAM)&sz[1], lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
}
MultiByteToWideChar(g_acp, 0, (char *)&sz[0], g_mcs, (WCHAR *)&wParamW, 1);
break;
}
}
/*
if(FDBCS_CPG(g_acp) && (IsDBCSLeadByte((LOBYTE(wParam)))))
{
// Ok, its a DBCS code page and wParam contains a DBCS character.
// we must send two WM_CHAR messages, one with each byte in it
retval = TransmitHelper(mt, hWnd, Msg, (WPARAM)LOBYTE(wParam), lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
if(retval==0)
{
// The first byte was handled, so send the second byte
retval = TransmitHelper(mt, hWnd, Msg, (WPARAM)HIBYTE(wParam), lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
}
break;
}
*/
// Not a DBCS code page, or at least not a DBCS character, so we just fall through now.
case WM_IME_CHAR:
case WM_IME_COMPOSITION:
retval = TransmitHelper(mt, hWnd, Msg, wParam, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
MultiByteToWideChar(g_acp, 0, (char *)&wParam, g_mcs, (WCHAR *)&wParamW, 1);
break;
case WM_CHARTOITEM:
{
// Mask off the hiword bits, convert, then stick the hiword bits back on.
WPARAM wpT = wParamW & 0xFFFF;
WideCharToMultiByte(g_acp, 0, (WCHAR *)&wpT, 1, (char *)&wParam, g_mcs, NULL, NULL);
retval = TransmitHelper(mt, hWnd, Msg, wParam, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
MultiByteToWideChar(g_acp, 0, (char *)&wParam, g_mcs, (WCHAR *)&wpT, 1);
wParamW = MAKELONG(LOWORD(wpT),HIWORD(wParamW));
break;
}
case (WM_USER + 125): // might be WM_CAP_FILE_SAVEDIBW:
case (WM_USER + 123): // might be WM_CAP_FILE_SAVEASW:
case (WM_USER + 166): // might be WM_CAP_SET_MCI_DEVICEW:
case (WM_USER + 180): // might be WM_CAP_PAL_OPENW:
case (WM_USER + 181): // might be WM_CAP_PAL_SAVEW:
case (WM_USER + 120): // might be WM_CAP_FILE_SET_CAPTURE_FILEW:
if(!IsCaptureWindow(hWnd))
{
// The numbers are right, but its not a capture window, so
// do not convert. Instead, just pass as is.
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
}
else
{
// No memory? If the alloc fails, we eat the results.
ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
if(ar != arFailed)
{
Msg = MapCaptureMessage(Msg);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
}
if(ar == arAlloc)
GodotHeapFree((LPSTR)lParam);
}
break;
case CB_ADDSTRING:
case CB_DIR:
case CB_FINDSTRING:
case CB_FINDSTRINGEXACT:
case CB_INSERTSTRING:
case CB_SELECTSTRING:
{
LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
if(((styl & CBS_OWNERDRAWFIXED) ||
(styl & CBS_OWNERDRAWVARIABLE)) &&
(!(styl & CBS_HASSTRINGS)))
{
// Owner draw combo box which does not have strings stored
// (See Windows Bugs # 356304 for details here)
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
}
else
{
// No memory? If the alloc fails, we eat the results.
ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
if(ar == arAlloc)
GodotHeapFree((LPSTR)lParam);
}
break;
}
case LB_ADDFILE:
case LB_ADDSTRING:
case LB_DIR:
case LB_FINDSTRING:
case LB_FINDSTRINGEXACT:
case LB_INSERTSTRING:
case LB_SELECTSTRING:
{
LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
if(((styl & LBS_OWNERDRAWFIXED) ||
(styl & LBS_OWNERDRAWVARIABLE)) &&
(!(styl & LBS_HASSTRINGS)))
{
// Owner draw listbox which does not have strings stored
// (See Windows Bugs # 356304 for details here)
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
}
else
{
// No memory? If the alloc fails, we eat the results.
ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
if(ar == arAlloc)
GodotHeapFree((LPSTR)lParam);
}
break;
}
case EM_REPLACESEL:
case WM_SETTEXT:
case WM_DEVMODECHANGE:
case WM_SETTINGCHANGE:
case WM_SETMESSAGESTRING: // MFC internal msg
{
// All these messages require a string in lParam to be converted from Unicode
// No memory? If the alloc fails, we eat the results.
ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
if(ar == arAlloc)
GodotHeapFree((LPSTR)lParam);
break;
}
case WM_DDE_EXECUTE:
// wParam is the client window hWnd, lParam is the command LPTSTR.
// Only convert lParam if both client and server windows are Unicode
if(GetUnicodeWindowProp((HWND)wParamW))
{
// No memory? If the alloc fails, we eat the results.
ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
if(ar == arAlloc)
GodotHeapFree((LPSTR)lParam);
}
else
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
break;
case EM_GETLINE:
// lParam is a pointer to the buffer that receives a copy of the line. Before
// sending the message, set the first word of this buffer to the size, in TCHARs,
// of the buffer. For ANSI text, this is the number of bytes; for Unicode text,
// this is the numer of characters. The size in the first word is overwritten by
// the copied line.
cchlParam = (WORD)lParamW;
lParam = (LPARAM)(LPSTR)GodotHeapAlloc(cchlParam * g_mcs);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
if(retval)
{
retval = MultiByteToWideChar(g_acp,
0,
(LPSTR)lParam,
retval + 1,
(LPWSTR)lParamW,
cchlParam);
if(retval)
retval--;
}
else
{
if((LPWSTR)lParamW)
*((LPWSTR)lParamW) = L'\0';
}
if(lParam)
GodotHeapFree((LPSTR)lParam);
break;
case LB_GETTEXT:
// lParam is a pointer to the buffer that will receive the string; it is type
// LPTSTR which is subsequently cast to an LPARAM. The buffer must have sufficient
// space for the string and a terminating null character. An LB_GETTEXTLEN message
// can be sent before the LB_GETTEXT message to retrieve the length, in TCHARs, of
// the string.
cchlParam = SendMessageA(hWnd, LB_GETTEXTLEN, wParamW, 0) + 1;
lParam = (LPARAM)(LPSTR)GodotHeapAlloc(cchlParam * g_mcs);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
if(retval)
{
retval = MultiByteToWideChar(g_acp,
0,
(LPSTR)lParam,
retval + 1,
(LPWSTR)lParamW,
cchlParam);
if(retval)
retval--;
}
else
{
if((LPWSTR)lParamW)
*((LPWSTR)lParamW) = L'\0';
}
if(lParam)
GodotHeapFree((LPSTR)lParam);
break;
case LB_GETTEXTLEN:
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
if(FDBCS_CPG(g_acp))
{
// In the DBCS case, LB_GETTEXTLEN returns number of bytes, but
// we need to get the number of characters for the Unicode case.
LPSTR lpsz = GodotHeapAlloc(retval + 1);
if(lpsz)
{
cchlParam = TransmitHelper(mt, hWnd, LB_GETTEXT, (WPARAM)(retval + 1), (LPARAM)lpsz,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
if(cchlParam > 0)
{
LPWSTR lpwz = GodotHeapAlloc((cchlParam + 1) * sizeof(WCHAR));
size_t cch = (cchlParam + 1) * sizeof(WCHAR);
retval = MultiByteToWideChar(g_acp, 0, lpsz, cchlParam, lpwz, cch);
if(lpwz)
GodotHeapFree(lpwz);
}
GodotHeapFree(lpsz);
}
}
break;
case CB_GETLBTEXT:
// lParam is a pointer to the buffer that will receive the string; it is type
// LPTSTR which is subsequently cast to an LPARAM. The buffer must have sufficient
// space for the string and a terminating null character. An CB_GETLBTEXTLEN message
// can be sent before the CB_GETLBTEXT message to retrieve the length, in TCHARs, of
// the string.
cchlParam = SendMessageA(hWnd, CB_GETLBTEXTLEN, wParamW, 0) + 1;
lParam = (LPARAM)(LPSTR)GodotHeapAlloc(cchlParam * g_mcs);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
if(retval)
{
retval = MultiByteToWideChar(g_acp,
0,
(LPSTR)lParam,
retval + 1,
(LPWSTR)lParamW,
cchlParam);
if(retval)
retval--;
}
else
{
if((LPWSTR)lParamW)
*((LPWSTR)lParamW) = L'\0';
}
if(lParam)
GodotHeapFree((LPSTR)lParam);
break;
case CB_GETLBTEXTLEN:
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
if(FDBCS_CPG(g_acp))
{
// In the DBCS case, CB_GETLBTEXTLEN returns number of bytes, but
// we need to get the number of characters for the Unicode case.
LPSTR lpsz = GodotHeapAlloc(retval + 1);
if(lpsz)
{
cchlParam = TransmitHelper(mt, hWnd, CB_GETLBTEXT, (WPARAM)(retval + 1), (LPARAM)lpsz,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
if(cchlParam > 0)
{
LPWSTR lpwz = GodotHeapAlloc((cchlParam + 1) * sizeof(WCHAR));
if(lpwz)
{
size_t cch = (cchlParam + 1) * sizeof(WCHAR);
retval = MultiByteToWideChar(g_acp, 0, lpsz, cchlParam, lpwz, cch);
GodotHeapFree(lpwz);
}
}
GodotHeapFree(lpsz);
}
}
break;
case (WM_USER + 167): // might be WM_CAP_GET_MCI_DEVICEW
case (WM_USER + 112): // might be WM_CAP_DRIVER_GET_NAMEW:
case (WM_USER + 113): // might be WM_CAP_DRIVER_GET_VERSIONW:
case (WM_USER + 121): // might be WM_CAP_FILE_GET_CAPTURE_FILEW:
if(!IsCaptureWindow(hWnd))
{
// The numbers are right, but its not a capture window, so
// do not convert. Instead, just pass as is.
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
break;
}
// If we are still here, then it is a capture message. So lets map
// it and faill through.
Msg = MapCaptureMessage(Msg);
case WM_GETTEXT:
// wParam specifies the size of the buffer in the string in lParam
cchlParam = (size_t)wParamW;
lParam = (LPARAM)(LPSTR)GodotHeapAlloc(cchlParam * g_mcs);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
if(retval)
{
retval = MultiByteToWideChar(g_acp,
0,
(LPSTR)lParam,
retval + 1,
(LPWSTR)lParamW,
cchlParam);
if(retval)
retval--;
}
else
{
if((LPWSTR)lParamW)
*((LPWSTR)lParamW) = L'\0';
}
if(lParam)
GodotHeapFree((LPSTR)lParam);
break;
case WM_GETTEXTLENGTH:
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
if(FDBCS_CPG(g_acp))
{
// In the DBCS case, WM_GETTEXTLENGTH returns number of bytes, but
// we need to get the number of characters for the Unicode case.
// If any of the allocs fail, we will live with the less than perfect
// result we have in hand
LPSTR lpsz = GodotHeapAlloc(retval + 1);
if(lpsz)
{
cchlParam = TransmitHelper(mt, hWnd, WM_GETTEXT, (WPARAM)(retval + 1), (LPARAM)lpsz,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
if(cchlParam > 0)
{
LPWSTR lpwz = GodotHeapAlloc((cchlParam + 1) * sizeof(WCHAR));
if(lpwz)
{
size_t cch = (cchlParam + 1) * sizeof(WCHAR);
retval = MultiByteToWideChar(g_acp, 0, lpsz, cchlParam, lpwz, cch);
GodotHeapFree(lpwz);
}
}
GodotHeapFree(lpsz);
}
}
break;
case (WM_USER + 1):
if(IsFontDialog(hWnd))
{
// This is a WM_CHOOSEFONT_GETLOGFONT msg
LOGFONTA lfa;
lParam = (LPARAM)&lfa;
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
LogFontWfromA((LPLOGFONTW)lParamW, (LPLOGFONTA)lParam);
}
else
{
// This would be one of the common control msgs we do not handle
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
break;
}
break;
case (WM_USER + 100):
if(IsNewFileOpenDialog(hWnd))
{
// This is a CDM_GETSPEC msg
wParam = wParamW * g_mcs;
(LPSTR)lParam = (LPSTR)GodotHeapAlloc(wParam);
retval = TransmitHelper(mt, hWnd, Msg, wParam, lParam,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
MultiByteToWideChar(g_acp, 0, (LPSTR)lParam, wParam, (LPWSTR)lParamW, wParamW);
retval = gwcslen((LPWSTR)lParamW);
if(lParam)
GodotHeapFree((LPSTR)lParam);
}
else
{
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
}
break;
case (WM_USER + 101):
if(IsFontDialog(hWnd))
{
// This is a WM_CHOOSEFONT_SETLOGFONT msg
LOGFONTA lfa;
lParam = (LPARAM)&lfa;
LogFontAfromW((LPLOGFONTA)lParam, (LPLOGFONTW)lParamW);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
}
else if(IsNewFileOpenDialog(hWnd))
{
// This is a CDM_GETFILEPATH msg
wParam = wParamW * g_mcs;
(LPSTR)lParam = (LPSTR)GodotHeapAlloc(wParam);
retval = TransmitHelper(mt, hWnd, Msg, wParam, lParam,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
MultiByteToWideChar(g_acp, 0, (LPSTR)lParam, wParam, (LPWSTR)lParamW, wParamW);
retval = gwcslen((LPWSTR)lParamW);
if(lParam)
GodotHeapFree((LPSTR)lParam);
}
else
{
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
}
break;
case (WM_USER + 102):
if(IsFontDialog(hWnd))
{
// This is a WM_CHOOSEFONT_SETFLAGS msg
// The docs claim that lParam has a CHOOSEFONT struct but the code shows
// that it only has the Flags in it
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
}
else if(IsNewFileOpenDialog(hWnd))
{
// This is a CDM_GETFOLDERPATH
// lParam is a buffer for the path of the open folder
wParam = wParamW * g_mcs;
(LPSTR)lParam = (LPSTR)GodotHeapAlloc(wParam);
retval = TransmitHelper(mt, hWnd, Msg, wParam, lParam,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
MultiByteToWideChar(g_acp, 0, (LPSTR)lParam, wParam, (LPWSTR)lParamW, wParamW);
retval = gwcslen((LPWSTR)lParamW);
if(lParam)
GodotHeapFree((LPSTR)lParam);
}
else
{
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
}
break;
case (WM_USER + 104):
if(IsNewFileOpenDialog(hWnd))
{
// This is a CDM_SETCONTROLTEXT message
// lParam is the control text (wParam is the control ID)
// No memory? If the alloc fails, we eat the results.
ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
if(ar == arAlloc)
GodotHeapFree((LPSTR)lParam);
}
else
{
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
}
break;
case (WM_USER + 106):
if(IsNewFileOpenDialog(hWnd))
{
// This is a CDM_SETDEFEXT message
// lParam is the extension
// No memory? If the alloc fails, we eat the results.
ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
if(ar == arAlloc)
GodotHeapFree((LPSTR)lParam);
}
else
{
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
}
break;
case EM_GETPASSWORDCHAR:
{
// All these messages require that the (single char) retval be converted to Unicode
// CONSIDER: is this always single character?
LRESULT retvalA = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
MultiByteToWideChar(g_acp, 0,
(char *)&retvalA,
g_mcs,
(WCHAR *)&retval,
sizeof(WCHAR));
break;
}
case WM_CREATE:
case WM_NCCREATE:
{
LPCREATESTRUCTW lpcs = (LPCREATESTRUCTW)lParamW;
CREATESTRUCTA csA;
ALLOCRETURN arClass = arNoAlloc;
ALLOCRETURN arName = arNoAlloc;
ZeroMemory(&csA, sizeof(CREATESTRUCTA));
csA.lpCreateParams = lpcs->lpCreateParams;
csA.hInstance = lpcs->hInstance;
csA.hMenu = lpcs->hMenu;
csA.hwndParent = lpcs->hwndParent;
csA.cy = lpcs->cy;
csA.cx = lpcs->cx;
csA.y = lpcs->y;
csA.x = lpcs->x;
csA.style = lpcs->style;
csA.dwExStyle = lpcs->dwExStyle;
arClass = GodotToAcpOnHeap(lpcs->lpszClass, &(LPSTR)(csA.lpszClass));
arName = GodotToAcpOnHeap(lpcs->lpszName, &(LPSTR)(csA.lpszName));
lParam = (LPARAM)&csA;
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
if(arClass==arAlloc)
GodotHeapFree((LPSTR)csA.lpszClass);
if(arName==arAlloc)
GodotHeapFree((LPSTR)csA.lpszName);
break;
}
case WM_MDICREATE:
// wParam is not used, lParam is a pointer to an MDICREATESTRUCT structure containing
// information that the system uses to create the MDI child window.
{
LPMDICREATESTRUCTW lpmcsi = (LPMDICREATESTRUCTW)lParamW;
MDICREATESTRUCTA mcsiA;
ALLOCRETURN arClass = arNoAlloc;
ALLOCRETURN arTitle = arNoAlloc;
ZeroMemory(&mcsiA, sizeof(MDICREATESTRUCTA));
mcsiA.hOwner = lpmcsi->hOwner;
mcsiA.x = lpmcsi->x;
mcsiA.y = lpmcsi->y;
mcsiA.cx = lpmcsi->cx;
mcsiA.cy = lpmcsi->cy;
mcsiA.style = lpmcsi->style;
mcsiA.lParam = lpmcsi->lParam;
arClass = GodotToAcpOnHeap(lpmcsi->szClass, &(LPSTR)(mcsiA.szClass));
arTitle = GodotToAcpOnHeap(lpmcsi->szTitle, &(LPSTR)(mcsiA.szTitle));
retval = TransmitHelper(mt, hWnd, Msg, wParamW, (LPARAM)&mcsiA,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
if(arClass==arAlloc)
GodotHeapFree((LPSTR)mcsiA.szClass);
if(arTitle==arAlloc)
GodotHeapFree((LPSTR)mcsiA.szTitle);
}
break;
default:
// Lets get our registered messages, if we haven't yet.
if(!msgHELPMSGSTRING)
msgHELPMSGSTRING = RegisterWindowMessage(HELPMSGSTRINGA);
if(!msgFINDMSGSTRING)
msgFINDMSGSTRING = RegisterWindowMessage(FINDMSGSTRINGA);
if(((Msg == msgFINDMSGSTRING) || (Msg == msgHELPMSGSTRING)) &&
((((LPFINDREPLACEW)lParamW)->lStructSize) == sizeof(FINDREPLACEA)))
{
LPFINDREPLACEW lpfr;
// No translation needed
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
lpPrevWndFunc, lpCallBack, dwData,
fuFlags, uTimeout, lpdwResult);
lpfr = (LPFINDREPLACEW)lParamW;
if((lpfr->Flags & FR_DIALOGTERM) &&
((lpfr->lpfnHook == &FRHookProcFind) || (lpfr->lpfnHook == &FRHookProcReplace)))
{
// Now handle our cleanup. I do not think this should
// be needed, but it can't hurt to do it just in case.
LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE);
// They are destroying the dialog, so unhook ourselves
// and clean up the dialog (if we have not done it yet).
if(lpfr->lpfnHook == &FRHookProcFind)
{
// Find dialog, not yet cleaned up
lpfr->lpfnHook = lpgti->pfnFindText;
if(lpfr->lpfnHook == NULL)
lpfr->Flags &= ~FR_ENABLEHOOK;
}
else if(lpfr->lpfnHook == &FRHookProcReplace)
{
// Replace dialog, not yet cleaned up
lpfr->lpfnHook = lpgti->pfnReplaceText;
if(lpfr->lpfnHook == NULL)
lpfr->Flags &= ~FR_ENABLEHOOK;
}
}
}
else if((Msg == msgHELPMSGSTRING) &&
((LPCHOOSEFONTA)lParamW)->lStructSize == sizeof(CHOOSEFONTA))
{
LPCHOOSEFONTW lpcf = (LPCHOOSEFONTW)lParamW;
CHOOSEFONTA cfA;
ALLOCRETURN ar = arNoAlloc;
// lParam is an LPCHOOSEFONTW to be converted. Copy all the
// members that the user might expect.
ZeroMemory(&cfA, sizeof(CHOOSEFONTA));
cfA.lStructSize = sizeof(CHOOSEFONTA);
cfA.hDC = lpcf->hDC;
LogFontAfromW(cfA.lpLogFont, lpcf->lpLogFont);
cfA.iPointSize = lpcf->iPointSize;
cfA.Flags = lpcf->Flags;
cfA.rgbColors = lpcf->rgbColors;
cfA.lCustData = lpcf->lCustData;
ar = GodotToAcpOnHeap(lpcf->lpszStyle, &(cfA.lpszStyle));
cfA.nFontType = lpcf->nFontType;
cfA.nSizeMin = lpcf->nSizeMin;
cfA.nSizeMax = lpcf->nSizeMax;
retval = TransmitHelper(mt, hWnd, Msg, wParamW, (LPARAM)&cfA, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
if(ar==arAlloc)
GodotHeapFree(cfA.lpszStyle);
break;
}
else
{
// No translation needed
retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW, lpPrevWndFunc,
lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
break;
}
}
}
return (retval);
}
/*-------------------------------
TransmitHelper
Our helper function that handles the proper one of
the twelve functions that call GodotTransmitMessage
-------------------------------*/
LRESULT TransmitHelper(
MESSAGETYPES mt,
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
WNDPROC lpPrevWndFunc,
SENDASYNCPROC lpCallBack,
ULONG_PTR dwData,
UINT fuFlags,
UINT uTimeout,
PDWORD_PTR lpdwResult
)
{
LRESULT RetVal;
switch(mt)
{
case mtSendMessage:
{
// We have to special case the WM_MDICREATE case, because it creates a window and we
// thus have to do the hook, etc. Note that currently it is only done in SendMessage,
// not in any other call -- this matches the docs, and we cannot risk hitting a
// recursive situation here.
if(Msg==WM_MDICREATE)
{
LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE);
if(lpgti)
INIT_WINDOW_SNIFF(lpgti->hHook);
RetVal=SendMessageA(hWnd, Msg, wParam, lParam);
if(lpgti)
TERM_WINDOW_SNIFF(lpgti->hHook);
}
else
{
RetVal=SendMessageA(hWnd, Msg, wParam, lParam);
}
break;
}
case mtSendMessageCallback:
RetVal=(LRESULT)SendMessageCallbackA(hWnd, Msg, wParam, lParam, lpCallBack, dwData);
break;
case mtSendMessageTimeout:
RetVal=SendMessageTimeoutA(hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult);
break;
case mtSendNotifyMessage:
RetVal=(LRESULT)SendNotifyMessageA(hWnd, Msg, wParam, lParam);
break;
case mtPostMessage:
RetVal=(LRESULT)PostMessageA(hWnd, Msg, wParam, lParam);
break;
case mtPostThreadMessage:
// hWnd is overloaded in this case to be the thread ID
RetVal=(LRESULT)PostThreadMessageA((DWORD)hWnd, Msg, wParam, lParam);
break;
case mtCallWindowProc:
case mtCallWindowProcA:
{
WNDPROC lpfn = WndprocFromFauxWndproc(hWnd, lpPrevWndFunc, fptUnknown);
// If the wndproc was not a "faux" one or if the wndproc
// is expecting ANSI (or both!), then use CallWindowProcA,
// since that is what the wndproc would expect. Otherwise,
// use Unicode and call the function directly.
if((lpfn==lpPrevWndFunc) || (DoesProcExpectAnsi(hWnd, lpfn, fptUnknown)))
{
if(lpfn)
RetVal=((CallWindowProcA)(lpfn, hWnd, Msg, wParam, lParam));
}
else
{
if(lpfn)
RetVal=((* lpfn)(hWnd, Msg, wParam, lParam));
}
break;
}
case mtDefWindowProc:
RetVal=DefWindowProcA(hWnd, Msg, wParam, lParam);
break;
case mtDefDlgProc:
RetVal=DefDlgProcA(hWnd, Msg, wParam, lParam);
break;
case mtDefFrameProc:
// dwData is overload in this case to ve the second hWnd param
RetVal=DefFrameProcA(hWnd, (HWND)dwData, Msg, wParam, lParam);
break;
case mtDefMDIChildProc:
RetVal=DefMDIChildProcA(hWnd, Msg, wParam, lParam);
break;
case mtBroadcastSystemMessage:
if (s_pfnBSMA == NULL)
{
s_pfnBSMA = (PFNbsma)GetProcAddress(GetUserHandle(), "BroadcastSystemMessageA");
if (s_pfnBSMA == NULL)
s_pfnBSMA = (PFNbsma)GetProcAddress(GetUserHandle(), "BroadcastSystemMessage");
}
if (s_pfnBSMA)
// fuFlags is overloaded here as the dwFlags broadcast options
// lpdwResult is overloaded here as the passed in lpdwRecipients
RetVal=(s_pfnBSMA((DWORD)fuFlags, lpdwResult, Msg, wParam, lParam));
else
{
// Should be impossible!!!
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
RetVal=(-1);
}
break;
default:
// Should also be impossible!!!
RetVal=(0);
break;
}
return(RetVal);
}
/*-------------------------------
GodotReceiveMessage
Our global wrapper for getting messages (GetMessage, et. al.). Does all precall
and postcall conversions needed for any string values that are used
-------------------------------*/
BOOL GodotReceiveMessage(MESSAGETYPES mt, LPMSG lpMsg, HWND hWnd, UINT wMin, UINT wMax, UINT wRemoveMsg)
{
BOOL retval;
MSG MsgA;
// call stuff
switch(mt)
{
case mtGetMessage:
retval = (GetMessageA)(&MsgA, hWnd, wMin, wMax);
break;
case mtPeekMessage:
retval = (PeekMessageA)(&MsgA, hWnd, wMin, wMax, wRemoveMsg);
break;
}
// Copy some defaults (we will override for specific messages, as needed)
lpMsg->wParam = MsgA.wParam;
lpMsg->lParam = MsgA.lParam;
lpMsg->hwnd = MsgA.hwnd;
lpMsg->message = MsgA.message;
lpMsg->time = MsgA.time;
lpMsg->pt.x = MsgA.pt.x;
lpMsg->pt.y = MsgA.pt.y;
// The caller is always expecting Unicode here, so we must ALWAYS convert.
switch(MsgA.message)
{
case EM_SETPASSWORDCHAR:
case WM_CHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case WM_MENUCHAR:
case WM_IME_CHAR:
case WM_IME_COMPOSITION:
// All these messages require the wParam to be converted to Unicode
MultiByteToWideChar(g_acp, 0, (char *)&(MsgA.wParam), g_mcs, (WCHAR *)&(lpMsg->wParam), 1);
break;
case WM_CHARTOITEM:
{
// Mask off the hiword bits, convert, then stick the hiword bits back on.
WPARAM wpT = MsgA.wParam & 0xFFFF;
MultiByteToWideChar(g_acp, 0, (char *)&(wpT), g_mcs, (WCHAR *)&(lpMsg->wParam), 1);
lpMsg->wParam = MAKELONG(LOWORD(wpT),HIWORD(MsgA.wParam));
break;
}
case CB_ADDSTRING:
case CB_DIR:
case CB_FINDSTRING:
case CB_FINDSTRINGEXACT:
case CB_INSERTSTRING:
case CB_SELECTSTRING:
{
LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
if(!(((styl & CBS_OWNERDRAWFIXED) ||
(styl & CBS_OWNERDRAWVARIABLE)) &&
(!(styl & CBS_HASSTRINGS))))
{
// Owner draw combo box which does not have strings stored
// (See Windows Bugs # 356304 for details here)
if(FSTRING_VALID((LPSTR)(MsgA.lParam)))
{
MultiByteToWideChar(g_acp, 0,
(LPSTR)(MsgA.lParam), ((MsgA.wParam) * g_mcs),
(LPWSTR)(lpMsg->lParam), MsgA.wParam);
}
}
}
break;
case LB_ADDSTRING:
case LB_ADDFILE:
case LB_DIR:
case LB_FINDSTRING:
case LB_FINDSTRINGEXACT:
case LB_INSERTSTRING:
case LB_SELECTSTRING:
{
LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
if(!(((styl & LBS_OWNERDRAWFIXED) ||
(styl & LBS_OWNERDRAWVARIABLE)) &&
(!(styl & LBS_HASSTRINGS))))
{
// Owner draw listbox which does not have strings stored
// (See Windows Bugs # 356304 for details here)
if(FSTRING_VALID((LPSTR)(MsgA.lParam)))
{
MultiByteToWideChar(g_acp, 0,
(LPSTR)(MsgA.lParam), ((MsgA.wParam) * g_mcs),
(LPWSTR)(lpMsg->lParam), MsgA.wParam);
}
}
}
break;
case EM_REPLACESEL:
case WM_SETTEXT:
case WM_DEVMODECHANGE:
case WM_SETTINGCHANGE:
case WM_SETMESSAGESTRING: // MFC internal msg
if(FSTRING_VALID((LPSTR)(MsgA.lParam)))
{
// All these messages require the lParam to be converted to Unicode
// CONSIDER: Is that string buffer size right?
MultiByteToWideChar(g_acp, 0,
(LPSTR)(MsgA.lParam), ((MsgA.wParam) * g_mcs),
(LPWSTR)(lpMsg->lParam), MsgA.wParam);
}
case WM_DDE_EXECUTE:
// wParam is the client window hWnd, lParam is the command LPTSTR.
// Only convert lParam if both client and server windows are Unicode
if(GetUnicodeWindowProp((HWND)lpMsg->wParam))
{
MultiByteToWideChar(g_acp, 0,
(LPSTR)(MsgA.lParam), ((MsgA.wParam) * g_mcs),
(LPWSTR)(lpMsg->lParam), MsgA.wParam);
}
break;
}
// Get out of here
return (retval);
}
/*-------------------------------
GodotDispatchMessage
Handles all the message dispatch functions
-------------------------------*/
LRESULT GodotDispatchMessage(MESSAGETYPES mt, HWND hDlg, HACCEL hAccTable, LPMSG lpMsg)
{
// Begin locals
LRESULT RetVal;
ALLOCRETURN ar = arNoAlloc;
MSG MsgA;
// We will override some of these params later, as needed
MsgA.wParam = lpMsg->wParam;
MsgA.lParam = lpMsg->lParam;
MsgA.hwnd = lpMsg->hwnd;
MsgA.message = lpMsg->message;
MsgA.time = lpMsg->time;
MsgA.pt = lpMsg->pt;
// The caller is always passing Unicode here, so we must ALWAYS convert.
switch(lpMsg->message)
{
case EM_SETPASSWORDCHAR:
case WM_CHAR:
case WM_DEADCHAR:
case WM_SYSCHAR:
case WM_SYSDEADCHAR:
case WM_MENUCHAR:
case WM_IME_CHAR:
case WM_IME_COMPOSITION:
// All these messages require the wParam to be converted from Unicode
WideCharToMultiByte(g_acp, 0,
(WCHAR *)&(lpMsg->wParam), 1,
(CHAR *)&(MsgA.wParam), g_mcs, NULL, NULL);
break;
case WM_CHARTOITEM:
{
// Mask off the hiword bits, convert, then stick the hiword bits back on.
WPARAM wpT = lpMsg->wParam & 0xFFFF;
WideCharToMultiByte(g_acp, 0,
(WCHAR *)&(wpT), 1,
(CHAR *)&(MsgA.wParam), g_mcs, NULL, NULL);
MsgA.wParam = MAKELONG(LOWORD(wpT),HIWORD(lpMsg->wParam));
break;
}
case CB_ADDSTRING:
case LB_ADDFILE:
case CB_DIR:
case CB_FINDSTRING:
case CB_FINDSTRINGEXACT:
case CB_INSERTSTRING:
case CB_SELECTSTRING:
{
LONG styl = GetWindowLongA(hDlg, GWL_STYLE);
if(!(((styl & CBS_OWNERDRAWFIXED) ||
(styl & CBS_OWNERDRAWVARIABLE)) &&
(!(styl & CBS_HASSTRINGS))))
{
// Owner draw combobox which does not have strings stored
// (See Windows Bugs # 356304 for details here)
ar = GodotToAcpOnHeap((LPWSTR)(lpMsg->lParam), &(LPSTR)(MsgA.lParam));
}
break;
}
case LB_ADDSTRING:
case LB_DIR:
case LB_FINDSTRING:
case LB_FINDSTRINGEXACT:
case LB_INSERTSTRING:
case LB_SELECTSTRING:
{
LONG styl = GetWindowLongA(hDlg, GWL_STYLE);
if(!(((styl & LBS_OWNERDRAWFIXED) ||
(styl & LBS_OWNERDRAWVARIABLE)) &&
(!(styl & LBS_HASSTRINGS))))
{
// Owner draw listbox which does not have strings stored
// (See Windows Bugs # 356304 for details here)
ar = GodotToAcpOnHeap((LPWSTR)(lpMsg->lParam), &(LPSTR)(MsgA.lParam));
}
break;
}
case EM_REPLACESEL:
case WM_SETTEXT:
case WM_DEVMODECHANGE:
case WM_SETTINGCHANGE:
case WM_SETMESSAGESTRING: // MFC internal msg
// All these messages require the lParam to be converted from Unicode
// It is a full string, so lets treat it as such.
ar = GodotToAcpOnHeap((LPWSTR)(lpMsg->lParam), &(LPSTR)(MsgA.lParam));
break;
case WM_DDE_EXECUTE:
// wParam is the client window hWnd, lParam is the command LPTSTR.
// Only convert lParam if both client and server windows are Unicode
if(GetUnicodeWindowProp((HWND)lpMsg->wParam))
{
ar = GodotToAcpOnHeap((LPWSTR)(lpMsg->lParam), &(LPSTR)(MsgA.lParam));
}
break;
}
switch(mt)
{
case mtDispatchMessage:
RetVal=DispatchMessageA(&MsgA);
break;
case mtIsDialogMessage:
RetVal=(LRESULT)IsDialogMessageA(hDlg, &MsgA);
break;
case mtTranslateAccelerator:
RetVal = (LRESULT)TranslateAcceleratorA(hDlg, hAccTable, &MsgA);
break;
}
// If we used some heap memory then free it now
if(ar == arAlloc)
GodotHeapFree((LPSTR)(MsgA.lParam));
return(RetVal);
}