|
|
/*++
Copyright (c) 2000-2001, Microsoft Corporation All rights reserved.
Module Name:
hook.c
Abstract:
This file contains functions that wrap various hook procedures, and the helper functions that support their efforts.
Hooks found in this file: WindowProc DialogProc CBTProc EnumChildToTagProc
comdlg32.dll hooks: FRHookProcFind FRHookProcReplace OFNHookProc OFNHookProcSave PagePaintHook CCHookProc CFHookProc PageSetupHook PrintHookProc SetupHookProc OFNHookProcOldStyle OFNHookProcOldStyleSave
Helper functions: FRHelper UpdateTextAndFlags NotifyFindReplaceParent OFNHookHelper OFNotifyHelper GenericHookHelper RemoveFontPropIfPresent SetNewFileOpenProp SetFontProp
Externally available helper functions: IsFontDialog IsNewFileOpenDialog IsCaptureWindow SetCaptureWindowProp
Revision History:
27 Jan 2001 v-michka Created.
--*/
#include "precomp.h"
// Stolen from commdlg.h
#define CCHCLOSE 9
#define iszClose 0x040d // "Close" text for find/replace
static WCHAR m_szClose [CCHCLOSE];
// So we can keep track of font dialogs
const char m_szComdlgClass[] = "GodotComdlgClass"; ATOM m_aComdlgClass;
#define CHOOSEFONT_DIALOG (HANDLE)1
#define NEWFILEOPEN_DIALOG (HANDLE)2
#define CAPTURE_WINDOW (HANDLE)3 // Not really a common dialog, but close enough
// forward declares we will need -- we must have Unicode text, so
// why write new wrappers when we have some lying around already?
UINT __stdcall GodotGetDlgItemTextW(HWND hDlg, int nIDDlgItem, LPWSTR lpString, int nMaxCount); int __stdcall GodotLoadStringW(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int nBufferMax); BOOL __stdcall GodotSetWindowTextW(HWND hWnd, LPCWSTR lpString); LRESULT __stdcall GodotSendMessageW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
// our own forward declares
BOOL CALLBACK EnumChildToTagProc(HWND hwnd, LPARAM lParam); UINT FRHelper(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam, BOOL fFindText); VOID UpdateTextAndFlags(HWND hDlg, LPFINDREPLACEW lpfrw, DWORD dwActionFlag, BOOL fFindText); LRESULT NotifyFindReplaceParent(LPFINDREPLACEW lpfr, LPFRHOOKPROC lpfrhp, UINT uMsg, BOOL fFindText); UINT_PTR OFNHookHelperOldStyle(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam, WNDPROC lpfn); UINT_PTR OFNHookHelper(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam, BOOL fOpenFile); UINT_PTR OFNotifyHelper(HWND hdlg, WNDPROC lpfn, WPARAM wParam, LPARAM lParam); UINT_PTR GenericHookHelper(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam, WNDPROC lpfn); void SetFontProp(HWND hdlg); void SetNewFileOpenProp(HWND hdlg);
/*-------------------------------
WindowProc This is our global wrapper around *all* window procedrures for windows that we create or subclass. -------------------------------*/ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT RetVal; WNDPROC lpfn = WndprocFromFauxWndproc(hwnd, 0, fptWndproc);
// Chain to the user's wndproc
RetVal = GodotDoCallback(hwnd, uMsg, wParam, lParam, lpfn, FALSE, fptWndproc);
// If we get a final destroy message, lets unhook ourselves
if(uMsg==WM_NCDESTROY) CleanupWindow(hwnd);
return(RetVal); }
/*-------------------------------
DialogProc This is our global wrapper around *all* dialog procedrures for windows that we create or subclass. -------------------------------*/ INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { DLGPROC lpfn; INT_PTR RetVal; LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE);
// See if we have a DLGPROC waiting to be assigned somewhere.
if(lpgti && lpgti->pfnDlgProc) { // Perhaps it is for *this* dialog. We must make sure it is, or else we will be
// assigning the proc to the wrong window! See Windows Bugs # 350862 for details.
if(OUTSIDE_GODOT_RANGE(GetWindowLongInternal(hwndDlg, DWL_DLGPROC, TRUE))) { // Set the dlg proc and clear out the dlg proc pointer
lpfn = (DLGPROC)SetWindowLongInternal(hwndDlg, DWL_DLGPROC, (LONG)lpgti->pfnDlgProc, TRUE); lpgti->pfnDlgProc = NULL; } }
// Preprocess: also set some RetVal values, which may
// or may not be overridden by the user's dlgproc.
switch(uMsg) { case WM_CTLCOLORBTN: case WM_CTLCOLORDLG: case WM_CTLCOLOREDIT: case WM_CTLCOLORLISTBOX: case WM_CTLCOLORSCROLLBAR: case WM_CTLCOLORSTATIC: case WM_VKEYTOITEM: RetVal = (INT_PTR)(BOOL)FALSE; break; case WM_INITDIALOG: // Mark all the children now: before the client gets a
// chance to init controls, but afte we are sure the
// controls exist.
EnumChildWindows(hwndDlg, &EnumChildToTagProc, 0); RetVal = (INT_PTR)(BOOL)FALSE; break;
case WM_CHARTOITEM: case WM_COMPAREITEM: // The user's proc MUST do something for these messages,
// we have no idea what to return here!
RetVal = 0; break;
case WM_QUERYDRAGICON: RetVal = (INT_PTR)NULL; break;
default: RetVal = (INT_PTR)(BOOL)FALSE; break; } // Chain to the user's dialog procedure. They ought to have one, right?
if(lpfn = WndprocFromFauxWndproc(hwndDlg, 0, fptDlgproc)) RetVal = GodotDoCallback(hwndDlg, uMsg, wParam, lParam, lpfn, FALSE, fptDlgproc);
return(RetVal); }
/*-------------------------------
CBTProc
This is our CBT hook that we use to get information about a window about to be created. We also do our window subclassing here so we can be assured that we are handling the messages properly. -------------------------------*/ LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam) { LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE); HHOOK hh = (lpgti ? lpgti->hHook : NULL);
switch(nCode) { // We only care about the window creation notification
case HCBT_CREATEWND: { LRESULT RetVal;
InitWindow((HWND)wParam, NULL);
RetVal = CallNextHookEx(hh, nCode, wParam, lParam);
// Make sure no one cancelled window creation; if they did, the
// window will be destroyed without a WM_DESTROY call. Therefore
// we must be sure to clean ourselves up or we will watch Windows
// lose our global atom!
if(RetVal != 0) CleanupWindow((HWND)wParam);
// Lets unhook here, we have done our duty
TERM_WINDOW_SNIFF(hh); return(RetVal); break; }
default: // Should be impossible, but just in case,
// we do a nice default sorta thing here.
if(hh) return(CallNextHookEx(hh, nCode, wParam, lParam)); else return(0); break; } }
/*-------------------------------
EnumChildToTagProc
Tag some child windows -------------------------------*/ BOOL CALLBACK EnumChildToTagProc(HWND hwnd, LPARAM lParam) { InitWindow(hwnd, NULL);
// Keep on enumerating
return(TRUE); }
/*-------------------------------
FRHookProcFind/FRHookProcReplace -------------------------------*/ UINT_PTR CALLBACK FRHookProcFind(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { return(FRHelper(hdlg, uiMsg, wParam, lParam, TRUE)); } UINT_PTR CALLBACK FRHookProcReplace(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { return(FRHelper(hdlg, uiMsg, wParam, lParam, FALSE)); }
/*-------------------------------
// OFNHookProc/OFNHookProcSave
-------------------------------*/ UINT_PTR CALLBACK OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { return(OFNHookHelper(hdlg, uiMsg, wParam, lParam, TRUE)); } UINT_PTR CALLBACK OFNHookProcSave(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { return(OFNHookHelper(hdlg, uiMsg, wParam, lParam, FALSE)); }
/*-------------------------------
// PagePaintHook
//
//
// We use this hook to handle the WM_PSD_PAGESETUPDLG when it comes through
-------------------------------*/ UINT_PTR CALLBACK PagePaintHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE); WNDPROC lpfnP = (lpgti ? lpgti->pfnPagePaint : NULL);
if(uiMsg != WM_PSD_PAGESETUPDLG) return(GenericHookHelper(hdlg, uiMsg, wParam, lParam, lpfnP)); else { // Ok, this is the WM_PSD_PAGESETUPDLG event. wParam is some random stuff
// to pass on and lParam is a PAGESETUPDLGA structure that we need to turn
// into a PAGESETUPDLGW.
if(lpfnP) { LPPAGESETUPDLGA lppsda; PAGESETUPDLGW psdw; UINT_PTR RetVal; ALLOCRETURN ar = arNoAlloc; WNDPROC lpfnS = (lpgti ? lpgti->pfnPageSetup : NULL);
lppsda = (LPPAGESETUPDLGA)lParam; psdw.lStructSize = sizeof(PAGESETUPDLGW);
// Copy some stuff over now
psdw.hwndOwner = lppsda->hwndOwner; psdw.ptPaperSize = lppsda->ptPaperSize; psdw.rtMinMargin = lppsda->rtMinMargin; psdw.rtMargin = lppsda->rtMargin; psdw.hInstance = lppsda->hInstance; psdw.lCustData = lppsda->lCustData; // Do NOT deallocate the HGLOBALS here, someone else might
// need them! Passing FALSE for the fFree param accomplishes
// this feat.
psdw.hDevMode = HDevModeWfromA(&(lppsda->hDevMode), FALSE); psdw.hDevNames = HDevNamesWfromA(&(lppsda->hDevNames), FALSE);
// Hide the details of our hook from them (by munging flags as
// necessary)
psdw.Flags = lppsda->Flags; if(lpfnP) psdw.Flags &= ~PSD_ENABLEPAGEPAINTHOOK; psdw.lpfnPagePaintHook = lpfnP; if(lpfnS) psdw.Flags &= ~PSD_ENABLEPAGESETUPHOOK; psdw.lpfnPageSetupHook = lpfnS;
if(lppsda->Flags & PSD_ENABLEPAGESETUPTEMPLATE) { psdw.hPageSetupTemplate = lppsda->hPageSetupTemplate; ar = GodotToUnicodeOnHeap(lppsda->lpPageSetupTemplateName, &(LPWSTR)psdw.lpPageSetupTemplateName); }
RetVal = ((* lpfnP)(hdlg, WM_PSD_PAGESETUPDLG, wParam, (LPARAM)&psdw)); if(ar==arAlloc) GodotHeapFree((LPWSTR)psdw.lpPageSetupTemplateName); lppsda->hDevMode = HDevModeAfromW(&(psdw.hDevMode), TRUE); lppsda->hDevNames = HDevNamesAfromW(&(psdw.hDevNames), TRUE); return(RetVal); } else return(FALSE); } }
//
// Ok, here are all our almost but not quite pointless hooks that we have.
// These hooks allow us to make sure that the dialog and all the controls in
// it are tagged appropriately. See GenericHookHelper for details.
//
UINT_PTR CALLBACK CCHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE); return(GenericHookHelper(hdlg, uiMsg, wParam, lParam, (lpgti ? lpgti->pfnChooseColor : NULL))); }
UINT_PTR CALLBACK CFHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE);
if(uiMsg==WM_INITDIALOG) SetFontProp(hdlg); return(GenericHookHelper(hdlg, uiMsg, wParam, lParam, (lpgti ? lpgti->pfnChooseFont : NULL))); }
UINT_PTR CALLBACK PageSetupHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE); return(GenericHookHelper(hdlg, uiMsg, wParam, lParam, (lpgti ? lpgti->pfnPageSetup : NULL))); }
UINT_PTR CALLBACK PrintHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE); return(GenericHookHelper(hdlg, uiMsg, wParam, lParam, (lpgti ? lpgti->pfnPrintDlg : NULL))); }
UINT_PTR CALLBACK SetupHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE); return(GenericHookHelper(hdlg, uiMsg, wParam, lParam, (lpgti ? lpgti->pfnPrintDlgSetup : NULL))); }
UINT_PTR CALLBACK OFNHookProcOldStyle(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE); WNDPROC lpfn = (WNDPROC)(lpgti ? lpgti->pfnGetOpenFileNameOldStyle : NULL); return(OFNHookHelperOldStyle(hdlg, uiMsg, wParam, lParam, lpfn)); }
UINT_PTR CALLBACK OFNHookProcOldStyleSave(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) { LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE); WNDPROC lpfn = (WNDPROC)(lpgti ? lpgti->pfnGetSaveFileNameOldStyle : NULL); return(OFNHookHelperOldStyle(hdlg, uiMsg, wParam, lParam, lpfn)); }
/*-------------------------------
// FRHelper
//
// Used to handle lots of the shared code between the find and replace hook functions. Note
// that some of it does not always apply: certain controls are hidden from the FIND dialog, etc.
// But since all of the code other than the actual callbacks themselves is shared, this keeps
// us from a lot of duplication.
-------------------------------*/ UINT FRHelper(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam, BOOL fFindText) { LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE); LPFRHOOKPROC lpfn = 0; UINT RetVal;
if(!lpgti) { if(lpfn) return((* lpfn)(hdlg, uiMsg, wParam, lParam)); else return(FALSE); }
if(fFindText) lpfn = lpgti->pfnFindText; else lpfn = lpgti->pfnReplaceText;
switch(uiMsg) { case WM_COMMAND: { LPFINDREPLACEW lpfr;
if(fFindText) lpfr = lpgti->lpfrwFind; else lpfr = lpgti->lpfrwReplace; switch(GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: // FIND
UpdateTextAndFlags(hdlg, lpfr, FR_FINDNEXT, fFindText); NotifyFindReplaceParent(lpfr, lpfn, msgFINDMSGSTRING, fFindText); RetVal = TRUE; break; case psh1: // REPLACE
case psh2: // REPLACE ALL
UpdateTextAndFlags(hdlg, lpfr, (psh1 ? FR_REPLACE : FR_REPLACEALL), fFindText); if (NotifyFindReplaceParent(lpfr, lpfn, msgFINDMSGSTRING, fFindText) == TRUE) { // Change <Cancel> button to <Close> if function
// returns TRUE (IDCANCEL instead of psh1).
// First load the string if we never have before
if(m_szClose[0] == 0) GodotLoadStringW(GetComDlgHandle(), iszClose, m_szClose, CCHCLOSE); GodotSetWindowTextW(GetDlgItem(hdlg, IDCANCEL), (LPWSTR)m_szClose); } RetVal = TRUE; break;
case pshHelp: // HELP
if (msgHELPMSGSTRING && lpfr->hwndOwner) { UpdateTextAndFlags(hdlg, lpfr, 0, fFindText); NotifyFindReplaceParent(lpfr, lpfn, msgHELPMSGSTRING, fFindText); } RetVal = TRUE; break; case IDCANCEL: // CANCEL, both types
case IDABORT: // They are destroying the dialog, so unhook ourselves
// and clean up the dialog. Usually the caller will keep
// a FINDREPLACEW lying around, so if we do not clean up
// we might have some re-entrancy issues here.
if(lpfn) lpfr->lpfnHook = lpfn; else { lpfr->lpfnHook = NULL; lpfr->Flags &= ~FR_ENABLEHOOK; }
if(fFindText) { lpgti->lpfrwFind = NULL; lpgti->pfnFindText = NULL; } else { lpgti->lpfrwReplace = NULL; lpgti->pfnReplaceText = NULL; }
// Fall through. We do not set the RetVal to TRUE, since
// we need to make sure that comdlg32.dll cleans up
default: // Everything else
RetVal = FALSE; break; } break; }
case WM_INITDIALOG: // Mark all the children now, before the user's proc gets to them
EnumChildWindows(hdlg, &EnumChildToTagProc, 0); // Perhaps the caller's hook will override this, but we need to cover
// our bases in case there the caller has no hook. The caller expects
// us to return TRUE if they are drawing the dlg, FALSE if we are.
RetVal = TRUE; break;
default: RetVal = FALSE; break; }
if(lpfn) RetVal = (* lpfn)(hdlg, uiMsg, wParam, lParam); return(RetVal); }
/*-------------------------------
// OFNHookHelperOldStyle
//
// Almost all of the old style fileopen/save code is shared, and this function shares it!
-------------------------------*/ UINT_PTR OFNHookHelperOldStyle(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam, WNDPROC lpfn) { UINT_PTR RetVal = FALSE;
if(!msgSHAREVISTRING) msgSHAREVISTRING = RegisterWindowMessage(SHAREVISTRINGA); if(!msgFILEOKSTRING) msgFILEOKSTRING = RegisterWindowMessage(FILEOKSTRINGA); if(uiMsg==WM_INITDIALOG) { // Mark all the children now, before the user's proc gets to them
EnumChildWindows(hdlg, &EnumChildToTagProc, 0); if(lpfn) RetVal = (* lpfn)(hdlg, uiMsg, wParam, lParam); else RetVal = TRUE; } else if(((uiMsg == msgFILEOKSTRING) || (uiMsg == msgSHAREVISTRING))) { WCHAR drive[_MAX_DRIVE + 1]; WCHAR dir[_MAX_DIR +1]; WCHAR file[_MAX_FNAME +1]; LPOPENFILENAMEA lpofnA = (LPOPENFILENAMEA)lParam; OPENFILENAMEW ofn; LPARAM lParamW; 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.
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);
lParamW = (LPARAM)&ofn;
if(lpfn) RetVal = (* lpfn)(hdlg, uiMsg, wParam, lParamW);
// 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(lpfn) RetVal = (* lpfn)(hdlg, uiMsg, wParam, lParam); }
return(RetVal); }
/*-------------------------------
// OFNHookHelper
//
// Almost all of the fileopen/save code is shared, and this function shares it!
-------------------------------*/ UINT_PTR OFNHookHelper(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam, BOOL fOpenFile) { UINT_PTR RetVal = 0; LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE); LPOFNHOOKPROC lpfn;
if(fOpenFile) lpfn = (lpgti ? lpgti->pfnGetOpenFileName : NULL); else lpfn = (lpgti ? lpgti->pfnGetSaveFileName : NULL);
if(uiMsg==WM_INITDIALOG) { HWND hwndParent; // Tag the window as a new style file open dlg
SetNewFileOpenProp(hdlg);
if(hwndParent = GetParent(hdlg)) SetNewFileOpenProp(hwndParent); // Mark all the children now, before the user's proc gets to them
EnumChildWindows(hdlg, &EnumChildToTagProc, 0); RetVal = TRUE; }
if(lpfn) { switch(uiMsg) { case WM_NOTIFY: RetVal = OFNotifyHelper(hdlg, lpfn, wParam, lParam); break;
default: RetVal = (* lpfn)(hdlg, uiMsg, wParam, lParam); break; } } return(RetVal); }
/*-------------------------------
// OSNotifyHelper
-------------------------------*/ UINT_PTR OFNotifyHelper(HWND hdlg, WNDPROC lpfn, WPARAM wParam, LPARAM lParam) { UINT_PTR RetVal; LPOFNOTIFYA lpofnfyA = (LPOFNOTIFYA)lParam;
switch(lpofnfyA->hdr.code) { case CDN_FILEOK: case CDN_FOLDERCHANGE: case CDN_HELP: case CDN_INCLUDEITEM: case CDN_INITDONE: case CDN_SELCHANGE: case CDN_SHAREVIOLATION: case CDN_TYPECHANGE: { LPOPENFILENAMEA lpofnA = lpofnfyA->lpOFN; OFNOTIFYW ofnfy; OPENFILENAMEW ofn; WCHAR drive[_MAX_DRIVE]; WCHAR dir[_MAX_DIR]; WCHAR file[_MAX_FNAME]; ALLOCRETURN arCustomFilter = arNoAlloc; ALLOCRETURN arFile = arNoAlloc; ALLOCRETURN arFileTitle = arNoAlloc;
ZeroMemory(&ofnfy, sizeof(OFNOTIFYW)); ofnfy.hdr = lpofnfyA->hdr; ofnfy.lpOFN = &ofn; ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400W; ofn.Flags = lpofnA->Flags; ofn.hwndOwner = lpofnA->hwndOwner; ofn.hInstance = lpofnA->hInstance; ofn.lpfnHook = lpfn; 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); if(ofnfy.hdr.code == CDN_SHAREVIOLATION) { WCHAR lpwzFile[MAX_PATH];
if(FSTRING_VALID(lpofnfyA->pszFile)) { MultiByteToWideChar(g_acp, 0, lpofnfyA->pszFile, -1, lpwzFile, MAX_PATH); ofnfy.pszFile = lpwzFile; } RetVal = (* lpfn)(hdlg, WM_NOTIFY, wParam, (LPARAM)&ofnfy); } else { RetVal = (* lpfn)(hdlg, WM_NOTIFY, wParam, (LPARAM)&ofnfy); }
// 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);
break; }
default: RetVal = (* lpfn)(hdlg, WM_NOTIFY, wParam, lParam); break; } return(RetVal); }
/*-------------------------------
// GenericHookHelper
//
// This function is to assist all the comdlg32 hook functions that serve
// no real purpose that we know of, other than to make sure all the
// child controls get marked as "Unicode" controls, etc.
-------------------------------*/ UINT_PTR GenericHookHelper(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam, WNDPROC lpfn) { UINT_PTR RetVal = FALSE; switch(uiMsg) { case WM_INITDIALOG: // Mark all the children now, before the user's proc gets to them
EnumChildWindows(hdlg, &EnumChildToTagProc, 0); if(lpfn) RetVal = (* lpfn)(hdlg, uiMsg, wParam, lParam); else RetVal = TRUE; break; case WM_DESTROY: case WM_NCDESTROY: default: if(lpfn) RetVal = (* lpfn)(hdlg, uiMsg, wParam, lParam); break; } return(RetVal); }
/*-------------------------------
// UpdateTextAndFlags
//
// Get the text from the control, and update the flags. Use in
// preparation for notifying the owner window that the user has
// done something interesting.
//
// Modified from find.c from the comdlg32 project in the Shell
// depot. It definitely needed its own special spin, though!
//
// chx1 is whether or not to match entire words
// chx2 is whether or not case is relevant
// chx3 is whether or not to wrap scans
-------------------------------*/ VOID UpdateTextAndFlags(HWND hDlg, LPFINDREPLACEW lpfrw, DWORD dwActionFlag, BOOL fFindText) { // Only clear flags that this routine sets. The hook and template
// flags should not be anded off here.
lpfrw->Flags &= ~((DWORD)(FR_WHOLEWORD | FR_MATCHCASE | FR_REPLACE | FR_FINDNEXT | FR_REPLACEALL | FR_DOWN)); if (IsDlgButtonChecked(hDlg, chx1)) lpfrw->Flags |= FR_WHOLEWORD;
if (IsDlgButtonChecked(hDlg, chx2)) lpfrw->Flags |= FR_MATCHCASE;
// Set ACTION flag FR_{REPLACE,FINDNEXT,REPLACEALL}.
lpfrw->Flags |= dwActionFlag;
GodotGetDlgItemTextW(hDlg, edt1, lpfrw->lpstrFindWhat, lpfrw->wFindWhatLen);
if (fFindText) { // Assume searching down. Check if UP button is NOT pressed, rather
// than if DOWN button IS. So, if buttons have been hidden or
// disabled, FR_DOWN flag will be set correctly.
if (!IsDlgButtonChecked(hDlg, rad1)) lpfrw->Flags |= FR_DOWN; } else { GodotGetDlgItemTextW(hDlg, edt2, lpfrw->lpstrReplaceWith, lpfrw->wReplaceWithLen); lpfrw->Flags |= FR_DOWN; } }
/*-------------------------------
// NotifyFindReplaceParent
//
// Let hwndOwner know what is happening, since the user has
// performed some kind of action that they might want to
// know about.
//
// Modified from find.c from the comdlg32 project in the Shell
// depot. It definitely needed its own special spin, though!
-------------------------------*/ LRESULT NotifyFindReplaceParent(LPFINDREPLACEW lpfr, LPFRHOOKPROC lpfrhp, UINT uMsg, BOOL fFindText) { LRESULT RetVal; DWORD Flags;
// Cache the flags setting since we may be mucking with it
Flags = lpfr->Flags;
// Now, muck with the structure a bit
// to hide our hook from the user
if(lpfrhp) lpfr->lpfnHook = lpfrhp; else { lpfr->lpfnHook = NULL; Flags &= ~FR_ENABLEHOOK; }
RetVal = GodotSendMessageW(lpfr->hwndOwner, uMsg, 0, (DWORD_PTR)lpfr);
// Restore the structure to what it was
lpfr->Flags = Flags; if(fFindText) lpfr->lpfnHook = &FRHookProcFind; else lpfr->lpfnHook = &FRHookProcReplace; return(RetVal); }
/*-------------------------------
// IsFontDialog
-------------------------------*/ BOOL IsFontDialog(HWND hdlg) { return((BOOL)(GetPropA(hdlg, m_szComdlgClass) == CHOOSEFONT_DIALOG)); }
/*-------------------------------
// IsNewFileOpenDialog
-------------------------------*/ BOOL IsNewFileOpenDialog(HWND hdlg) { return((BOOL)(GetPropA(hdlg, m_szComdlgClass) == NEWFILEOPEN_DIALOG)); }
/*-------------------------------
// IsCaptureWindow
-------------------------------*/ BOOL IsCaptureWindow(HWND hdlg) { return((BOOL)(GetPropA(hdlg, m_szComdlgClass) == CAPTURE_WINDOW)); }
/*-------------------------------
// RemoveComdlgPropIfPresent
-------------------------------*/ void RemoveComdlgPropIfPresent(HWND hdlg) { if(GetPropA(hdlg, m_szComdlgClass) != 0) RemovePropA(hdlg, m_szComdlgClass); return; }
/*-------------------------------
// SetNewFileOpenProp
-------------------------------*/ void SetNewFileOpenProp(HWND hdlg) { // We have to aggressively refcount our prop to keep anyone from
// losing it. Thus we do an initial GlobalAddAtom on it and then
// subsequently call SetPropA on it with the same string.
if(!m_aComdlgClass) m_aComdlgClass = GlobalAddAtomA(m_szComdlgClass);
SetPropA(hdlg, m_szComdlgClass, (HANDLE)NEWFILEOPEN_DIALOG); return; }
/*-------------------------------
// SetFontProp
-------------------------------*/ void SetFontProp(HWND hdlg) { // We have to aggressively refcount our prop to keep anyone from
// losing it. Thus we do an initial GlobalAddAtom on it and then
// subsequently call SetPropA on it with the same string.
if(!m_aComdlgClass) m_aComdlgClass = GlobalAddAtomA(m_szComdlgClass);
SetPropA(hdlg, m_szComdlgClass, (HANDLE)CHOOSEFONT_DIALOG); return; }
/*-------------------------------
// SetCaptureWindowProp
-------------------------------*/ void SetCaptureWindowProp(HWND hdlg) { // We have to aggressively refcount our prop to keep anyone from
// losing it. Thus we do an initial GlobalAddAtom on it and then
// subsequently call SetPropA on it with the same string.
if(!m_aComdlgClass) m_aComdlgClass = GlobalAddAtomA(m_szComdlgClass);
SetPropA(hdlg, m_szComdlgClass, (HANDLE)CAPTURE_WINDOW); return; }
|