/* * Common Item Dialog * * Copyright 2010,2011 David Hedberg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #define COBJMACROS #define NONAMELESSUNION #define NONAMELESSSTRUCT #include "windef.h" #include "winbase.h" #include "winuser.h" #include "wingdi.h" #include "winreg.h" #include "shlwapi.h" #include "commdlg.h" #include "cdlg.h" #include "filedlgbrowser.h" #include "wine/debug.h" #include "wine/list.h" #define IDC_NAV_TOOLBAR 200 #define IDC_NAVBACK 201 #define IDC_NAVFORWARD 202 WINE_DEFAULT_DEBUG_CHANNEL(commdlg); enum ITEMDLG_TYPE { ITEMDLG_TYPE_OPEN, ITEMDLG_TYPE_SAVE }; typedef struct { struct list entry; IFileDialogEvents *pfde; DWORD cookie; } events_client; typedef struct FileDialogImpl { IFileDialog2 IFileDialog2_iface; union { IFileOpenDialog IFileOpenDialog_iface; IFileSaveDialog IFileSaveDialog_iface; } u; enum ITEMDLG_TYPE dlg_type; IExplorerBrowserEvents IExplorerBrowserEvents_iface; IServiceProvider IServiceProvider_iface; ICommDlgBrowser3 ICommDlgBrowser3_iface; LONG ref; FILEOPENDIALOGOPTIONS options; COMDLG_FILTERSPEC *filterspecs; UINT filterspec_count; UINT filetypeindex; struct list events_clients; DWORD events_next_cookie; IShellItemArray *psia_selection; IShellItemArray *psia_results; IShellItem *psi_defaultfolder; IShellItem *psi_setfolder; IShellItem *psi_folder; HWND dlg_hwnd; IExplorerBrowser *peb; DWORD ebevents_cookie; LPWSTR set_filename; LPWSTR custom_title; LPWSTR custom_okbutton; LPWSTR custom_cancelbutton; LPWSTR custom_filenamelabel; } FileDialogImpl; /************************************************************************** * Helper functions. */ static UINT get_file_name(FileDialogImpl *This, LPWSTR *str) { HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME); UINT len; if(!hwnd_edit) { if(This->set_filename) { len = lstrlenW(This->set_filename); *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1)); lstrcpyW(*str, This->set_filename); return len; } return FALSE; } len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0); *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1)); if(!*str) return FALSE; SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str); return len; } static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str) { HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME); if(This->set_filename) LocalFree(This->set_filename); This->set_filename = StrDupW(str); return SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str); } static void fill_filename_from_selection(FileDialogImpl *This) { IShellItem *psi; LPWSTR *names; HRESULT hr; UINT item_count, valid_count; UINT len_total, i; if(!This->psia_selection) return; hr = IShellItemArray_GetCount(This->psia_selection, &item_count); if(FAILED(hr) || !item_count) return; names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR)); /* Get names of the selected items */ valid_count = 0; len_total = 0; for(i = 0; i < item_count; i++) { hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi); if(SUCCEEDED(hr)) { UINT attr; hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr); if(SUCCEEDED(hr) && (attr & SFGAO_FOLDER)) continue; /* FIXME: FOS_PICKFOLDERS */ hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]); if(SUCCEEDED(hr)) { len_total += lstrlenW(names[valid_count]) + 3; valid_count++; } IShellItem_Release(psi); } } if(valid_count == 1) { set_file_name(This, names[0]); CoTaskMemFree(names[0]); } else if(valid_count > 1) { LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total); LPWSTR cur_point = string; for(i = 0; i < valid_count; i++) { LPWSTR file = names[i]; *cur_point++ = '\"'; lstrcpyW(cur_point, file); cur_point += lstrlenW(file); *cur_point++ = '\"'; *cur_point++ = ' '; CoTaskMemFree(file); } *(cur_point-1) = '\0'; set_file_name(This, string); HeapFree(GetProcessHeap(), 0, string); } HeapFree(GetProcessHeap(), 0, names); return; } static HRESULT on_default_action(FileDialogImpl *This) { IShellFolder *psf_parent, *psf_desktop; LPITEMIDLIST *pidla; LPITEMIDLIST current_folder; LPWSTR fn_iter, files, tmp_files; UINT file_count = 0, len, i; int open_action; HRESULT hr, ret = E_FAIL; len = get_file_name(This, &tmp_files); if(len) { UINT size_used; file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used); } if(!file_count) return E_FAIL; hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, ¤t_folder); if(FAILED(hr)) { ERR("Failed to get pidl for current directory.\n"); return hr; } TRACE("Acting on %d file(s).\n", file_count); pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count); open_action = ONOPEN_OPEN; fn_iter = files; for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++) { WCHAR canon_filename[MAX_PATH]; psf_parent = NULL; COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename); if( (This->options & FOS_NOVALIDATE) && !(This->options & FOS_FILEMUSTEXIST) ) open_action = ONOPEN_OPEN; else open_action = ONOPEN_BROWSE; open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd, This->options, (This->dlg_type == ITEMDLG_TYPE_SAVE), open_action); pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename); if(psf_parent && !(open_action == ONOPEN_BROWSE)) IShellItem_Release(psf_parent); fn_iter += (WCHAR)lstrlenW(fn_iter) + 1; } HeapFree(GetProcessHeap(), 0, files); ILFree(current_folder); if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE) open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */ switch(open_action) { case ONOPEN_SEARCH: FIXME("Filtering not implemented.\n"); break; case ONOPEN_BROWSE: hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER); if(FAILED(hr)) ERR("Failed to browse to directory: %08x\n", hr); IShellItem_Release(psf_parent); break; case ONOPEN_OPEN: hr = SHGetDesktopFolder(&psf_desktop); if(SUCCEEDED(hr)) { if(This->psia_results) IShellItemArray_Release(This->psia_results); hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla, &This->psia_results); if(SUCCEEDED(hr)) ret = S_OK; IShellFolder_Release(psf_desktop); } break; default: ERR("Failed.\n"); break; } /* Clean up */ for(i = 0; i < file_count; i++) ILFree(pidla[i]); HeapFree(GetProcessHeap(), 0, pidla); /* Success closes the dialog */ return ret; } /************************************************************************** * Control functions. */ static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width) { LPWSTR text; UINT len, final_width; SIZE size; RECT rc; HDC hdc; TRACE("\n"); len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0); text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1)); if(!text) return; SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text); hdc = GetDC(hctrl); GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size); ReleaseDC(hctrl, hdc); GetWindowRect(hctrl, &rc); final_width = min(max(size.cx, min_width) + 4, max_width); SetWindowPos(hctrl, NULL, 0, 0, final_width, rc.bottom - rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); HeapFree(GetProcessHeap(), 0, text); } /************************************************************************** * Window related functions. */ static SIZE update_layout(FileDialogImpl *This) { HDWP hdwp; HWND hwnd; RECT dialog_rc; RECT cancel_rc, open_rc; RECT filetype_rc, filename_rc, filenamelabel_rc; RECT toolbar_rc, ebrowser_rc; int missing_width, missing_height; static const UINT vspacing = 4, hspacing = 4; SIZE ret; GetClientRect(This->dlg_hwnd, &dialog_rc); missing_width = max(0, 320 - dialog_rc.right); missing_height = max(0, 200 - dialog_rc.bottom); if(missing_width || missing_height) { TRACE("Missing (%d, %d)\n", missing_width, missing_height); ret.cx = missing_width; ret.cy = missing_height; return ret; } /**** * Calculate the size of the dialog and all the parts. */ /* Cancel button */ hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL); if(hwnd) { int cancel_width, cancel_height; GetWindowRect(hwnd, &cancel_rc); cancel_width = cancel_rc.right - cancel_rc.left; cancel_height = cancel_rc.bottom - cancel_rc.top; cancel_rc.left = dialog_rc.right - cancel_width - hspacing; cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing; cancel_rc.right = cancel_rc.left + cancel_width; cancel_rc.bottom = cancel_rc.top + cancel_height; } /* Open/Save button */ hwnd = GetDlgItem(This->dlg_hwnd, IDOK); if(hwnd) { int open_width, open_height; GetWindowRect(hwnd, &open_rc); open_width = open_rc.right - open_rc.left; open_height = open_rc.bottom - open_rc.top; open_rc.left = cancel_rc.left - open_width - hspacing; open_rc.top = cancel_rc.top; open_rc.right = open_rc.left + open_width; open_rc.bottom = open_rc.top + open_height; } /* The filetype combobox. */ hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE); if(hwnd) { int filetype_width, filetype_height; GetWindowRect(hwnd, &filetype_rc); filetype_width = filetype_rc.right - filetype_rc.left; filetype_height = filetype_rc.bottom - filetype_rc.top; filetype_rc.right = cancel_rc.right; filetype_rc.left = filetype_rc.right - filetype_width; filetype_rc.top = cancel_rc.top - filetype_height - vspacing; filetype_rc.bottom = filetype_rc.top + filetype_height; if(!This->filterspec_count) filetype_rc.left = filetype_rc.right; } /* Filename label. */ hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC); if(hwnd) { int filetypelabel_width, filetypelabel_height; GetWindowRect(hwnd, &filenamelabel_rc); filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left; filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top; filenamelabel_rc.left = 160; /* FIXME */ filenamelabel_rc.top = filetype_rc.top; filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width; filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height; } /* Filename edit box. */ hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME); if(hwnd) { int filename_width, filename_height; GetWindowRect(hwnd, &filename_rc); filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2; filename_height = filename_rc.bottom - filename_rc.top; filename_rc.left = filenamelabel_rc.right + hspacing; filename_rc.top = filetype_rc.top; filename_rc.right = filename_rc.left + filename_width; filename_rc.bottom = filename_rc.top + filename_height; } hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR); if(hwnd) { GetWindowRect(hwnd, &toolbar_rc); MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2); } /* The ExplorerBrowser control. */ ebrowser_rc.left = dialog_rc.left + vspacing; ebrowser_rc.top = toolbar_rc.bottom + vspacing; ebrowser_rc.right = dialog_rc.right - hspacing; ebrowser_rc.bottom = filename_rc.top - hspacing; /**** * Move everything to the right place. */ /* FIXME: The Save Dialog uses a slightly different layout. */ hdwp = BeginDeferWindowPos(6); if(hdwp && This->peb) IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc); /* The default controls */ if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) ) DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) ) DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top, filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top, SWP_NOZORDER | SWP_NOACTIVATE); if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) ) DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) ) DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) ) DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); if(hdwp) EndDeferWindowPos(hdwp); else ERR("Failed to position dialog controls.\n"); ret.cx = 0; ret.cy = 0; return ret; } static HRESULT init_explorerbrowser(FileDialogImpl *This) { IShellItem *psi_folder; FOLDERSETTINGS fos; RECT rc = {0}; HRESULT hr; /* Create ExplorerBrowser instance */ OleInitialize(NULL); hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER, &IID_IExplorerBrowser, (void**)&This->peb); if(FAILED(hr)) { ERR("Failed to instantiate ExplorerBrowser control.\n"); return hr; } IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES); hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL); if(FAILED(hr)) { ERR("Failed to initialize the ExplorerBrowser control.\n"); IExplorerBrowser_Release(This->peb); This->peb = NULL; return hr; } hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie); if(FAILED(hr)) ERR("Advise (ExplorerBrowser) failed.\n"); /* Get previous options? */ fos.ViewMode = fos.fFlags = 0; if(!(This->options & FOS_ALLOWMULTISELECT)) fos.fFlags |= FWF_SINGLESEL; IExplorerBrowser_SetFolderSettings(This->peb, &fos); hr = IUnknown_SetSite((IUnknown*)This->peb, (IUnknown*)This); if(FAILED(hr)) ERR("SetSite (ExplorerBrowser) failed.\n"); /* Browse somewhere */ psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder; IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER); return S_OK; } static void init_toolbar(FileDialogImpl *This, HWND hwnd) { HWND htoolbar; TBADDBITMAP tbab; TBBUTTON button[2]; htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL); tbab.hInst = HINST_COMMCTRL; tbab.nID = IDB_HIST_LARGE_COLOR; SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab); button[0].iBitmap = HIST_BACK; button[0].idCommand = IDC_NAVBACK; button[0].fsState = TBSTATE_ENABLED; button[0].fsStyle = BTNS_BUTTON; button[0].dwData = 0; button[0].iString = 0; button[1].iBitmap = HIST_FORWARD; button[1].idCommand = IDC_NAVFORWARD; button[1].fsState = TBSTATE_ENABLED; button[1].fsStyle = BTNS_BUTTON; button[1].dwData = 0; button[1].iString = 0; SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)&button); SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24)); SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0); } static void update_control_text(FileDialogImpl *This) { HWND hitem; if(This->custom_title) SetWindowTextW(This->dlg_hwnd, This->custom_title); if(This->custom_okbutton && (hitem = GetDlgItem(This->dlg_hwnd, IDOK))) { SetWindowTextW(hitem, This->custom_okbutton); ctrl_resize(hitem, 50, 250); } if(This->custom_cancelbutton && (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL))) { SetWindowTextW(hitem, This->custom_cancelbutton); ctrl_resize(hitem, 50, 250); } if(This->custom_filenamelabel && (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC))) { SetWindowTextW(hitem, This->custom_filenamelabel); ctrl_resize(hitem, 50, 250); } } static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam) { FileDialogImpl *This = (FileDialogImpl*)lParam; HWND hitem; TRACE("(%p, %p)\n", This, hwnd); SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This); This->dlg_hwnd = hwnd; hitem = GetDlgItem(This->dlg_hwnd, pshHelp); if(hitem) ShowWindow(hitem, SW_HIDE); hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC); if(hitem) ShowWindow(hitem, SW_HIDE); /* Fill filetypes combobox, or hide it. */ hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE); if(This->filterspec_count) { UINT i; for(i = 0; i < This->filterspec_count; i++) SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName); SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0); } else ShowWindow(hitem, SW_HIDE); if(This->set_filename && (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) ) SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename); init_explorerbrowser(This); init_toolbar(This, hwnd); update_control_text(This); update_layout(This); return TRUE; } static LRESULT on_wm_size(FileDialogImpl *This) { update_layout(This); return FALSE; } static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam) { MINMAXINFO *mmi = (MINMAXINFO*)lparam; TRACE("%p (%p)\n", This, mmi); /* FIXME */ mmi->ptMinTrackSize.x = 640; mmi->ptMinTrackSize.y = 480; return FALSE; } static LRESULT on_wm_destroy(FileDialogImpl *This) { TRACE("%p\n", This); if(This->peb) { IExplorerBrowser_Destroy(This->peb); IExplorerBrowser_Release(This->peb); This->peb = NULL; } This->dlg_hwnd = NULL; return TRUE; } static LRESULT on_idok(FileDialogImpl *This) { TRACE("%p\n", This); if(SUCCEEDED(on_default_action(This))) EndDialog(This->dlg_hwnd, S_OK); return FALSE; } static LRESULT on_idcancel(FileDialogImpl *This) { TRACE("%p\n", This); EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED)); return FALSE; } static LRESULT on_browse_back(FileDialogImpl *This) { TRACE("%p\n", This); IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK); return FALSE; } static LRESULT on_browse_forward(FileDialogImpl *This) { TRACE("%p\n", This); IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD); return FALSE; } static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam) { if(HIWORD(wparam) == CBN_SELCHANGE) { IShellView *psv; HRESULT hr; This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0); TRACE("File type selection changed to %d.\n", This->filetypeindex); hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv); if(SUCCEEDED(hr)) { IShellView_Refresh(psv); IShellView_Release(psv); } } return FALSE; } static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam) { switch(LOWORD(wparam)) { case IDOK: return on_idok(This); case IDCANCEL: return on_idcancel(This); case IDC_NAVBACK: return on_browse_back(This); case IDC_NAVFORWARD: return on_browse_forward(This); case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam); default: TRACE("Unknown command.\n"); } return FALSE; } static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam) { FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA); switch(umessage) { case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam); case WM_COMMAND: return on_wm_command(This, wparam, lparam); case WM_SIZE: return on_wm_size(This); case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam); case WM_DESTROY: return on_wm_destroy(This); } return FALSE; } static HRESULT create_dialog(FileDialogImpl *This, HWND parent) { INT_PTR res; SetLastError(0); res = DialogBoxParamW(COMDLG32_hInstance, MAKEINTRESOURCEW(NEWFILEOPENV3ORD), parent, itemdlg_dlgproc, (LPARAM)This); This->dlg_hwnd = NULL; if(res == -1) { ERR("Failed to show dialog (LastError: %d)\n", GetLastError()); return E_FAIL; } TRACE("Returning 0x%08x\n", (HRESULT)res); return (HRESULT)res; } /************************************************************************** * IFileDialog implementation */ static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface) { return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface); } static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface, REFIID riid, void **ppvObject) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject); *ppvObject = NULL; if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IFileDialog) || IsEqualGUID(riid, &IID_IFileDialog2)) { *ppvObject = iface; } else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN) { *ppvObject = &This->u.IFileOpenDialog_iface; } else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE) { *ppvObject = &This->u.IFileSaveDialog_iface; } else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents)) { *ppvObject = &This->IExplorerBrowserEvents_iface; } else if(IsEqualGUID(riid, &IID_IServiceProvider)) { *ppvObject = &This->IServiceProvider_iface; } else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) || IsEqualGUID(&IID_ICommDlgBrowser2, riid) || IsEqualGUID(&IID_ICommDlgBrowser, riid)) { *ppvObject = &This->ICommDlgBrowser3_iface; } else FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid)); if(*ppvObject) { IUnknown_AddRef((IUnknown*)*ppvObject); return S_OK; } return E_NOINTERFACE; } static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface) { FileDialogImpl *This = impl_from_IFileDialog2(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("%p - ref %d\n", This, ref); return ref; } static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface) { FileDialogImpl *This = impl_from_IFileDialog2(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("%p - ref %d\n", This, ref); if(!ref) { UINT i; for(i = 0; i < This->filterspec_count; i++) { LocalFree((void*)This->filterspecs[i].pszName); LocalFree((void*)This->filterspecs[i].pszSpec); } HeapFree(GetProcessHeap(), 0, This->filterspecs); if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder); if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder); if(This->psi_folder) IShellItem_Release(This->psi_folder); if(This->psia_selection) IShellItemArray_Release(This->psia_selection); if(This->psia_results) IShellItemArray_Release(This->psia_results); LocalFree(This->set_filename); LocalFree(This->custom_title); LocalFree(This->custom_okbutton); LocalFree(This->custom_cancelbutton); LocalFree(This->custom_filenamelabel); HeapFree(GetProcessHeap(), 0, This); } return ref; } static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", iface, hwndOwner); return create_dialog(This, hwndOwner); } static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec) { FileDialogImpl *This = impl_from_IFileDialog2(iface); UINT i; TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec); if(This->filterspecs) return E_UNEXPECTED; if(!rgFilterSpec) return E_INVALIDARG; if(!cFileTypes) return S_OK; This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes); for(i = 0; i < cFileTypes; i++) { This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName); This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec); } This->filterspec_count = cFileTypes; return S_OK; } static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%d)\n", This, iFileType); if(!This->filterspecs) return E_FAIL; if(iFileType >= This->filterspec_count) This->filetypeindex = This->filterspec_count - 1; else This->filetypeindex = iFileType; return S_OK; } static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", This, piFileType); if(!piFileType) return E_INVALIDARG; *piFileType = This->filetypeindex; return S_OK; } static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie) { FileDialogImpl *This = impl_from_IFileDialog2(iface); events_client *client; TRACE("%p (%p, %p)\n", This, pfde, pdwCookie); if(!pfde || !pdwCookie) return E_INVALIDARG; client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client)); client->pfde = pfde; client->cookie = ++This->events_next_cookie; IFileDialogEvents_AddRef(pfde); *pdwCookie = client->cookie; list_add_tail(&This->events_clients, &client->entry); return S_OK; } static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie) { FileDialogImpl *This = impl_from_IFileDialog2(iface); events_client *client, *found = NULL; TRACE("%p (%d)\n", This, dwCookie); LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry) { if(client->cookie == dwCookie) { found = client; break; } } if(found) { list_remove(&found->entry); IFileDialogEvents_Release(found->pfde); HeapFree(GetProcessHeap(), 0, found); return S_OK; } return E_INVALIDARG; } static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (0x%x)\n", This, fos); This->options = fos; return S_OK; } static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", This, pfos); if(!pfos) return E_INVALIDARG; *pfos = This->options; return S_OK; } static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", This, psi); if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder); This->psi_defaultfolder = psi; if(This->psi_defaultfolder) IShellItem_AddRef(This->psi_defaultfolder); return S_OK; } static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", This, psi); if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder); This->psi_setfolder = psi; if(This->psi_setfolder) IShellItem_AddRef(This->psi_setfolder); return S_OK; } static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", This, ppsi); if(!ppsi) return E_INVALIDARG; /* FIXME: If the dialog is shown, return the current(ly selected) folder. */ *ppsi = NULL; if(This->psi_folder) *ppsi = This->psi_folder; else if(This->psi_setfolder) *ppsi = This->psi_setfolder; else if(This->psi_defaultfolder) *ppsi = This->psi_defaultfolder; if(*ppsi) { IShellItem_AddRef(*ppsi); return S_OK; } return E_FAIL; } static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi) { FileDialogImpl *This = impl_from_IFileDialog2(iface); HRESULT hr; TRACE("%p (%p)\n", This, ppsi); if(!ppsi) return E_INVALIDARG; if(This->psia_selection) { /* FIXME: Check filename edit box */ hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi); return hr; } return E_FAIL; } static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", iface, pszName); set_file_name(This, pszName); return S_OK; } static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", iface, pszName); if(!pszName) return E_INVALIDARG; *pszName = NULL; if(get_file_name(This, pszName)) return S_OK; else return E_FAIL; } static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", This, pszTitle); LocalFree(This->custom_title); This->custom_title = StrDupW(pszTitle); update_control_text(This); return S_OK; } static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", This, pszText); LocalFree(This->custom_okbutton); This->custom_okbutton = StrDupW(pszText); update_control_text(This); update_layout(This); return S_OK; } static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", This, pszLabel); LocalFree(This->custom_filenamelabel); This->custom_filenamelabel = StrDupW(pszLabel); update_control_text(This); update_layout(This); return S_OK; } static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi) { FileDialogImpl *This = impl_from_IFileDialog2(iface); HRESULT hr; TRACE("%p (%p)\n", This, ppsi); if(!ppsi) return E_INVALIDARG; if(This->psia_results) { UINT item_count; hr = IShellItemArray_GetCount(This->psia_results, &item_count); if(SUCCEEDED(hr)) { if(item_count != 1) return E_FAIL; /* Adds a reference. */ hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi); } return hr; } return E_UNEXPECTED; } static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap) { FileDialogImpl *This = impl_from_IFileDialog2(iface); FIXME("stub - %p (%p, %d)\n", This, psi, fdap); return E_NOTIMPL; } static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension) { FileDialogImpl *This = impl_from_IFileDialog2(iface); FIXME("stub - %p (%s)\n", This, debugstr_w(pszDefaultExtension)); return E_NOTIMPL; } static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (0x%08x)\n", This, hr); if(This->dlg_hwnd) EndDialog(This->dlg_hwnd, hr); return S_OK; } static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid) { FileDialogImpl *This = impl_from_IFileDialog2(iface); FIXME("stub - %p (%s)\n", This, debugstr_guid(guid)); return E_NOTIMPL; } static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface) { FileDialogImpl *This = impl_from_IFileDialog2(iface); FIXME("stub - %p\n", This); return E_NOTIMPL; } static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter) { FileDialogImpl *This = impl_from_IFileDialog2(iface); FIXME("stub - %p (%p)\n", This, pFilter); return E_NOTIMPL; } static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel) { FileDialogImpl *This = impl_from_IFileDialog2(iface); TRACE("%p (%p)\n", This, pszLabel); LocalFree(This->custom_cancelbutton); This->custom_cancelbutton = StrDupW(pszLabel); update_control_text(This); update_layout(This); return S_OK; } static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi) { FileDialogImpl *This = impl_from_IFileDialog2(iface); FIXME("stub - %p (%p)\n", This, psi); return E_NOTIMPL; } static const IFileDialog2Vtbl vt_IFileDialog2 = { IFileDialog2_fnQueryInterface, IFileDialog2_fnAddRef, IFileDialog2_fnRelease, IFileDialog2_fnShow, IFileDialog2_fnSetFileTypes, IFileDialog2_fnSetFileTypeIndex, IFileDialog2_fnGetFileTypeIndex, IFileDialog2_fnAdvise, IFileDialog2_fnUnadvise, IFileDialog2_fnSetOptions, IFileDialog2_fnGetOptions, IFileDialog2_fnSetDefaultFolder, IFileDialog2_fnSetFolder, IFileDialog2_fnGetFolder, IFileDialog2_fnGetCurrentSelection, IFileDialog2_fnSetFileName, IFileDialog2_fnGetFileName, IFileDialog2_fnSetTitle, IFileDialog2_fnSetOkButtonLabel, IFileDialog2_fnSetFileNameLabel, IFileDialog2_fnGetResult, IFileDialog2_fnAddPlace, IFileDialog2_fnSetDefaultExtension, IFileDialog2_fnClose, IFileDialog2_fnSetClientGuid, IFileDialog2_fnClearClientData, IFileDialog2_fnSetFilter, IFileDialog2_fnSetCancelButtonLabel, IFileDialog2_fnSetNavigationRoot }; /************************************************************************** * IFileOpenDialog */ static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface) { return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface); } static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface, REFIID riid, void **ppvObject) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); } static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_AddRef(&This->IFileDialog2_iface); } static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_Release(&This->IFileDialog2_iface); } static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner); } static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec); } static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType); } static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType); } static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde, DWORD *pdwCookie) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie); } static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie); } static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos); } static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos); } static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi); } static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi); } static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi); } static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi); } static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName); } static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName); } static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle); } static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText); } static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel); } static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi); } static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap); } static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface, LPCWSTR pszDefaultExtension) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension); } static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_Close(&This->IFileDialog2_iface, hr); } static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid); } static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_ClearClientData(&This->IFileDialog2_iface); } static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter); } static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); TRACE("%p (%p)\n", This, ppenum); *ppenum = This->psia_results; if(*ppenum) { IShellItemArray_AddRef(*ppenum); return S_OK; } return E_FAIL; } static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai) { FileDialogImpl *This = impl_from_IFileOpenDialog(iface); TRACE("%p (%p)\n", This, ppsai); if(This->psia_selection) { *ppsai = This->psia_selection; IShellItemArray_AddRef(*ppsai); return S_OK; } return E_FAIL; } static const IFileOpenDialogVtbl vt_IFileOpenDialog = { IFileOpenDialog_fnQueryInterface, IFileOpenDialog_fnAddRef, IFileOpenDialog_fnRelease, IFileOpenDialog_fnShow, IFileOpenDialog_fnSetFileTypes, IFileOpenDialog_fnSetFileTypeIndex, IFileOpenDialog_fnGetFileTypeIndex, IFileOpenDialog_fnAdvise, IFileOpenDialog_fnUnadvise, IFileOpenDialog_fnSetOptions, IFileOpenDialog_fnGetOptions, IFileOpenDialog_fnSetDefaultFolder, IFileOpenDialog_fnSetFolder, IFileOpenDialog_fnGetFolder, IFileOpenDialog_fnGetCurrentSelection, IFileOpenDialog_fnSetFileName, IFileOpenDialog_fnGetFileName, IFileOpenDialog_fnSetTitle, IFileOpenDialog_fnSetOkButtonLabel, IFileOpenDialog_fnSetFileNameLabel, IFileOpenDialog_fnGetResult, IFileOpenDialog_fnAddPlace, IFileOpenDialog_fnSetDefaultExtension, IFileOpenDialog_fnClose, IFileOpenDialog_fnSetClientGuid, IFileOpenDialog_fnClearClientData, IFileOpenDialog_fnSetFilter, IFileOpenDialog_fnGetResults, IFileOpenDialog_fnGetSelectedItems }; /************************************************************************** * IFileSaveDialog */ static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface) { return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface); } static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface, REFIID riid, void **ppvObject) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); } static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_AddRef(&This->IFileDialog2_iface); } static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_Release(&This->IFileDialog2_iface); } static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner); } static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec); } static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType); } static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType); } static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde, DWORD *pdwCookie) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie); } static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie); } static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos); } static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos); } static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi); } static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi); } static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi); } static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi); } static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName); } static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName); } static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle); } static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText); } static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel); } static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi); } static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap); } static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface, LPCWSTR pszDefaultExtension) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension); } static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_Close(&This->IFileDialog2_iface, hr); } static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid); } static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_ClearClientData(&This->IFileDialog2_iface); } static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter); } static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); FIXME("stub - %p (%p)\n", This, psi); return E_NOTIMPL; } static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); FIXME("stub - %p (%p)\n", This, pStore); return E_NOTIMPL; } static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface, IPropertyDescriptionList *pList, BOOL fAppendDefault) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault); return E_NOTIMPL; } static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); FIXME("stub - %p (%p)\n", This, ppStore); return E_NOTIMPL; } static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface, IShellItem *psi, IPropertyStore *pStore, HWND hwnd, IFileOperationProgressSink *pSink) { FileDialogImpl *This = impl_from_IFileSaveDialog(iface); FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink); return E_NOTIMPL; } static const IFileSaveDialogVtbl vt_IFileSaveDialog = { IFileSaveDialog_fnQueryInterface, IFileSaveDialog_fnAddRef, IFileSaveDialog_fnRelease, IFileSaveDialog_fnShow, IFileSaveDialog_fnSetFileTypes, IFileSaveDialog_fnSetFileTypeIndex, IFileSaveDialog_fnGetFileTypeIndex, IFileSaveDialog_fnAdvise, IFileSaveDialog_fnUnadvise, IFileSaveDialog_fnSetOptions, IFileSaveDialog_fnGetOptions, IFileSaveDialog_fnSetDefaultFolder, IFileSaveDialog_fnSetFolder, IFileSaveDialog_fnGetFolder, IFileSaveDialog_fnGetCurrentSelection, IFileSaveDialog_fnSetFileName, IFileSaveDialog_fnGetFileName, IFileSaveDialog_fnSetTitle, IFileSaveDialog_fnSetOkButtonLabel, IFileSaveDialog_fnSetFileNameLabel, IFileSaveDialog_fnGetResult, IFileSaveDialog_fnAddPlace, IFileSaveDialog_fnSetDefaultExtension, IFileSaveDialog_fnClose, IFileSaveDialog_fnSetClientGuid, IFileSaveDialog_fnClearClientData, IFileSaveDialog_fnSetFilter, IFileSaveDialog_fnSetSaveAsItem, IFileSaveDialog_fnSetProperties, IFileSaveDialog_fnSetCollectedProperties, IFileSaveDialog_fnGetProperties, IFileSaveDialog_fnApplyProperties }; /************************************************************************** * IExplorerBrowserEvents implementation */ static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface) { return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface); } static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface, REFIID riid, void **ppvObject) { FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject); return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); } static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface) { FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); TRACE("%p\n", This); return IFileDialog2_AddRef(&This->IFileDialog2_iface); } static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface) { FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); TRACE("%p\n", This); return IFileDialog2_Release(&This->IFileDialog2_iface); } static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidlFolder) { FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); TRACE("%p (%p)\n", This, pidlFolder); return S_OK; } static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface, IShellView *psv) { FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); TRACE("%p (%p)\n", This, psv); return S_OK; } static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidlFolder) { FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); HRESULT hr; TRACE("%p (%p)\n", This, pidlFolder); if(This->psi_folder) IShellItem_Release(This->psi_folder); hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder); if(FAILED(hr)) { ERR("Failed to get the current folder.\n"); This->psi_folder = NULL; } return S_OK; } static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidlFolder) { FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); TRACE("%p (%p)\n", This, pidlFolder); return S_OK; } static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = { IExplorerBrowserEvents_fnQueryInterface, IExplorerBrowserEvents_fnAddRef, IExplorerBrowserEvents_fnRelease, IExplorerBrowserEvents_fnOnNavigationPending, IExplorerBrowserEvents_fnOnViewCreated, IExplorerBrowserEvents_fnOnNavigationComplete, IExplorerBrowserEvents_fnOnNavigationFailed }; /************************************************************************** * IServiceProvider implementation */ static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface) { return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface); } static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObject) { FileDialogImpl *This = impl_from_IServiceProvider(iface); TRACE("%p\n", This); return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); } static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface) { FileDialogImpl *This = impl_from_IServiceProvider(iface); TRACE("%p\n", This); return IFileDialog2_AddRef(&This->IFileDialog2_iface); } static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface) { FileDialogImpl *This = impl_from_IServiceProvider(iface); TRACE("%p\n", This); return IFileDialog2_Release(&This->IFileDialog2_iface); } static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface, REFGUID guidService, REFIID riid, void **ppv) { FileDialogImpl *This = impl_from_IServiceProvider(iface); HRESULT hr = E_FAIL; TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); *ppv = NULL; if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb) hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv); else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame)) hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv); else FIXME("Interface %s requested from unknown service %s\n", debugstr_guid(riid), debugstr_guid(guidService)); if(SUCCEEDED(hr) && *ppv) { IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } return E_FAIL; } static const IServiceProviderVtbl vt_IServiceProvider = { IServiceProvider_fnQueryInterface, IServiceProvider_fnAddRef, IServiceProvider_fnRelease, IServiceProvider_fnQueryService }; /************************************************************************** * ICommDlgBrowser3 implementation */ static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface) { return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface); } static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface, REFIID riid, void **ppvObject) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p\n", This); return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); } static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p\n", This); return IFileDialog2_AddRef(&This->IFileDialog2_iface); } static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p\n", This); return IFileDialog2_Release(&This->IFileDialog2_iface); } static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface, IShellView *shv) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); HRESULT hr; TRACE("%p (%p)\n", This, shv); hr = on_default_action(This); if(SUCCEEDED(hr)) EndDialog(This->dlg_hwnd, S_OK); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface, IShellView *shv, ULONG uChange ) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); IDataObject *new_selection; HRESULT hr; TRACE("%p (%p, %x)\n", This, shv, uChange); switch(uChange) { case CDBOSC_SELCHANGE: if(This->psia_selection) { IShellItemArray_Release(This->psia_selection); This->psia_selection = NULL; } hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection); if(SUCCEEDED(hr)) { hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray, (void**)&This->psia_selection); if(SUCCEEDED(hr)) fill_filename_from_selection(This); IDataObject_Release(new_selection); } break; default: TRACE("Unhandled state change\n"); } return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface, IShellView *shv, LPCITEMIDLIST pidl) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); IShellItem *psi; LPWSTR filename; LPITEMIDLIST parent_pidl; HRESULT hr; ULONG attr; TRACE("%p (%p, %p)\n", This, shv, pidl); if(!This->filterspec_count) return S_OK; hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl); if(SUCCEEDED(hr)) { LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl); hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi); ILFree(parent_pidl); ILFree(full_pidl); } if(FAILED(hr)) { ERR("Failed to get shellitem (%08x).\n", hr); return S_OK; } hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr); if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK))) { IShellItem_Release(psi); return S_OK; } hr = S_OK; if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename))) { if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec)) hr = S_FALSE; CoTaskMemFree(filename); } IShellItem_Release(psi); return hr; } static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface, IShellView *ppshv, DWORD dwNotifyType) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType); return E_NOTIMPL; } static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface, IShellView *pshv, LPWSTR pszText, int cchMax) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax); return E_NOTIMPL; } static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("Stub: %p (%p)\n", This, pdwFlags); return E_NOTIMPL; } static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface, IShellView *pshv, int iColumn) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn); return E_NOTIMPL; } static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface, LPWSTR pszFileSpec, int cchFileSpec) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec); return E_NOTIMPL; } static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface, IShellView *pshv) { FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("Stub: %p (%p)\n", This, pshv); return E_NOTIMPL; } static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = { ICommDlgBrowser3_fnQueryInterface, ICommDlgBrowser3_fnAddRef, ICommDlgBrowser3_fnRelease, ICommDlgBrowser3_fnOnDefaultCommand, ICommDlgBrowser3_fnOnStateChange, ICommDlgBrowser3_fnIncludeObject, ICommDlgBrowser3_fnNotify, ICommDlgBrowser3_fnGetDefaultMenuText, ICommDlgBrowser3_fnGetViewFlags, ICommDlgBrowser3_fnOnColumnClicked, ICommDlgBrowser3_fnGetCurrentFilter, ICommDlgBrowser3_fnOnPreviewCreated }; static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type) { FileDialogImpl *fdimpl; HRESULT hr; IShellFolder *psf; TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv); if(!ppv) return E_POINTER; if(pUnkOuter) return CLASS_E_NOAGGREGATION; fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl)); if(!fdimpl) return E_OUTOFMEMORY; fdimpl->ref = 1; fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2; fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents; fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider; fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3; if(type == ITEMDLG_TYPE_OPEN) { fdimpl->dlg_type = ITEMDLG_TYPE_OPEN; fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog; fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR; fdimpl->custom_title = fdimpl->custom_okbutton = NULL; } else { WCHAR buf[16]; fdimpl->dlg_type = ITEMDLG_TYPE_SAVE; fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog; fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR; LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR)); fdimpl->custom_title = StrDupW(buf); fdimpl->custom_okbutton = StrDupW(buf); } fdimpl->filterspecs = NULL; fdimpl->filterspec_count = 0; fdimpl->filetypeindex = 0; fdimpl->psia_selection = fdimpl->psia_results = NULL; fdimpl->psi_setfolder = fdimpl->psi_folder = NULL; list_init(&fdimpl->events_clients); fdimpl->events_next_cookie = 0; fdimpl->dlg_hwnd = NULL; fdimpl->peb = NULL; fdimpl->set_filename = NULL; fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL; /* FIXME: The default folder setting should be restored for the * application if it was previously set. */ SHGetDesktopFolder(&psf); SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder); IShellFolder_Release(psf); hr = IUnknown_QueryInterface((IUnknown*)fdimpl, riid, ppv); IUnknown_Release((IUnknown*)fdimpl); return hr; } HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) { return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN); } HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) { return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE); }