From 2c90a06668b5fc7252688578fe765649c956bac1 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 23 Mar 2016 16:56:49 +0000 Subject: [PATCH] use IFileDialog when running on Vista or later * When compiled with MinGW, this was always disabled due to forcing XP as the lowest common denominator and using #ifdefs * This should also help with OFN_NOCHANGEDIR seemingly being ignored * Sadly, this change also adds ~20KB to our *compressed* size... :( --- src/Makefile.am | 2 +- src/Makefile.in | 2 +- src/missing.h | 304 ++++++++++++++++++++++++++++++++++++++++++++++++ src/rufus.rc | 10 +- src/stdlg.c | 292 +++++++++++++++++++++++----------------------- 5 files changed, 454 insertions(+), 156 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index d2fe6359..da1937ce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,4 +15,4 @@ rufus_SOURCES = badblocks.c checksum.c dos.c dos_locale.c drive.c format.c icon. rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ - libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust + libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid diff --git a/src/Makefile.in b/src/Makefile.in index 137a8a86..401d576f 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -276,7 +276,7 @@ rufus_SOURCES = badblocks.c checksum.c dos.c dos_locale.c drive.c format.c icon. rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ - libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust + libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid all: all-recursive diff --git a/src/missing.h b/src/missing.h index 62a96ab8..3dada756 100644 --- a/src/missing.h +++ b/src/missing.h @@ -272,3 +272,307 @@ typedef unsigned __int64 uintptr_t; typedef unsigned int uintptr_t; #endif #endif + +/* + * IFile[Open]Dialog interface for Vista and later (from MinGW headers) + */ +#ifdef DDKBUILD +typedef struct _COMDLG_FILTERSPEC { + LPCWSTR pszName; + LPCWSTR pszSpec; +} COMDLG_FILTERSPEC; +#endif + +#ifndef __IFileDialog_INTERFACE_DEFINED__ +#define __IFileDialog_INTERFACE_DEFINED__ + +enum _FILEOPENDIALOGOPTIONS { + FOS_OVERWRITEPROMPT = 0x2, + FOS_STRICTFILETYPES = 0x4, + FOS_NOCHANGEDIR = 0x8, + FOS_PICKFOLDERS = 0x20, + FOS_FORCEFILESYSTEM = 0x40, + FOS_ALLNONSTORAGEITEMS = 0x80, + FOS_NOVALIDATE = 0x100, + FOS_ALLOWMULTISELECT = 0x200, + FOS_PATHMUSTEXIST = 0x800, + FOS_FILEMUSTEXIST = 0x1000, + FOS_CREATEPROMPT = 0x2000, + FOS_SHAREAWARE = 0x4000, + FOS_NOREADONLYRETURN = 0x8000, + FOS_NOTESTFILECREATE = 0x10000, + FOS_HIDEMRUPLACES = 0x20000, + FOS_HIDEPINNEDPLACES = 0x40000, + FOS_NODEREFERENCELINKS = 0x100000, + FOS_DONTADDTORECENT = 0x2000000, + FOS_FORCESHOWHIDDEN = 0x10000000, + FOS_DEFAULTNOMINIMODE = 0x20000000, + FOS_FORCEPREVIEWPANEON = 0x40000000 +}; + +typedef enum FDAP { + FDAP_BOTTOM = 0, + FDAP_TOP = 1 +} FDAP; + +typedef DWORD FILEOPENDIALOGOPTIONS; + +DEFINE_GUID(IID_IFileDialog, 0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07, 0x5d, 0x13, 0x5f, 0xc8); + +typedef struct IFileDialogVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT(STDMETHODCALLTYPE *QueryInterface)( + IFileDialog* This, + REFIID riid, + void **ppvObject); + + ULONG(STDMETHODCALLTYPE *AddRef)( + IFileDialog* This); + + ULONG(STDMETHODCALLTYPE *Release)( + IFileDialog* This); + + /*** IModalWindow methods ***/ + HRESULT(STDMETHODCALLTYPE *Show)( + IFileDialog* This, + HWND hwndOwner); + + /*** IFileDialog methods ***/ + HRESULT(STDMETHODCALLTYPE *SetFileTypes)( + IFileDialog* This, + UINT cFileTypes, + const COMDLG_FILTERSPEC *rgFilterSpec); + + HRESULT(STDMETHODCALLTYPE *SetFileTypeIndex)( + IFileDialog* This, + UINT iFileType); + + HRESULT(STDMETHODCALLTYPE *GetFileTypeIndex)( + IFileDialog* This, + UINT *piFileType); + + HRESULT(STDMETHODCALLTYPE *Advise)( + IFileDialog* This, + IFileDialogEvents *pfde, + DWORD *pdwCookie); + + HRESULT(STDMETHODCALLTYPE *Unadvise)( + IFileDialog* This, + DWORD dwCookie); + + HRESULT(STDMETHODCALLTYPE *SetOptions)( + IFileDialog* This, + FILEOPENDIALOGOPTIONS fos); + + HRESULT(STDMETHODCALLTYPE *GetOptions)( + IFileDialog* This, + FILEOPENDIALOGOPTIONS *pfos); + + HRESULT(STDMETHODCALLTYPE *SetDefaultFolder)( + IFileDialog* This, + IShellItem *psi); + + HRESULT(STDMETHODCALLTYPE *SetFolder)( + IFileDialog* This, + IShellItem *psi); + + HRESULT(STDMETHODCALLTYPE *GetFolder)( + IFileDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *GetCurrentSelection)( + IFileDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *SetFileName)( + IFileDialog* This, + LPCWSTR pszName); + + HRESULT(STDMETHODCALLTYPE *GetFileName)( + IFileDialog* This, + LPWSTR *pszName); + + HRESULT(STDMETHODCALLTYPE *SetTitle)( + IFileDialog* This, + LPCWSTR pszTitle); + + HRESULT(STDMETHODCALLTYPE *SetOkButtonLabel)( + IFileDialog* This, + LPCWSTR pszText); + + HRESULT(STDMETHODCALLTYPE *SetFileNameLabel)( + IFileDialog* This, + LPCWSTR pszLabel); + + HRESULT(STDMETHODCALLTYPE *GetResult)( + IFileDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *AddPlace)( + IFileDialog* This, + IShellItem *psi, + FDAP fdap); + + HRESULT(STDMETHODCALLTYPE *SetDefaultExtension)( + IFileDialog* This, + LPCWSTR pszDefaultExtension); + + HRESULT(STDMETHODCALLTYPE *Close)( + IFileDialog* This, + HRESULT hr); + + HRESULT(STDMETHODCALLTYPE *SetClientGuid)( + IFileDialog* This, + REFGUID guid); + + HRESULT(STDMETHODCALLTYPE *ClearClientData)( + IFileDialog* This); + + HRESULT(STDMETHODCALLTYPE *SetFilter)( + IFileDialog* This, + IShellItemFilter *pFilter); + + END_INTERFACE +} IFileDialogVtbl; +interface IFileDialog { + CONST_VTBL IFileDialogVtbl* lpVtbl; +}; +#endif + +#ifndef __IFileOpenDialog_INTERFACE_DEFINED__ +#define __IFileOpenDialog_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IFileOpenDialog, 0xd57c7288, 0xd4ad, 0x4768, 0xbe, 0x02, 0x9d, 0x96, 0x95, 0x32, 0xd9, 0x60); + +typedef struct IFileOpenDialogVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT(STDMETHODCALLTYPE *QueryInterface)( + IFileOpenDialog* This, + REFIID riid, + void **ppvObject); + + ULONG(STDMETHODCALLTYPE *AddRef)( + IFileOpenDialog* This); + + ULONG(STDMETHODCALLTYPE *Release)( + IFileOpenDialog* This); + + /*** IModalWindow methods ***/ + HRESULT(STDMETHODCALLTYPE *Show)( + IFileOpenDialog* This, + HWND hwndOwner); + + /*** IFileDialog methods ***/ + HRESULT(STDMETHODCALLTYPE *SetFileTypes)( + IFileOpenDialog* This, + UINT cFileTypes, + const COMDLG_FILTERSPEC *rgFilterSpec); + + HRESULT(STDMETHODCALLTYPE *SetFileTypeIndex)( + IFileOpenDialog* This, + UINT iFileType); + + HRESULT(STDMETHODCALLTYPE *GetFileTypeIndex)( + IFileOpenDialog* This, + UINT *piFileType); + + HRESULT(STDMETHODCALLTYPE *Advise)( + IFileOpenDialog* This, + IFileDialogEvents *pfde, + DWORD *pdwCookie); + + HRESULT(STDMETHODCALLTYPE *Unadvise)( + IFileOpenDialog* This, + DWORD dwCookie); + + HRESULT(STDMETHODCALLTYPE *SetOptions)( + IFileOpenDialog* This, + FILEOPENDIALOGOPTIONS fos); + + HRESULT(STDMETHODCALLTYPE *GetOptions)( + IFileOpenDialog* This, + FILEOPENDIALOGOPTIONS *pfos); + + HRESULT(STDMETHODCALLTYPE *SetDefaultFolder)( + IFileOpenDialog* This, + IShellItem *psi); + + HRESULT(STDMETHODCALLTYPE *SetFolder)( + IFileOpenDialog* This, + IShellItem *psi); + + HRESULT(STDMETHODCALLTYPE *GetFolder)( + IFileOpenDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *GetCurrentSelection)( + IFileOpenDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *SetFileName)( + IFileOpenDialog* This, + LPCWSTR pszName); + + HRESULT(STDMETHODCALLTYPE *GetFileName)( + IFileOpenDialog* This, + LPWSTR *pszName); + + HRESULT(STDMETHODCALLTYPE *SetTitle)( + IFileOpenDialog* This, + LPCWSTR pszTitle); + + HRESULT(STDMETHODCALLTYPE *SetOkButtonLabel)( + IFileOpenDialog* This, + LPCWSTR pszText); + + HRESULT(STDMETHODCALLTYPE *SetFileNameLabel)( + IFileOpenDialog* This, + LPCWSTR pszLabel); + + HRESULT(STDMETHODCALLTYPE *GetResult)( + IFileOpenDialog* This, + IShellItem **ppsi); + + HRESULT(STDMETHODCALLTYPE *AddPlace)( + IFileOpenDialog* This, + IShellItem *psi, + FDAP fdap); + + HRESULT(STDMETHODCALLTYPE *SetDefaultExtension)( + IFileOpenDialog* This, + LPCWSTR pszDefaultExtension); + + HRESULT(STDMETHODCALLTYPE *Close)( + IFileOpenDialog* This, + HRESULT hr); + + HRESULT(STDMETHODCALLTYPE *SetClientGuid)( + IFileOpenDialog* This, + REFGUID guid); + + HRESULT(STDMETHODCALLTYPE *ClearClientData)( + IFileOpenDialog* This); + + HRESULT(STDMETHODCALLTYPE *SetFilter)( + IFileOpenDialog* This, + IShellItemFilter *pFilter); + + /*** IFileOpenDialog methods ***/ + HRESULT(STDMETHODCALLTYPE *GetResults)( + IFileOpenDialog* This, + IShellItemArray **ppenum); + + HRESULT(STDMETHODCALLTYPE *GetSelectedItems)( + IFileOpenDialog* This, + IShellItemArray **ppsai); + + END_INTERFACE +} IFileOpenDialogVtbl; +interface IFileOpenDialog { + CONST_VTBL IFileOpenDialogVtbl* lpVtbl; +}; +#endif diff --git a/src/rufus.rc b/src/rufus.rc index 8b8c33d5..f710d079 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.8.886" +CAPTION "Rufus 2.8.887" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -320,8 +320,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,8,886,0 - PRODUCTVERSION 2,8,886,0 + FILEVERSION 2,8,887,0 + PRODUCTVERSION 2,8,887,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -338,13 +338,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.8.886" + VALUE "FileVersion", "2.8.887" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2016 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.8.886" + VALUE "ProductVersion", "2.8.887" END END BLOCK "VarFileInfo" diff --git a/src/stdlg.c b/src/stdlg.c index e530c7dc..69098919 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -44,9 +44,7 @@ #include "settings.h" #include "license.h" -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) PF_TYPE_DECL(WINAPI, HRESULT, SHCreateItemFromParsingName, (PCWSTR, IBindCtx*, REFIID, void **)); -#endif PF_TYPE_DECL(WINAPI, LPITEMIDLIST, SHSimpleIDListFromPath, (PCWSTR pszPath)); #define INIT_VISTA_SHELL32 PF_INIT(SHCreateItemFromParsingName, Shell32) #define INIT_XP_SHELL32 PF_INIT(SHSimpleIDListFromPath, Shell32) @@ -135,8 +133,6 @@ void BrowseForFolder(void) { BROWSEINFOW bi; LPITEMIDLIST pidl; - -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) WCHAR *wpath; size_t i; HRESULT hr; @@ -147,79 +143,79 @@ void BrowseForFolder(void) { char* tmp_path = NULL; dialog_showing++; - // Even if we have Vista support with the compiler, - // it does not mean we have the Vista API available - INIT_VISTA_SHELL32; - if (IS_VISTA_SHELL32_AVAILABLE) { - hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC, - &IID_IFileOpenDialog, (LPVOID)&pfod); - if (FAILED(hr)) { - uprintf("CoCreateInstance for FileOpenDialog failed: error %X\n", hr); - pfod = NULL; // Just in case - goto fallback; - } - hr = pfod->lpVtbl->SetOptions(pfod, FOS_PICKFOLDERS); - if (FAILED(hr)) { - uprintf("Failed to set folder option for FileOpenDialog: error %X\n", hr); - goto fallback; - } - // Set the initial folder (if the path is invalid, will simply use last) - wpath = utf8_to_wchar(szFolderPath); - // The new IFileOpenDialog makes us split the path - fname = NULL; - if ((wpath != NULL) && (wcslen(wpath) >= 1)) { - for (i=wcslen(wpath)-1; i!=0; i--) { - if (wpath[i] == L'\\') { - wpath[i] = 0; - fname = &wpath[i+1]; - break; - } +#ifndef DDKBUILD // WDK being uncooperative yet again... + if (nWindowsVersion >= WINDOWS_VISTA) { + INIT_VISTA_SHELL32; + if (IS_VISTA_SHELL32_AVAILABLE) { + hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC, + &IID_IFileOpenDialog, (LPVOID)&pfod); + if (FAILED(hr)) { + uprintf("CoCreateInstance for FileOpenDialog failed: error %X\n", hr); + pfod = NULL; // Just in case + goto fallback; } - } - - hr = (*pfSHCreateItemFromParsingName)(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path); - if (SUCCEEDED(hr)) { - if (wpath != NULL) { - hr = pfod->lpVtbl->SetFolder(pfod, si_path); - } - if (fname != NULL) { - hr = pfod->lpVtbl->SetFileName(pfod, fname); - } - } - safe_free(wpath); - - hr = pfod->lpVtbl->Show(pfod, hMainDialog); - if (SUCCEEDED(hr)) { - hr = pfod->lpVtbl->GetResult(pfod, &psi); - if (SUCCEEDED(hr)) { - psi->lpVtbl->GetDisplayName(psi, SIGDN_FILESYSPATH, &wpath); - tmp_path = wchar_to_utf8(wpath); - CoTaskMemFree(wpath); - if (tmp_path == NULL) { - uprintf("Could not convert path\n"); - } else { - safe_strcpy(szFolderPath, MAX_PATH, tmp_path); - safe_free(tmp_path); - } - } else { + hr = pfod->lpVtbl->SetOptions(pfod, FOS_PICKFOLDERS); + if (FAILED(hr)) { uprintf("Failed to set folder option for FileOpenDialog: error %X\n", hr); + goto fallback; } - } else if ((hr & 0xFFFF) != ERROR_CANCELLED) { - // If it's not a user cancel, assume the dialog didn't show and fallback - uprintf("Could not show FileOpenDialog: error %X\n", hr); - goto fallback; + // Set the initial folder (if the path is invalid, will simply use last) + wpath = utf8_to_wchar(szFolderPath); + // The new IFileOpenDialog makes us split the path + fname = NULL; + if ((wpath != NULL) && (wcslen(wpath) >= 1)) { + for (i = wcslen(wpath) - 1; i != 0; i--) { + if (wpath[i] == L'\\') { + wpath[i] = 0; + fname = &wpath[i + 1]; + break; + } + } + } + + hr = (*pfSHCreateItemFromParsingName)(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path); + if (SUCCEEDED(hr)) { + if (wpath != NULL) { + hr = pfod->lpVtbl->SetFolder(pfod, si_path); + } + if (fname != NULL) { + hr = pfod->lpVtbl->SetFileName(pfod, fname); + } + } + safe_free(wpath); + + hr = pfod->lpVtbl->Show(pfod, hMainDialog); + if (SUCCEEDED(hr)) { + hr = pfod->lpVtbl->GetResult(pfod, &psi); + if (SUCCEEDED(hr)) { + psi->lpVtbl->GetDisplayName(psi, SIGDN_FILESYSPATH, &wpath); + tmp_path = wchar_to_utf8(wpath); + CoTaskMemFree(wpath); + if (tmp_path == NULL) { + uprintf("Could not convert path\n"); + } else { + safe_strcpy(szFolderPath, MAX_PATH, tmp_path); + safe_free(tmp_path); + } + } else { + uprintf("Failed to set folder option for FileOpenDialog: error %X\n", hr); + } + } else if ((hr & 0xFFFF) != ERROR_CANCELLED) { + // If it's not a user cancel, assume the dialog didn't show and fallback + uprintf("Could not show FileOpenDialog: error %X\n", hr); + goto fallback; + } + pfod->lpVtbl->Release(pfod); + dialog_showing--; + return; } - pfod->lpVtbl->Release(pfod); - dialog_showing--; - return; - } fallback: - if (pfod != NULL) { - pfod->lpVtbl->Release(pfod); + if (pfod != NULL) { + pfod->lpVtbl->Release(pfod); + } } -#else - dialog_showing++; #endif + INIT_XP_SHELL32; memset(&bi, 0, sizeof(BROWSEINFOW)); bi.hwndOwner = hMainDialog; @@ -253,99 +249,97 @@ char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options) size_t i, j, ext_strlen; BOOL r; char* filepath = NULL; - -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) HRESULT hr = FALSE; IFileDialog *pfd = NULL; IShellItem *psiResult; COMDLG_FILTERSPEC* filter_spec; wchar_t *wpath = NULL, *wfilename = NULL; IShellItem *si_path = NULL; // Automatically freed -#endif if ((ext == NULL) || (ext->count == 0) || (ext->extension == NULL) || (ext->description == NULL)) return NULL; dialog_showing++; -#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) - INIT_VISTA_SHELL32; - filter_spec = (COMDLG_FILTERSPEC*)calloc(ext->count + 1, sizeof(COMDLG_FILTERSPEC)); - if ((IS_VISTA_SHELL32_AVAILABLE) && (filter_spec != NULL)) { - // Setup the file extension filter table - for (i=0; icount; i++) { - filter_spec[i].pszSpec = utf8_to_wchar(ext->extension[i]); - filter_spec[i].pszName = utf8_to_wchar(ext->description[i]); - } - filter_spec[i].pszSpec = L"*.*"; - filter_spec[i].pszName = utf8_to_wchar(lmprintf(MSG_107)); - - hr = CoCreateInstance(save?&CLSID_FileSaveDialog:&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC, - &IID_IFileDialog, (LPVOID)&pfd); - - if (FAILED(hr)) { - SetLastError(hr); - uprintf("CoCreateInstance for FileOpenDialog failed: %s\n", WindowsErrorString()); - pfd = NULL; // Just in case - goto fallback; - } - - // Set the file extension filters - pfd->lpVtbl->SetFileTypes(pfd, (UINT)ext->count+1, filter_spec); - - // Set the default directory - wpath = utf8_to_wchar(path); - hr = (*pfSHCreateItemFromParsingName)(wpath, NULL, &IID_IShellItem, (LPVOID) &si_path); - if (SUCCEEDED(hr)) { - pfd->lpVtbl->SetFolder(pfd, si_path); - } - safe_free(wpath); - - // Set the default filename - wfilename = utf8_to_wchar((ext->filename == NULL)?"":ext->filename); - if (wfilename != NULL) { - pfd->lpVtbl->SetFileName(pfd, wfilename); - } - - // Display the dialog - hr = pfd->lpVtbl->Show(pfd, hMainDialog); - - // Cleanup - safe_free(wfilename); - for (i=0; icount; i++) { - safe_free(filter_spec[i].pszSpec); - safe_free(filter_spec[i].pszName); - } - safe_free(filter_spec[i].pszName); - safe_free(filter_spec); - - if (SUCCEEDED(hr)) { - // Obtain the result of the user's interaction with the dialog. - hr = pfd->lpVtbl->GetResult(pfd, &psiResult); - if (SUCCEEDED(hr)) { - hr = psiResult->lpVtbl->GetDisplayName(psiResult, SIGDN_FILESYSPATH, &wpath); - if (SUCCEEDED(hr)) { - filepath = wchar_to_utf8(wpath); - CoTaskMemFree(wpath); - } else { - SetLastError(hr); - uprintf("Unable to access file path: %s\n", WindowsErrorString()); - } - psiResult->lpVtbl->Release(psiResult); +#ifndef DDKBUILD + if (nWindowsVersion >= WINDOWS_VISTA) { + INIT_VISTA_SHELL32; + filter_spec = (COMDLG_FILTERSPEC*)calloc(ext->count + 1, sizeof(COMDLG_FILTERSPEC)); + if ((IS_VISTA_SHELL32_AVAILABLE) && (filter_spec != NULL)) { + // Setup the file extension filter table + for (i = 0; i < ext->count; i++) { + filter_spec[i].pszSpec = utf8_to_wchar(ext->extension[i]); + filter_spec[i].pszName = utf8_to_wchar(ext->description[i]); } - } else if ((hr & 0xFFFF) != ERROR_CANCELLED) { - // If it's not a user cancel, assume the dialog didn't show and fallback - SetLastError(hr); - uprintf("Could not show FileOpenDialog: %s\n", WindowsErrorString()); - goto fallback; - } - pfd->lpVtbl->Release(pfd); - dialog_showing--; - return filepath; - } + filter_spec[i].pszSpec = L"*.*"; + filter_spec[i].pszName = utf8_to_wchar(lmprintf(MSG_107)); + hr = CoCreateInstance(save ? &CLSID_FileSaveDialog : &CLSID_FileOpenDialog, NULL, CLSCTX_INPROC, + &IID_IFileDialog, (LPVOID)&pfd); + + if (FAILED(hr)) { + SetLastError(hr); + uprintf("CoCreateInstance for FileOpenDialog failed: %s\n", WindowsErrorString()); + pfd = NULL; // Just in case + goto fallback; + } + + // Set the file extension filters + pfd->lpVtbl->SetFileTypes(pfd, (UINT)ext->count + 1, filter_spec); + + // Set the default directory + wpath = utf8_to_wchar(path); + hr = (*pfSHCreateItemFromParsingName)(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path); + if (SUCCEEDED(hr)) { + pfd->lpVtbl->SetFolder(pfd, si_path); + } + safe_free(wpath); + + // Set the default filename + wfilename = utf8_to_wchar((ext->filename == NULL) ? "" : ext->filename); + if (wfilename != NULL) { + pfd->lpVtbl->SetFileName(pfd, wfilename); + } + + // Display the dialog + hr = pfd->lpVtbl->Show(pfd, hMainDialog); + + // Cleanup + safe_free(wfilename); + for (i = 0; i < ext->count; i++) { + safe_free(filter_spec[i].pszSpec); + safe_free(filter_spec[i].pszName); + } + safe_free(filter_spec[i].pszName); + safe_free(filter_spec); + + if (SUCCEEDED(hr)) { + // Obtain the result of the user's interaction with the dialog. + hr = pfd->lpVtbl->GetResult(pfd, &psiResult); + if (SUCCEEDED(hr)) { + hr = psiResult->lpVtbl->GetDisplayName(psiResult, SIGDN_FILESYSPATH, &wpath); + if (SUCCEEDED(hr)) { + filepath = wchar_to_utf8(wpath); + CoTaskMemFree(wpath); + } else { + SetLastError(hr); + uprintf("Unable to access file path: %s\n", WindowsErrorString()); + } + psiResult->lpVtbl->Release(psiResult); + } + } else if ((hr & 0xFFFF) != ERROR_CANCELLED) { + // If it's not a user cancel, assume the dialog didn't show and fallback + SetLastError(hr); + uprintf("Could not show FileOpenDialog: %s\n", WindowsErrorString()); + goto fallback; + } + pfd->lpVtbl->Release(pfd); + dialog_showing--; + return filepath; + } fallback: - if (pfd != NULL) { - pfd->lpVtbl->Release(pfd); + if (pfd != NULL) { + pfd->lpVtbl->Release(pfd); + } } #endif