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. --- .../WixStandardBootstrapperApplication.cpp | 26 ++-- 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 +++++++++++++++++++++ src/tools/thmviewer/thmviewer.cpp | 27 ++-- 5 files changed, 234 insertions(+), 70 deletions(-) diff --git a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp index d7b5a269..8544ff0e 100644 --- a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp +++ b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp @@ -1145,26 +1145,19 @@ public: // IBootstrapperApplication ) { HRESULT hr = S_OK; + LPWSTR sczPath = NULL; if (BOOTSTRAPPER_CACHE_RESOLVE_NONE == *pAction && BOOTSTRAPPER_DISPLAY_FULL == m_command.display) // prompt to change the source location. { - OPENFILENAMEW ofn = { }; - WCHAR wzFile[MAX_PATH] = { }; - - ::StringCchCopyW(wzFile, countof(wzFile), rgSearchPaths[dwRecommendedSearchPath]); - - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = m_hWnd; - ofn.lpstrFile = wzFile; - ofn.nMaxFile = countof(wzFile); - ofn.lpstrFilter = L"All Files\0*.*\0"; - ofn.nFilterIndex = 1; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - ofn.lpstrTitle = m_pTheme->sczCaption; + static COMDLG_FILTERSPEC vrgFilters[] = + { + { L"All Files", L"*.*" }, + }; - if (::GetOpenFileNameW(&ofn)) + hr = WnduShowOpenFileDialog(m_hWnd, TRUE, TRUE, m_pTheme->sczCaption, vrgFilters, countof(vrgFilters), 1, rgSearchPaths[dwRecommendedSearchPath], &sczPath); + if (SUCCEEDED(hr)) { - hr = m_pEngine->SetLocalSource(wzPackageOrContainerId, wzPayloadId, ofn.lpstrFile); + hr = m_pEngine->SetLocalSource(wzPackageOrContainerId, wzPayloadId, sczPath); *pAction = BOOTSTRAPPER_CACHE_RESOLVE_RETRY; } else @@ -1175,6 +1168,9 @@ public: // IBootstrapperApplication // else there's nothing more we can do in non-interactive mode *pfCancel |= CheckCanceled(); + + ReleaseStr(sczPath); + return hr; } 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, diff --git a/src/tools/thmviewer/thmviewer.cpp b/src/tools/thmviewer/thmviewer.cpp index 38f3c4dc..4230dd35 100644 --- a/src/tools/thmviewer/thmviewer.cpp +++ b/src/tools/thmviewer/thmviewer.cpp @@ -66,6 +66,13 @@ static void CALLBACK ThmviewerTraceError( __in va_list args ); +static COMDLG_FILTERSPEC vrgFilters[] = +{ + { L"Theme Files (*.thm)", L"*.thm" }, + { L"XML Files (*.xml)", L"*.xml" }, + { L"All Files (*.*)", L"*.*" }, +}; + int WINAPI wWinMain( __in HINSTANCE hInstance, @@ -110,24 +117,8 @@ int WINAPI wWinMain( if (!sczThemeFile) { // Prompt for a path to the theme file. - OPENFILENAMEW ofn = { }; - WCHAR wzFile[MAX_PATH] = { }; - - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hWnd; - ofn.lpstrFile = wzFile; - ofn.nMaxFile = countof(wzFile); - ofn.lpstrFilter = L"Theme Files (*.thm)\0*.thm\0XML Files (*.xml)\0*.xml\0All Files (*.*)\0*.*\0"; - ofn.nFilterIndex = 1; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - ofn.lpstrTitle = vpTheme->sczCaption; - - if (::GetOpenFileNameW(&ofn)) - { - hr = StrAllocString(&sczThemeFile, wzFile, 0); - ExitOnFailure(hr, "Failed to copy opened file to theme file."); - } - else + hr = WnduShowOpenFileDialog(hWnd, TRUE, TRUE, vpTheme->sczCaption, vrgFilters, countof(vrgFilters), 1, NULL, &sczThemeFile); + if (FAILED(hr)) { ::MessageBoxW(hWnd, L"Must specify a path to theme file.", vpTheme->sczCaption, MB_OK | MB_ICONERROR); ExitFunction1(hr = E_INVALIDARG); -- cgit v1.2.3-55-g6feb