浏览代码

dialog: Fix compilation with pre-Vista headers.

Closes #13823
William Horvath 2 周之前
父节点
当前提交
d15e531bad
共有 1 个文件被更改,包括 186 次插入4 次删除
  1. 186 4
      src/dialog/windows/SDL_windowsdialog.c

+ 186 - 4
src/dialog/windows/SDL_windowsdialog.c

@@ -29,6 +29,172 @@
 #include "../../core/windows/SDL_windows.h"
 #include "../../thread/SDL_systhread.h"
 
+// Flags/GUIDs defined for compatibility with pre-Vista headers
+#ifndef __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,
+    FOS_SUPPORTSTREAMABLEITEMS = 0x80000000
+};
+
+typedef DWORD FILEOPENDIALOGOPTIONS;
+
+typedef enum FDAP {
+    FDAP_BOTTOM = 0,
+    FDAP_TOP = 1
+} FDAP;
+
+/* *INDENT-OFF* */ // clang-format off
+typedef struct IFileDialogVtbl
+{
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(IFileDialog *, REFIID, void **);
+    ULONG (STDMETHODCALLTYPE *AddRef)(IFileDialog *);
+    ULONG (STDMETHODCALLTYPE *Release)(IFileDialog *);
+    HRESULT (STDMETHODCALLTYPE *Show)(IFileDialog *, HWND);
+    HRESULT (STDMETHODCALLTYPE *SetFileTypes)(IFileDialog *, UINT, const COMDLG_FILTERSPEC *);
+    HRESULT (STDMETHODCALLTYPE *SetFileTypeIndex)(IFileDialog *, UINT);
+    HRESULT (STDMETHODCALLTYPE *GetFileTypeIndex)(IFileDialog *, UINT *);
+    HRESULT (STDMETHODCALLTYPE *Advise)(IFileDialog *, IFileDialogEvents *, DWORD *);
+    HRESULT (STDMETHODCALLTYPE *Unadvise)(IFileDialog *, DWORD);
+    HRESULT (STDMETHODCALLTYPE *SetOptions)(IFileDialog *, FILEOPENDIALOGOPTIONS);
+    HRESULT (STDMETHODCALLTYPE *GetOptions)(IFileDialog *, FILEOPENDIALOGOPTIONS *);
+    HRESULT (STDMETHODCALLTYPE *SetDefaultFolder)(IFileDialog *, IShellItem *);
+    HRESULT (STDMETHODCALLTYPE *SetFolder)(IFileDialog *, IShellItem *);
+    HRESULT (STDMETHODCALLTYPE *GetFolder)(IFileDialog *, IShellItem **);
+    HRESULT (STDMETHODCALLTYPE *GetCurrentSelection)(IFileDialog *, IShellItem **);
+    HRESULT (STDMETHODCALLTYPE *SetFileName)(IFileDialog *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *GetFileName)(IFileDialog *, LPWSTR *);
+    HRESULT (STDMETHODCALLTYPE *SetTitle)(IFileDialog *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *SetOkButtonLabel)(IFileDialog *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *SetFileNameLabel)(IFileDialog *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *GetResult)(IFileDialog *, IShellItem **);
+    HRESULT (STDMETHODCALLTYPE *AddPlace)(IFileDialog *, IShellItem *, FDAP);
+    HRESULT (STDMETHODCALLTYPE *SetDefaultExtension)(IFileDialog *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *Close)(IFileDialog *, HRESULT);
+    HRESULT (STDMETHODCALLTYPE *SetClientGuid)(IFileDialog *, REFGUID);
+    HRESULT (STDMETHODCALLTYPE *ClearClientData)(IFileDialog *);
+    HRESULT (STDMETHODCALLTYPE *SetFilter)(IFileDialog *,IShellItemFilter *);
+} IFileDialogVtbl;
+/* *INDENT-ON* */ // clang-format on
+
+struct IFileDialog
+{
+    const struct IFileDialogVtbl *lpVtbl;
+};
+#endif
+
+#ifndef __IFileDialog2_INTERFACE_DEFINED__
+/* *INDENT-OFF* */ // clang-format off
+typedef struct IFileDialog2Vtbl
+{
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(IFileDialog2 *, REFIID, void **);
+    ULONG (STDMETHODCALLTYPE *AddRef)(IFileDialog2 *);
+    ULONG (STDMETHODCALLTYPE *Release)(IFileDialog2 *);
+    HRESULT (STDMETHODCALLTYPE *Show)(IFileDialog2 *, HWND);
+    HRESULT (STDMETHODCALLTYPE *SetFileTypes)(IFileDialog2 *, UINT, const COMDLG_FILTERSPEC *);
+    HRESULT (STDMETHODCALLTYPE *SetFileTypeIndex)(IFileDialog2 *, UINT);
+    HRESULT (STDMETHODCALLTYPE *GetFileTypeIndex)(IFileDialog2 *, UINT *);
+    HRESULT (STDMETHODCALLTYPE *Advise)(IFileDialog2 *, IFileDialogEvents *, DWORD *);
+    HRESULT (STDMETHODCALLTYPE *Unadvise)(IFileDialog2 *, DWORD);
+    HRESULT (STDMETHODCALLTYPE *SetOptions)(IFileDialog2 *, FILEOPENDIALOGOPTIONS);
+    HRESULT (STDMETHODCALLTYPE *GetOptions)(IFileDialog2 *, FILEOPENDIALOGOPTIONS *);
+    HRESULT (STDMETHODCALLTYPE *SetDefaultFolder)(IFileDialog2 *, IShellItem *);
+    HRESULT (STDMETHODCALLTYPE *SetFolder)(IFileDialog2 *, IShellItem *);
+    HRESULT (STDMETHODCALLTYPE *GetFolder)(IFileDialog2 *, IShellItem **);
+    HRESULT (STDMETHODCALLTYPE *GetCurrentSelection)(IFileDialog2 *, IShellItem **);
+    HRESULT (STDMETHODCALLTYPE *SetFileName)(IFileDialog2 *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *GetFileName)(IFileDialog2 *, LPWSTR *);
+    HRESULT (STDMETHODCALLTYPE *SetTitle)(IFileDialog2 *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *SetOkButtonLabel)(IFileDialog2 *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *SetFileNameLabel)(IFileDialog2 *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *GetResult)(IFileDialog2 *, IShellItem **);
+    HRESULT (STDMETHODCALLTYPE *AddPlace)(IFileDialog2 *, IShellItem *, FDAP);
+    HRESULT (STDMETHODCALLTYPE *SetDefaultExtension)(IFileDialog2 *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *Close)(IFileDialog2 *, HRESULT);
+    HRESULT (STDMETHODCALLTYPE *SetClientGuid)(IFileDialog2 *, REFGUID);
+    HRESULT (STDMETHODCALLTYPE *ClearClientData)(IFileDialog2 *);
+    HRESULT (STDMETHODCALLTYPE *SetFilter)(IFileDialog2 *, IShellItemFilter *);
+    HRESULT (STDMETHODCALLTYPE *SetCancelButtonLabel)(IFileDialog2 *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *SetNavigationRoot)(IFileDialog2 *, IShellItem *);
+} IFileDialog2Vtbl;
+/* *INDENT-ON* */ // clang-format on
+
+struct IFileDialog2
+{
+    const struct IFileDialog2Vtbl *lpVtbl;
+};
+#endif
+
+#ifndef __IFileOpenDialog_INTERFACE_DEFINED__
+/* *INDENT-OFF* */ // clang-format off
+typedef struct IFileOpenDialogVtbl
+{
+    HRESULT (STDMETHODCALLTYPE *QueryInterface)(IFileOpenDialog *, REFIID, void **);
+    ULONG (STDMETHODCALLTYPE *AddRef)(IFileOpenDialog *);
+    ULONG (STDMETHODCALLTYPE *Release)(IFileOpenDialog *);
+    HRESULT (STDMETHODCALLTYPE *Show)(IFileOpenDialog *, HWND);
+    HRESULT (STDMETHODCALLTYPE *SetFileTypes)(IFileOpenDialog *, UINT, const COMDLG_FILTERSPEC *);
+    HRESULT (STDMETHODCALLTYPE *SetFileTypeIndex)(IFileOpenDialog *, UINT);
+    HRESULT (STDMETHODCALLTYPE *GetFileTypeIndex)(IFileOpenDialog *, UINT *);
+    HRESULT (STDMETHODCALLTYPE *Advise)(IFileOpenDialog *, IFileDialogEvents *, DWORD *);
+    HRESULT (STDMETHODCALLTYPE *Unadvise)(IFileOpenDialog *, DWORD);
+    HRESULT (STDMETHODCALLTYPE *SetOptions)(IFileOpenDialog *, FILEOPENDIALOGOPTIONS);
+    HRESULT (STDMETHODCALLTYPE *GetOptions)(IFileOpenDialog *, FILEOPENDIALOGOPTIONS *);
+    HRESULT (STDMETHODCALLTYPE *SetDefaultFolder)(IFileOpenDialog *, IShellItem *);
+    HRESULT (STDMETHODCALLTYPE *SetFolder)(IFileOpenDialog *, IShellItem *);
+    HRESULT (STDMETHODCALLTYPE *GetFolder)(IFileOpenDialog *, IShellItem **);
+    HRESULT (STDMETHODCALLTYPE *GetCurrentSelection)(IFileOpenDialog *, IShellItem **);
+    HRESULT (STDMETHODCALLTYPE *SetFileName)(IFileOpenDialog *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *GetFileName)(IFileOpenDialog *, LPWSTR *);
+    HRESULT (STDMETHODCALLTYPE *SetTitle)(IFileOpenDialog *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *SetOkButtonLabel)(IFileOpenDialog *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *SetFileNameLabel)(IFileOpenDialog *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *GetResult)(IFileOpenDialog *, IShellItem **);
+    HRESULT (STDMETHODCALLTYPE *AddPlace)(IFileOpenDialog *, IShellItem *, FDAP);
+    HRESULT (STDMETHODCALLTYPE *SetDefaultExtension)(IFileOpenDialog *, LPCWSTR);
+    HRESULT (STDMETHODCALLTYPE *Close)(IFileOpenDialog *, HRESULT);
+    HRESULT (STDMETHODCALLTYPE *SetClientGuid)(IFileOpenDialog *, REFGUID);
+    HRESULT (STDMETHODCALLTYPE *ClearClientData)(IFileOpenDialog *);
+    HRESULT (STDMETHODCALLTYPE *SetFilter)(IFileOpenDialog *, IShellItemFilter *);
+    HRESULT (STDMETHODCALLTYPE *GetResults)(IFileOpenDialog *, IShellItemArray **);
+    HRESULT (STDMETHODCALLTYPE *GetSelectedItems)(IFileOpenDialog *, IShellItemArray **);
+} IFileOpenDialogVtbl;
+/* *INDENT-ON* */ // clang-format on
+
+struct IFileOpenDialog
+{
+    const struct IFileOpenDialogVtbl *lpVtbl;
+};
+#endif
+
+/* *INDENT-OFF* */ // clang-format off
+static const CLSID SDL_CLSID_FileOpenDialog = { 0xdc1c5a9c, 0xe88a, 0x4dde, { 0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7 } };
+static const CLSID SDL_CLSID_FileSaveDialog = { 0xc0b4e2f3, 0xba21, 0x4773, { 0x8d, 0xba, 0x33, 0x5e, 0xc9, 0x46, 0xeb, 0x8b } };
+
+static const IID SDL_IID_IFileDialog = { 0x42f85136, 0xdb7e, 0x439c, { 0x85, 0xf1, 0xe4, 0x07, 0x5d, 0x13, 0x5f, 0xc8 } };
+static const IID SDL_IID_IFileDialog2 = { 0x61744fc7, 0x85b5, 0x4791, { 0xa9, 0xb0, 0x27, 0x22, 0x76, 0x30, 0x9b, 0x13 } };
+static const IID SDL_IID_IFileOpenDialog = { 0xd57c7288, 0xd4ad, 0x4768, { 0xbe, 0x02, 0x9d, 0x96, 0x95, 0x32, 0xd9, 0x60 } };
+/* *INDENT-ON* */ // clang-format on
+
 // If this number is too small, selecting too many files will give an error
 #define SELECTLIST_SIZE 65536
 
