|
|
/*++
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); }
|