From 3756ae7c8dc60d459511d0b067ebef5efb052746 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Wed, 10 Aug 2022 19:24:24 -0500 Subject: Use IFileOpenDialog instead of SHBrowseForFolder and GetOpenFileName. It is the recommended option since Vista and has better long path support. --- src/libs/dutil/WixToolset.DUtil/inc/wndutil.h | 27 +++++ src/libs/dutil/WixToolset.DUtil/thmutil.cpp | 67 +++++------ src/libs/dutil/WixToolset.DUtil/wndutil.cpp | 157 ++++++++++++++++++++++++++ 3 files changed, 214 insertions(+), 37 deletions(-) (limited to 'src/libs') diff --git a/src/libs/dutil/WixToolset.DUtil/inc/wndutil.h b/src/libs/dutil/WixToolset.DUtil/inc/wndutil.h index 8de77f6e..ad4e07b0 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/wndutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/wndutil.h @@ -35,6 +35,33 @@ HRESULT DAPI WnduGetControlText( __inout_z LPWSTR* psczText ); +/******************************************************************** + WnduShowOpenFileDialog - shows the system dialog to select a file for opening. + +*******************************************************************/ +HRESULT DAPI WnduShowOpenFileDialog( + __in_opt HWND hwndParent, + __in BOOL fForcePathExists, + __in BOOL fForceFileExists, + __in_opt LPCWSTR wzTitle, + __in_opt COMDLG_FILTERSPEC* rgFilters, + __in DWORD cFilters, + __in DWORD dwDefaultFilter, + __in_opt LPCWSTR wzDefaultPath, + __inout LPWSTR* psczPath + ); + +/******************************************************************** + WnduShowOpenFolderDialog - shows the system dialog to select a folder. + +*******************************************************************/ +HRESULT DAPI WnduShowOpenFolderDialog( + __in_opt HWND hwndParent, + __in BOOL fForceFileSystem, + __in_opt LPCWSTR wzTitle, + __inout LPWSTR* psczPath + ); + #ifdef __cplusplus } #endif diff --git a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp index 52a52a1e..f7f7c5b6 100644 --- a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp @@ -4992,54 +4992,47 @@ static void OnBrowseDirectory( ) { HRESULT hr = S_OK; - WCHAR wzPath[MAX_PATH] = { }; - BROWSEINFOW browseInfo = { }; - PIDLIST_ABSOLUTE pidl = NULL; + LPWSTR sczPath = NULL; + THEME_CONTROL* pTargetControl = NULL; + BOOL fSetVariable = NULL != pTheme->pfnSetStringVariable; - browseInfo.hwndOwner = pTheme->hwndParent; - browseInfo.pszDisplayName = wzPath; - browseInfo.lpszTitle = pTheme->sczCaption; - browseInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI; - pidl = ::SHBrowseForFolderW(&browseInfo); - if (pidl && ::SHGetPathFromIDListW(pidl, wzPath)) + hr = WnduShowOpenFolderDialog(pTheme->hwndParent, TRUE, pTheme->sczCaption, &sczPath); + if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr) { - // Since editbox changes aren't immediately saved off, we have to treat them differently. - THEME_CONTROL* pTargetControl = NULL; - BOOL fSetVariable = NULL != pTheme->pfnSetStringVariable; - - for (DWORD i = 0; i < pTheme->cControls; ++i) - { - THEME_CONTROL* pControl = pTheme->rgControls + i; - - if ((!pControl->wPageId || pControl->wPageId == pTheme->dwCurrentPageId) && - CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pControl->sczName, -1, pAction->BrowseDirectory.sczVariableName, -1)) - { - pTargetControl = pControl; - break; - } - } + ExitFunction(); + } + ThmExitOnFailure(hr, "Failed to prompt user for directory."); - if (pTargetControl && !pTargetControl->fDisableAutomaticFunctionality && (!fSetVariable || THEME_CONTROL_TYPE_EDITBOX == pTargetControl->type)) - { - fSetVariable = FALSE; - hr = ThemeSetTextControl(pTargetControl, wzPath); - ThmExitOnFailure(hr, "Failed to set text on control: %ls", pTargetControl->sczName); - } + for (DWORD i = 0; i < pTheme->cControls; ++i) + { + THEME_CONTROL* pControl = pTheme->rgControls + i; - if (fSetVariable) + if ((!pControl->wPageId || pControl->wPageId == pTheme->dwCurrentPageId) && + CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pControl->sczName, -1, pAction->BrowseDirectory.sczVariableName, -1)) { - hr = pTheme->pfnSetStringVariable(pAction->BrowseDirectory.sczVariableName, wzPath, FALSE, pTheme->pvVariableContext); - ThmExitOnFailure(hr, "Failed to set variable: %ls", pAction->BrowseDirectory.sczVariableName); + pTargetControl = pControl; + break; } + } - ThemeShowPageEx(pTheme, pTheme->dwCurrentPageId, SW_SHOW, THEME_SHOW_PAGE_REASON_REFRESH); + // Since editbox changes aren't immediately saved off, we have to treat them differently. + if (pTargetControl && !pTargetControl->fDisableAutomaticFunctionality && (!fSetVariable || THEME_CONTROL_TYPE_EDITBOX == pTargetControl->type)) + { + fSetVariable = FALSE; + hr = ThemeSetTextControl(pTargetControl, sczPath); + ThmExitOnFailure(hr, "Failed to set text on control: %ls", pTargetControl->sczName); } -LExit: - if (pidl) + if (fSetVariable) { - ::CoTaskMemFree(pidl); + hr = pTheme->pfnSetStringVariable(pAction->BrowseDirectory.sczVariableName, sczPath, FALSE, pTheme->pvVariableContext); + ThmExitOnFailure(hr, "Failed to set variable: %ls", pAction->BrowseDirectory.sczVariableName); } + + ThemeShowPageEx(pTheme, pTheme->dwCurrentPageId, SW_SHOW, THEME_SHOW_PAGE_REASON_REFRESH); + +LExit: + ReleaseStr(sczPath); } static BOOL OnButtonClicked( diff --git a/src/libs/dutil/WixToolset.DUtil/wndutil.cpp b/src/libs/dutil/WixToolset.DUtil/wndutil.cpp index b75b0491..5d832e50 100644 --- a/src/libs/dutil/WixToolset.DUtil/wndutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/wndutil.cpp @@ -161,6 +161,163 @@ LExit: } +DAPI_(HRESULT) WnduShowOpenFileDialog( + __in_opt HWND hwndParent, + __in BOOL fForcePathExists, + __in BOOL fForceFileExists, + __in_opt LPCWSTR wzTitle, + __in COMDLG_FILTERSPEC* rgFilters, + __in DWORD cFilters, + __in DWORD dwDefaultFilter, + __in_opt LPCWSTR wzDefaultPath, + __inout LPWSTR* psczPath + ) +{ + HRESULT hr = S_OK; + IFileOpenDialog* pFileOpenDialog = NULL; + FILEOPENDIALOGOPTIONS fos = 0; + FILEOPENDIALOGOPTIONS additionalFlags = FOS_NOCHANGEDIR; + IShellItem* psi = NULL; + LPWSTR sczDefaultDirectory = NULL; + LPWSTR sczPath = NULL; + + hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpenDialog)); + WnduExitOnFailure(hr, "Failed to create FileOpenDialog object."); + + hr = pFileOpenDialog->SetTitle(wzTitle); + WnduExitOnFailure(hr, "Failed to set FileOpenDialog title."); + + hr = pFileOpenDialog->GetOptions(&fos); + WnduExitOnFailure(hr, "Failed to get FileOpenDialog options."); + + if (fForcePathExists) + { + additionalFlags |= FOS_PATHMUSTEXIST; + } + + if (fForceFileExists) + { + additionalFlags |= FOS_FILEMUSTEXIST; + } + + hr = pFileOpenDialog->SetOptions(fos | additionalFlags); + WnduExitOnFailure(hr, "Failed to set FileOpenDialog options."); + + hr = pFileOpenDialog->SetFileTypes(cFilters, rgFilters); + WnduExitOnFailure(hr, "Failed to set FileOpenDialog file types."); + + hr = pFileOpenDialog->SetFileTypeIndex(dwDefaultFilter); + WnduExitOnFailure(hr, "Failed to set FileOpenDialog default file type."); + + if (wzDefaultPath && *wzDefaultPath) + { + hr = PathGetDirectory(wzDefaultPath, &sczDefaultDirectory); + if (SUCCEEDED(hr)) + { + hr = ::SHCreateItemFromParsingName(sczDefaultDirectory, NULL, IID_PPV_ARGS(&psi)); + if (SUCCEEDED(hr)) + { + hr = pFileOpenDialog->SetFolder(psi); + WnduExitOnFailure(hr, "Failed to set FileOpenDialog folder."); + } + + ReleaseNullObject(psi); + } + + hr = pFileOpenDialog->SetFileName(wzDefaultPath); + WnduExitOnFailure(hr, "Failed to set FileOpenDialog file name."); + } + + hr = pFileOpenDialog->Show(hwndParent); + if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr) + { + ExitFunction(); + } + WnduExitOnFailure(hr, "Failed to show FileOpenDialog for file."); + + hr = pFileOpenDialog->GetResult(&psi); + WnduExitOnFailure(hr, "Failed to get FileOpenDialog result."); + + hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &sczPath); + WnduExitOnFailure(hr, "Failed to get FileOpenDialog result path."); + + hr = StrAllocString(psczPath, sczPath, 0); + WnduExitOnFailure(hr, "Failed to copy FileOpenDialog result path."); + +LExit: + if (sczPath) + { + ::CoTaskMemFree(sczPath); + } + + ReleaseStr(sczDefaultDirectory); + ReleaseObject(psi); + ReleaseObject(pFileOpenDialog); + + return hr; +} + + +DAPI_(HRESULT) WnduShowOpenFolderDialog( + __in_opt HWND hwndParent, + __in BOOL fForceFileSystem, + __in_opt LPCWSTR wzTitle, + __inout LPWSTR* psczPath + ) +{ + HRESULT hr = S_OK; + IFileOpenDialog* pFileOpenDialog = NULL; + FILEOPENDIALOGOPTIONS fos = 0; + FILEOPENDIALOGOPTIONS additionalFlags = FOS_PICKFOLDERS | FOS_NOCHANGEDIR; + IShellItem* psi = NULL; + LPWSTR sczPath = NULL; + + hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpenDialog)); + WnduExitOnFailure(hr, "Failed to create FileOpenDialog object."); + + hr = pFileOpenDialog->SetTitle(wzTitle); + WnduExitOnFailure(hr, "Failed to set FileOpenDialog title."); + + hr = pFileOpenDialog->GetOptions(&fos); + WnduExitOnFailure(hr, "Failed to get FileOpenDialog options."); + + if (fForceFileSystem) + { + additionalFlags |= FOS_FORCEFILESYSTEM; + } + + hr = pFileOpenDialog->SetOptions(fos | additionalFlags); + WnduExitOnFailure(hr, "Failed to set FileOpenDialog options."); + + hr = pFileOpenDialog->Show(hwndParent); + if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr) + { + ExitFunction(); + } + WnduExitOnFailure(hr, "Failed to show FileOpenDialog for folder."); + + hr = pFileOpenDialog->GetResult(&psi); + WnduExitOnFailure(hr, "Failed to get FileOpenDialog result."); + + hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &sczPath); + WnduExitOnFailure(hr, "Failed to get FileOpenDialog result path."); + + hr = StrAllocString(psczPath, sczPath, 0); + WnduExitOnFailure(hr, "Failed to copy FileOpenDialog result path."); + +LExit: + if (sczPath) + { + ::CoTaskMemFree(sczPath); + } + + ReleaseObject(psi); + ReleaseObject(pFileOpenDialog); + + return hr; +} + + static DWORD CALLBACK RichEditStreamFromFileHandleCallback( __in DWORD_PTR dwCookie, __in_bcount(cb) LPBYTE pbBuff, -- cgit v1.2.3-55-g6feb