diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2022-08-10 19:24:24 -0500 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2022-08-10 20:27:48 -0500 |
| commit | 3756ae7c8dc60d459511d0b067ebef5efb052746 (patch) | |
| tree | 5aa0505d3ab4e4337575597bcad9c6fd641ea78d /src/libs | |
| parent | 84e7b6d277e5c3d118e11a45834d420254a758c0 (diff) | |
| download | wix-3756ae7c8dc60d459511d0b067ebef5efb052746.tar.gz wix-3756ae7c8dc60d459511d0b067ebef5efb052746.tar.bz2 wix-3756ae7c8dc60d459511d0b067ebef5efb052746.zip | |
Use IFileOpenDialog instead of SHBrowseForFolder and GetOpenFileName.
It is the recommended option since Vista and has better long path support.
Diffstat (limited to 'src/libs')
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/inc/wndutil.h | 27 | ||||
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/thmutil.cpp | 67 | ||||
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/wndutil.cpp | 157 |
3 files changed, 214 insertions, 37 deletions
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( | |||
| 35 | __inout_z LPWSTR* psczText | 35 | __inout_z LPWSTR* psczText |
| 36 | ); | 36 | ); |
| 37 | 37 | ||
| 38 | /******************************************************************** | ||
| 39 | WnduShowOpenFileDialog - shows the system dialog to select a file for opening. | ||
| 40 | |||
| 41 | *******************************************************************/ | ||
| 42 | HRESULT DAPI WnduShowOpenFileDialog( | ||
| 43 | __in_opt HWND hwndParent, | ||
| 44 | __in BOOL fForcePathExists, | ||
| 45 | __in BOOL fForceFileExists, | ||
| 46 | __in_opt LPCWSTR wzTitle, | ||
| 47 | __in_opt COMDLG_FILTERSPEC* rgFilters, | ||
| 48 | __in DWORD cFilters, | ||
| 49 | __in DWORD dwDefaultFilter, | ||
| 50 | __in_opt LPCWSTR wzDefaultPath, | ||
| 51 | __inout LPWSTR* psczPath | ||
| 52 | ); | ||
| 53 | |||
| 54 | /******************************************************************** | ||
| 55 | WnduShowOpenFolderDialog - shows the system dialog to select a folder. | ||
| 56 | |||
| 57 | *******************************************************************/ | ||
| 58 | HRESULT DAPI WnduShowOpenFolderDialog( | ||
| 59 | __in_opt HWND hwndParent, | ||
| 60 | __in BOOL fForceFileSystem, | ||
| 61 | __in_opt LPCWSTR wzTitle, | ||
| 62 | __inout LPWSTR* psczPath | ||
| 63 | ); | ||
| 64 | |||
| 38 | #ifdef __cplusplus | 65 | #ifdef __cplusplus |
| 39 | } | 66 | } |
| 40 | #endif | 67 | #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( | |||
| 4992 | ) | 4992 | ) |
| 4993 | { | 4993 | { |
| 4994 | HRESULT hr = S_OK; | 4994 | HRESULT hr = S_OK; |
| 4995 | WCHAR wzPath[MAX_PATH] = { }; | 4995 | LPWSTR sczPath = NULL; |
| 4996 | BROWSEINFOW browseInfo = { }; | 4996 | THEME_CONTROL* pTargetControl = NULL; |
| 4997 | PIDLIST_ABSOLUTE pidl = NULL; | 4997 | BOOL fSetVariable = NULL != pTheme->pfnSetStringVariable; |
| 4998 | 4998 | ||
| 4999 | browseInfo.hwndOwner = pTheme->hwndParent; | 4999 | hr = WnduShowOpenFolderDialog(pTheme->hwndParent, TRUE, pTheme->sczCaption, &sczPath); |
| 5000 | browseInfo.pszDisplayName = wzPath; | 5000 | if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr) |
| 5001 | browseInfo.lpszTitle = pTheme->sczCaption; | ||
| 5002 | browseInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI; | ||
| 5003 | pidl = ::SHBrowseForFolderW(&browseInfo); | ||
| 5004 | if (pidl && ::SHGetPathFromIDListW(pidl, wzPath)) | ||
| 5005 | { | 5001 | { |
| 5006 | // Since editbox changes aren't immediately saved off, we have to treat them differently. | 5002 | ExitFunction(); |
| 5007 | THEME_CONTROL* pTargetControl = NULL; | 5003 | } |
| 5008 | BOOL fSetVariable = NULL != pTheme->pfnSetStringVariable; | 5004 | ThmExitOnFailure(hr, "Failed to prompt user for directory."); |
| 5009 | |||
| 5010 | for (DWORD i = 0; i < pTheme->cControls; ++i) | ||
| 5011 | { | ||
| 5012 | THEME_CONTROL* pControl = pTheme->rgControls + i; | ||
| 5013 | |||
| 5014 | if ((!pControl->wPageId || pControl->wPageId == pTheme->dwCurrentPageId) && | ||
| 5015 | CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pControl->sczName, -1, pAction->BrowseDirectory.sczVariableName, -1)) | ||
| 5016 | { | ||
| 5017 | pTargetControl = pControl; | ||
| 5018 | break; | ||
| 5019 | } | ||
| 5020 | } | ||
| 5021 | 5005 | ||
| 5022 | if (pTargetControl && !pTargetControl->fDisableAutomaticFunctionality && (!fSetVariable || THEME_CONTROL_TYPE_EDITBOX == pTargetControl->type)) | 5006 | for (DWORD i = 0; i < pTheme->cControls; ++i) |
| 5023 | { | 5007 | { |
| 5024 | fSetVariable = FALSE; | 5008 | THEME_CONTROL* pControl = pTheme->rgControls + i; |
| 5025 | hr = ThemeSetTextControl(pTargetControl, wzPath); | ||
| 5026 | ThmExitOnFailure(hr, "Failed to set text on control: %ls", pTargetControl->sczName); | ||
| 5027 | } | ||
| 5028 | 5009 | ||
| 5029 | if (fSetVariable) | 5010 | if ((!pControl->wPageId || pControl->wPageId == pTheme->dwCurrentPageId) && |
| 5011 | CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pControl->sczName, -1, pAction->BrowseDirectory.sczVariableName, -1)) | ||
| 5030 | { | 5012 | { |
| 5031 | hr = pTheme->pfnSetStringVariable(pAction->BrowseDirectory.sczVariableName, wzPath, FALSE, pTheme->pvVariableContext); | 5013 | pTargetControl = pControl; |
| 5032 | ThmExitOnFailure(hr, "Failed to set variable: %ls", pAction->BrowseDirectory.sczVariableName); | 5014 | break; |
| 5033 | } | 5015 | } |
| 5016 | } | ||
| 5034 | 5017 | ||
| 5035 | ThemeShowPageEx(pTheme, pTheme->dwCurrentPageId, SW_SHOW, THEME_SHOW_PAGE_REASON_REFRESH); | 5018 | // Since editbox changes aren't immediately saved off, we have to treat them differently. |
| 5019 | if (pTargetControl && !pTargetControl->fDisableAutomaticFunctionality && (!fSetVariable || THEME_CONTROL_TYPE_EDITBOX == pTargetControl->type)) | ||
| 5020 | { | ||
| 5021 | fSetVariable = FALSE; | ||
| 5022 | hr = ThemeSetTextControl(pTargetControl, sczPath); | ||
| 5023 | ThmExitOnFailure(hr, "Failed to set text on control: %ls", pTargetControl->sczName); | ||
| 5036 | } | 5024 | } |
| 5037 | 5025 | ||
| 5038 | LExit: | 5026 | if (fSetVariable) |
| 5039 | if (pidl) | ||
| 5040 | { | 5027 | { |
| 5041 | ::CoTaskMemFree(pidl); | 5028 | hr = pTheme->pfnSetStringVariable(pAction->BrowseDirectory.sczVariableName, sczPath, FALSE, pTheme->pvVariableContext); |
| 5029 | ThmExitOnFailure(hr, "Failed to set variable: %ls", pAction->BrowseDirectory.sczVariableName); | ||
| 5042 | } | 5030 | } |
| 5031 | |||
| 5032 | ThemeShowPageEx(pTheme, pTheme->dwCurrentPageId, SW_SHOW, THEME_SHOW_PAGE_REASON_REFRESH); | ||
| 5033 | |||
| 5034 | LExit: | ||
| 5035 | ReleaseStr(sczPath); | ||
| 5043 | } | 5036 | } |
| 5044 | 5037 | ||
| 5045 | static BOOL OnButtonClicked( | 5038 | 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: | |||
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | 163 | ||
| 164 | DAPI_(HRESULT) WnduShowOpenFileDialog( | ||
| 165 | __in_opt HWND hwndParent, | ||
| 166 | __in BOOL fForcePathExists, | ||
| 167 | __in BOOL fForceFileExists, | ||
| 168 | __in_opt LPCWSTR wzTitle, | ||
| 169 | __in COMDLG_FILTERSPEC* rgFilters, | ||
| 170 | __in DWORD cFilters, | ||
| 171 | __in DWORD dwDefaultFilter, | ||
| 172 | __in_opt LPCWSTR wzDefaultPath, | ||
| 173 | __inout LPWSTR* psczPath | ||
| 174 | ) | ||
| 175 | { | ||
| 176 | HRESULT hr = S_OK; | ||
| 177 | IFileOpenDialog* pFileOpenDialog = NULL; | ||
| 178 | FILEOPENDIALOGOPTIONS fos = 0; | ||
| 179 | FILEOPENDIALOGOPTIONS additionalFlags = FOS_NOCHANGEDIR; | ||
| 180 | IShellItem* psi = NULL; | ||
| 181 | LPWSTR sczDefaultDirectory = NULL; | ||
| 182 | LPWSTR sczPath = NULL; | ||
| 183 | |||
| 184 | hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpenDialog)); | ||
| 185 | WnduExitOnFailure(hr, "Failed to create FileOpenDialog object."); | ||
| 186 | |||
| 187 | hr = pFileOpenDialog->SetTitle(wzTitle); | ||
| 188 | WnduExitOnFailure(hr, "Failed to set FileOpenDialog title."); | ||
| 189 | |||
| 190 | hr = pFileOpenDialog->GetOptions(&fos); | ||
| 191 | WnduExitOnFailure(hr, "Failed to get FileOpenDialog options."); | ||
| 192 | |||
| 193 | if (fForcePathExists) | ||
| 194 | { | ||
| 195 | additionalFlags |= FOS_PATHMUSTEXIST; | ||
| 196 | } | ||
| 197 | |||
| 198 | if (fForceFileExists) | ||
| 199 | { | ||
| 200 | additionalFlags |= FOS_FILEMUSTEXIST; | ||
| 201 | } | ||
| 202 | |||
| 203 | hr = pFileOpenDialog->SetOptions(fos | additionalFlags); | ||
| 204 | WnduExitOnFailure(hr, "Failed to set FileOpenDialog options."); | ||
| 205 | |||
| 206 | hr = pFileOpenDialog->SetFileTypes(cFilters, rgFilters); | ||
| 207 | WnduExitOnFailure(hr, "Failed to set FileOpenDialog file types."); | ||
| 208 | |||
| 209 | hr = pFileOpenDialog->SetFileTypeIndex(dwDefaultFilter); | ||
| 210 | WnduExitOnFailure(hr, "Failed to set FileOpenDialog default file type."); | ||
| 211 | |||
| 212 | if (wzDefaultPath && *wzDefaultPath) | ||
| 213 | { | ||
| 214 | hr = PathGetDirectory(wzDefaultPath, &sczDefaultDirectory); | ||
| 215 | if (SUCCEEDED(hr)) | ||
| 216 | { | ||
| 217 | hr = ::SHCreateItemFromParsingName(sczDefaultDirectory, NULL, IID_PPV_ARGS(&psi)); | ||
| 218 | if (SUCCEEDED(hr)) | ||
| 219 | { | ||
| 220 | hr = pFileOpenDialog->SetFolder(psi); | ||
| 221 | WnduExitOnFailure(hr, "Failed to set FileOpenDialog folder."); | ||
| 222 | } | ||
| 223 | |||
| 224 | ReleaseNullObject(psi); | ||
| 225 | } | ||
| 226 | |||
| 227 | hr = pFileOpenDialog->SetFileName(wzDefaultPath); | ||
| 228 | WnduExitOnFailure(hr, "Failed to set FileOpenDialog file name."); | ||
| 229 | } | ||
| 230 | |||
| 231 | hr = pFileOpenDialog->Show(hwndParent); | ||
| 232 | if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr) | ||
| 233 | { | ||
| 234 | ExitFunction(); | ||
| 235 | } | ||
| 236 | WnduExitOnFailure(hr, "Failed to show FileOpenDialog for file."); | ||
| 237 | |||
| 238 | hr = pFileOpenDialog->GetResult(&psi); | ||
| 239 | WnduExitOnFailure(hr, "Failed to get FileOpenDialog result."); | ||
| 240 | |||
| 241 | hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &sczPath); | ||
| 242 | WnduExitOnFailure(hr, "Failed to get FileOpenDialog result path."); | ||
| 243 | |||
| 244 | hr = StrAllocString(psczPath, sczPath, 0); | ||
| 245 | WnduExitOnFailure(hr, "Failed to copy FileOpenDialog result path."); | ||
| 246 | |||
| 247 | LExit: | ||
| 248 | if (sczPath) | ||
| 249 | { | ||
| 250 | ::CoTaskMemFree(sczPath); | ||
| 251 | } | ||
| 252 | |||
| 253 | ReleaseStr(sczDefaultDirectory); | ||
| 254 | ReleaseObject(psi); | ||
| 255 | ReleaseObject(pFileOpenDialog); | ||
| 256 | |||
| 257 | return hr; | ||
| 258 | } | ||
| 259 | |||
| 260 | |||
| 261 | DAPI_(HRESULT) WnduShowOpenFolderDialog( | ||
| 262 | __in_opt HWND hwndParent, | ||
| 263 | __in BOOL fForceFileSystem, | ||
| 264 | __in_opt LPCWSTR wzTitle, | ||
| 265 | __inout LPWSTR* psczPath | ||
| 266 | ) | ||
| 267 | { | ||
| 268 | HRESULT hr = S_OK; | ||
| 269 | IFileOpenDialog* pFileOpenDialog = NULL; | ||
| 270 | FILEOPENDIALOGOPTIONS fos = 0; | ||
| 271 | FILEOPENDIALOGOPTIONS additionalFlags = FOS_PICKFOLDERS | FOS_NOCHANGEDIR; | ||
| 272 | IShellItem* psi = NULL; | ||
| 273 | LPWSTR sczPath = NULL; | ||
| 274 | |||
| 275 | hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpenDialog)); | ||
| 276 | WnduExitOnFailure(hr, "Failed to create FileOpenDialog object."); | ||
| 277 | |||
| 278 | hr = pFileOpenDialog->SetTitle(wzTitle); | ||
| 279 | WnduExitOnFailure(hr, "Failed to set FileOpenDialog title."); | ||
| 280 | |||
| 281 | hr = pFileOpenDialog->GetOptions(&fos); | ||
| 282 | WnduExitOnFailure(hr, "Failed to get FileOpenDialog options."); | ||
| 283 | |||
| 284 | if (fForceFileSystem) | ||
| 285 | { | ||
| 286 | additionalFlags |= FOS_FORCEFILESYSTEM; | ||
| 287 | } | ||
| 288 | |||
| 289 | hr = pFileOpenDialog->SetOptions(fos | additionalFlags); | ||
| 290 | WnduExitOnFailure(hr, "Failed to set FileOpenDialog options."); | ||
| 291 | |||
| 292 | hr = pFileOpenDialog->Show(hwndParent); | ||
| 293 | if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr) | ||
| 294 | { | ||
| 295 | ExitFunction(); | ||
| 296 | } | ||
| 297 | WnduExitOnFailure(hr, "Failed to show FileOpenDialog for folder."); | ||
| 298 | |||
| 299 | hr = pFileOpenDialog->GetResult(&psi); | ||
| 300 | WnduExitOnFailure(hr, "Failed to get FileOpenDialog result."); | ||
| 301 | |||
| 302 | hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &sczPath); | ||
| 303 | WnduExitOnFailure(hr, "Failed to get FileOpenDialog result path."); | ||
| 304 | |||
| 305 | hr = StrAllocString(psczPath, sczPath, 0); | ||
| 306 | WnduExitOnFailure(hr, "Failed to copy FileOpenDialog result path."); | ||
| 307 | |||
| 308 | LExit: | ||
| 309 | if (sczPath) | ||
| 310 | { | ||
| 311 | ::CoTaskMemFree(sczPath); | ||
| 312 | } | ||
| 313 | |||
| 314 | ReleaseObject(psi); | ||
| 315 | ReleaseObject(pFileOpenDialog); | ||
| 316 | |||
| 317 | return hr; | ||
| 318 | } | ||
| 319 | |||
| 320 | |||
| 164 | static DWORD CALLBACK RichEditStreamFromFileHandleCallback( | 321 | static DWORD CALLBACK RichEditStreamFromFileHandleCallback( |
| 165 | __in DWORD_PTR dwCookie, | 322 | __in DWORD_PTR dwCookie, |
| 166 | __in_bcount(cb) LPBYTE pbBuff, | 323 | __in_bcount(cb) LPBYTE pbBuff, |