@@ -115,6 +281,11 @@ bool windows_ShowModernFileFolderDialog(SDL_FileDialogType dialog_type, const ch
         allow_many = false;
     }
 
+    HMODULE shell32_handle = NULL;
+
+    typedef HRESULT(WINAPI *pfnSHCreateItemFromParsingName)(PCWSTR, IBindCtx *, REFIID, void **);
+    pfnSHCreateItemFromParsingName pSHCreateItemFromParsingName = NULL;
+
     IFileDialog *pFileDialog = NULL;
     IFileOpenDialog *pFileOpenDialog = NULL;
     IFileDialog2 *pFileDialog2 = NULL;
@@ -135,6 +306,17 @@ bool windows_ShowModernFileFolderDialog(SDL_FileDialogType dialog_type, const ch
     bool success = false;
     bool co_init = false;
 
+    // We can assume shell32 is already loaded here.
+    shell32_handle = GetModuleHandle(TEXT("shell32.dll"));
+    if (!shell32_handle) {
+        goto quit;
+    }
+
+    pSHCreateItemFromParsingName = (pfnSHCreateItemFromParsingName)GetProcAddress(shell32_handle, "SHCreateItemFromParsingName");
+    if (!pSHCreateItemFromParsingName) {
+        goto quit;
+    }
+
     if (filter_wchar && nfilters > 0) {
         wchar_t *filter_ptr = filter_wchar;
         filter_data = SDL_calloc(sizeof(COMDLG_FILTERSPEC), nfilters);
@@ -196,11 +378,11 @@ bool windows_ShowModernFileFolderDialog(SDL_FileDialogType dialog_type, const ch
 
     co_init = true;
 
-    CHECK(CoCreateInstance(is_save ? &CLSID_FileSaveDialog : &CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, &IID_IFileDialog, (void**)&pFileDialog));
-    CHECK(pFileDialog->lpVtbl->QueryInterface(pFileDialog, &IID_IFileDialog2, (void**)&pFileDialog2));
+    CHECK(CoCreateInstance(is_save ? &SDL_CLSID_FileSaveDialog : &SDL_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_IFileDialog, (void**)&pFileDialog));
+    CHECK(pFileDialog->lpVtbl->QueryInterface(pFileDialog, &SDL_IID_IFileDialog2, (void**)&pFileDialog2));
 
     if (allow_many) {
-        CHECK(pFileDialog->lpVtbl->QueryInterface(pFileDialog, &IID_IFileOpenDialog, (void**)&pFileOpenDialog));
+        CHECK(pFileDialog->lpVtbl->QueryInterface(pFileDialog, &SDL_IID_IFileOpenDialog, (void**)&pFileOpenDialog));
     }
 
     CHECK(pFileDialog2->lpVtbl->GetOptions(pFileDialog2, &pfos));
@@ -231,7 +413,7 @@ bool windows_ShowModernFileFolderDialog(SDL_FileDialogType dialog_type, const ch
     // SetFolder would enforce using the same location each and every time, but
     // Windows docs recommend against it
     if (default_folder_w) {
-        CHECK(SHCreateItemFromParsingName(default_folder_w, NULL, &IID_IShellItem, (void**)&pFolderItem));
+        CHECK(pSHCreateItemFromParsingName(default_folder_w, NULL, &IID_IShellItem, (void**)&pFolderItem));
         CHECK(pFileDialog->lpVtbl->SetDefaultFolder(pFileDialog, pFolderItem));
     }