// 22 may 2015 #include "uipriv_windows.hpp" // notes: // - FOS_SUPPORTSTREAMABLEITEMS doesn't seem to be supported on windows vista, or at least not with the flags we use // - even with FOS_NOVALIDATE the dialogs will reject invalid filenames (at least on Vista, anyway) // TODO // - http://blogs.msdn.com/b/wpfsdk/archive/2006/10/26/uncommon-dialogs--font-chooser-and-color-picker-dialogs.aspx // - when a dialog is active, tab navigation in other windows stops working // - when adding uiOpenFolder(), use IFileDialog as well - https://msdn.microsoft.com/en-us/library/windows/desktop/bb762115%28v=vs.85%29.aspx #define windowHWND(w) ((HWND) uiControlHandle(uiControl(w))) char *commonItemDialog(HWND parent, REFCLSID clsid, REFIID iid, FILEOPENDIALOGOPTIONS optsadd) { IFileDialog *d = NULL; FILEOPENDIALOGOPTIONS opts; IShellItem *result = NULL; WCHAR *wname = NULL; char *name = NULL; HRESULT hr; hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, (LPVOID *) (&d)); if (hr != S_OK) { logHRESULT(L"error creating common item dialog", hr); // always return NULL on error goto out; } hr = d->GetOptions(&opts); if (hr != S_OK) { logHRESULT(L"error getting current options", hr); goto out; } opts |= optsadd; hr = d->SetOptions(opts); if (hr != S_OK) { logHRESULT(L"error setting options", hr); goto out; } hr = d->Show(parent); if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) // cancelled; return NULL like we have ready goto out; if (hr != S_OK) { logHRESULT(L"error showing dialog", hr); goto out; } hr = d->GetResult(&result); if (hr != S_OK) { logHRESULT(L"error getting dialog result", hr); goto out; } hr = result->GetDisplayName(SIGDN_FILESYSPATH, &wname); if (hr != S_OK) { logHRESULT(L"error getting filename", hr); goto out; } name = toUTF8(wname); out: if (wname != NULL) CoTaskMemFree(wname); if (result != NULL) result->Release(); if (d != NULL) d->Release(); return name; } char *uiOpenFile(uiWindow *parent) { return commonItemDialog(windowHWND(parent), CLSID_FileOpenDialog, IID_IFileOpenDialog, FOS_NOCHANGEDIR | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_SHAREAWARE | FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS | FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE); } char *uiSaveFile(uiWindow *parent) { return commonItemDialog(windowHWND(parent), CLSID_FileSaveDialog, IID_IFileSaveDialog, // TODO strip FOS_NOREADONLYRETURN? FOS_OVERWRITEPROMPT | FOS_NOCHANGEDIR | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_SHAREAWARE | FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS | FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE); } // TODO switch to TaskDialogIndirect()? static void msgbox(HWND parent, const char *title, const char *description, TASKDIALOG_COMMON_BUTTON_FLAGS buttons, PCWSTR icon) { WCHAR *wtitle, *wdescription; HRESULT hr; wtitle = toUTF16(title); wdescription = toUTF16(description); hr = TaskDialog(parent, NULL, NULL, wtitle, wdescription, buttons, icon, NULL); if (hr != S_OK) logHRESULT(L"error showing task dialog", hr); uiFree(wdescription); uiFree(wtitle); } void uiMsgBox(uiWindow *parent, const char *title, const char *description) { msgbox(windowHWND(parent), title, description, TDCBF_OK_BUTTON, NULL); } void uiMsgBoxError(uiWindow *parent, const char *title, const char *description) { msgbox(windowHWND(parent), title, description, TDCBF_OK_BUTTON, TD_ERROR_ICON); }