|  | /* | 
|  | * 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 <stdarg.h> | 
|  |  | 
|  | #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 | 
|  |  | 
|  | #include <initguid.h> | 
|  | /* This seems to be another version of IID_IFileDialogCustomize. If | 
|  | * there is any difference I have yet to find it. */ | 
|  | DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F); | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(commdlg); | 
|  |  | 
|  | static const WCHAR notifysink_childW[] = {'n','f','s','_','c','h','i','l','d',0}; | 
|  | static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0}; | 
|  |  | 
|  | enum ITEMDLG_TYPE { | 
|  | ITEMDLG_TYPE_OPEN, | 
|  | ITEMDLG_TYPE_SAVE | 
|  | }; | 
|  |  | 
|  | enum ITEMDLG_CCTRL_TYPE { | 
|  | IDLG_CCTRL_MENU, | 
|  | IDLG_CCTRL_PUSHBUTTON, | 
|  | IDLG_CCTRL_COMBOBOX, | 
|  | IDLG_CCTRL_RADIOBUTTONLIST, | 
|  | IDLG_CCTRL_CHECKBUTTON, | 
|  | IDLG_CCTRL_EDITBOX, | 
|  | IDLG_CCTRL_SEPARATOR, | 
|  | IDLG_CCTRL_TEXT | 
|  | }; | 
|  |  | 
|  | typedef struct { | 
|  | HWND hwnd, wrapper_hwnd; | 
|  | UINT id, dlgid; | 
|  | enum ITEMDLG_CCTRL_TYPE type; | 
|  | CDCONTROLSTATEF cdcstate; | 
|  | struct list entry; | 
|  | } customctrl; | 
|  |  | 
|  | 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; | 
|  | IOleWindow             IOleWindow_iface; | 
|  | IFileDialogCustomize   IFileDialogCustomize_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 default_ext; | 
|  | LPWSTR custom_title; | 
|  | LPWSTR custom_okbutton; | 
|  | LPWSTR custom_cancelbutton; | 
|  | LPWSTR custom_filenamelabel; | 
|  |  | 
|  | UINT cctrl_width, cctrl_def_height, cctrls_cols; | 
|  | HWND cctrls_hwnd; | 
|  | struct list cctrls; | 
|  | UINT_PTR cctrl_next_dlgid; | 
|  | } FileDialogImpl; | 
|  |  | 
|  | /************************************************************************** | 
|  | * Event wrappers. | 
|  | */ | 
|  | static HRESULT events_OnFileOk(FileDialogImpl *This) | 
|  | { | 
|  | events_client *cursor; | 
|  | HRESULT hr = S_OK; | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) | 
|  | { | 
|  | TRACE("Notifying %p\n", cursor); | 
|  | hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface); | 
|  | if(FAILED(hr) && hr != E_NOTIMPL) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if(hr == E_NOTIMPL) | 
|  | hr = S_OK; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder) | 
|  | { | 
|  | events_client *cursor; | 
|  | HRESULT hr = S_OK; | 
|  | TRACE("%p (%p)\n", This, folder); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) | 
|  | { | 
|  | TRACE("Notifying %p\n", cursor); | 
|  | hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder); | 
|  | if(FAILED(hr) && hr != E_NOTIMPL) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if(hr == E_NOTIMPL) | 
|  | hr = S_OK; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static void events_OnFolderChange(FileDialogImpl *This) | 
|  | { | 
|  | events_client *cursor; | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) | 
|  | { | 
|  | TRACE("Notifying %p\n", cursor); | 
|  | IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void events_OnSelectionChange(FileDialogImpl *This) | 
|  | { | 
|  | events_client *cursor; | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) | 
|  | { | 
|  | TRACE("Notifying %p\n", cursor); | 
|  | IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface); | 
|  | } | 
|  | } | 
|  |  | 
|  | static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce) | 
|  | { | 
|  | return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce); | 
|  | } | 
|  |  | 
|  | static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id) | 
|  | { | 
|  | events_client *cursor; | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) | 
|  | { | 
|  | IFileDialogControlEvents *pfdce; | 
|  | if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce))) | 
|  | { | 
|  | TRACE("Notifying %p\n", cursor); | 
|  | IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id); | 
|  | IFileDialogControlEvents_Release(pfdce); | 
|  | } | 
|  | } | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id) | 
|  | { | 
|  | events_client *cursor; | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) | 
|  | { | 
|  | IFileDialogControlEvents *pfdce; | 
|  | if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce))) | 
|  | { | 
|  | TRACE("Notifying %p\n", cursor); | 
|  | IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id); | 
|  | IFileDialogControlEvents_Release(pfdce); | 
|  | } | 
|  | } | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked) | 
|  | { | 
|  | events_client *cursor; | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) | 
|  | { | 
|  | IFileDialogControlEvents *pfdce; | 
|  | if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce))) | 
|  | { | 
|  | TRACE("Notifying %p\n", cursor); | 
|  | IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked); | 
|  | IFileDialogControlEvents_Release(pfdce); | 
|  | } | 
|  | } | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This, | 
|  | DWORD ctl_id) | 
|  | { | 
|  | events_client *cursor; | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry) | 
|  | { | 
|  | IFileDialogControlEvents *pfdce; | 
|  | if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce))) | 
|  | { | 
|  | TRACE("Notifying %p\n", cursor); | 
|  | IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id); | 
|  | IFileDialogControlEvents_Release(pfdce); | 
|  | } | 
|  | } | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * 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 LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec) | 
|  | { | 
|  | WCHAR *endpos, *ext; | 
|  |  | 
|  | lstrcpyW(buf, spec); | 
|  | if( (endpos = StrChrW(buf, ';')) ) | 
|  | *endpos = '\0'; | 
|  |  | 
|  | ext = PathFindExtensionW(buf); | 
|  | if(StrChrW(ext, '*')) | 
|  | return NULL; | 
|  |  | 
|  | return ext; | 
|  | } | 
|  |  | 
|  | 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 & ~FOS_FILEMUSTEXIST, | 
|  | (This->dlg_type == ITEMDLG_TYPE_SAVE), | 
|  | open_action); | 
|  |  | 
|  | /* Add the proper extension */ | 
|  | if(open_action == ONOPEN_OPEN) | 
|  | { | 
|  | static const WCHAR dotW[] = {'.',0}; | 
|  |  | 
|  | if(This->dlg_type == ITEMDLG_TYPE_SAVE) | 
|  | { | 
|  | WCHAR extbuf[MAX_PATH], *newext = NULL; | 
|  |  | 
|  | if(This->filterspec_count) | 
|  | { | 
|  | newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec); | 
|  | } | 
|  | else if(This->default_ext) | 
|  | { | 
|  | lstrcpyW(extbuf, dotW); | 
|  | lstrcatW(extbuf, This->default_ext); | 
|  | newext = extbuf; | 
|  | } | 
|  |  | 
|  | if(newext) | 
|  | { | 
|  | WCHAR *ext = PathFindExtensionW(canon_filename); | 
|  | if(lstrcmpW(ext, newext)) | 
|  | lstrcatW(canon_filename, newext); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) && | 
|  | !PathFileExistsW(canon_filename)) | 
|  | { | 
|  | if(This->default_ext) | 
|  | { | 
|  | lstrcatW(canon_filename, dotW); | 
|  | lstrcatW(canon_filename, This->default_ext); | 
|  |  | 
|  | if(!PathFileExistsW(canon_filename)) | 
|  | { | 
|  | FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING); | 
|  | open_action = ONOPEN_BROWSE; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING); | 
|  | open_action = ONOPEN_BROWSE; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename); | 
|  |  | 
|  | if(psf_parent && !(open_action == ONOPEN_BROWSE)) | 
|  | IShellFolder_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); | 
|  |  | 
|  | IShellFolder_Release(psf_parent); | 
|  | break; | 
|  |  | 
|  | case ONOPEN_OPEN: | 
|  | if(events_OnFileOk(This) != S_OK) | 
|  | break; | 
|  |  | 
|  | 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 inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid) | 
|  | { | 
|  | customctrl *ctrl; | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) | 
|  | if(ctrl->dlgid == dlgid) | 
|  | return ctrl; | 
|  |  | 
|  | ERR("Failed to find control with dialog id %d\n", dlgid); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid) | 
|  | { | 
|  | customctrl *ctrl; | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) | 
|  | if(ctrl->id == ctlid) | 
|  | return ctrl; | 
|  |  | 
|  | ERR("Failed to find control with control id %d\n", ctlid); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline) | 
|  | { | 
|  | LPWSTR text; | 
|  | UINT len, final_width; | 
|  | UINT lines, final_height; | 
|  | SIZE size; | 
|  | RECT rc; | 
|  | HDC hdc; | 
|  | WCHAR *c; | 
|  |  | 
|  | 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); | 
|  |  | 
|  | if(len && multiline) | 
|  | { | 
|  | /* FIXME: line-wrap */ | 
|  | for(lines = 1, c = text; *c != '\0'; c++) | 
|  | if(*c == '\n') lines++; | 
|  |  | 
|  | final_height = size.cy*lines + 2*4; | 
|  | } | 
|  | else | 
|  | { | 
|  | GetWindowRect(hctrl, &rc); | 
|  | final_height = rc.bottom - rc.top; | 
|  | } | 
|  |  | 
|  | final_width = min(max(size.cx, min_width) + 4, max_width); | 
|  | SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height, | 
|  | SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, text); | 
|  | } | 
|  |  | 
|  | static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl) | 
|  | { | 
|  | RECT rc; | 
|  |  | 
|  | switch(ctrl->type) | 
|  | { | 
|  | case IDLG_CCTRL_PUSHBUTTON: | 
|  | case IDLG_CCTRL_COMBOBOX: | 
|  | case IDLG_CCTRL_CHECKBUTTON: | 
|  | case IDLG_CCTRL_TEXT: | 
|  | ctrl_resize(ctrl->hwnd, 160, 160, TRUE); | 
|  | GetWindowRect(ctrl->hwnd, &rc); | 
|  | SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top, | 
|  | SWP_NOZORDER|SWP_NOMOVE|SWP_NOZORDER); | 
|  | break; | 
|  | case IDLG_CCTRL_RADIOBUTTONLIST: | 
|  | case IDLG_CCTRL_EDITBOX: | 
|  | case IDLG_CCTRL_SEPARATOR: | 
|  | case IDLG_CCTRL_MENU: | 
|  | /* Nothing */ | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs) | 
|  | { | 
|  | FileDialogImpl *This = crs->lpCreateParams; | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam) | 
|  | { | 
|  | customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam)); | 
|  |  | 
|  | TRACE("%p, %lx\n", This, wparam); | 
|  |  | 
|  | if(ctrl) | 
|  | { | 
|  | if(ctrl->type == IDLG_CCTRL_CHECKBUTTON) | 
|  | { | 
|  | BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED); | 
|  | cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked); | 
|  | } | 
|  | else | 
|  | cctrl_event_OnButtonClicked(This, ctrl->id); | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam) | 
|  | { | 
|  | customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam)); | 
|  | TRACE("%p, %p (%lx)\n", This, ctrl, wparam); | 
|  |  | 
|  | if(ctrl) | 
|  | { | 
|  | UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0); | 
|  | UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0); | 
|  |  | 
|  | cctrl_event_OnItemSelected(This, ctrl->id, selid); | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam) | 
|  | { | 
|  | NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam; | 
|  | customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom)); | 
|  | POINT pt = { 0, nmtb->rcButton.bottom }; | 
|  | TBBUTTON tbb; | 
|  | UINT idcmd; | 
|  |  | 
|  | TRACE("%p, %p (%lx)\n", This, ctrl, lparam); | 
|  |  | 
|  | if(ctrl) | 
|  | { | 
|  | cctrl_event_OnControlActivating(This,ctrl->id); | 
|  |  | 
|  | SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb); | 
|  | ClientToScreen(ctrl->hwnd, &pt); | 
|  | idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL); | 
|  | if(idcmd) | 
|  | cctrl_event_OnItemSelected(This, ctrl->id, idcmd); | 
|  | } | 
|  |  | 
|  | return TBDDRET_DEFAULT; | 
|  | } | 
|  |  | 
|  | static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam) | 
|  | { | 
|  | switch(HIWORD(wparam)) | 
|  | { | 
|  | case BN_CLICKED:          return notifysink_on_bn_clicked(This, hwnd, wparam); | 
|  | case CBN_SELCHANGE:       return notifysink_on_cbn_selchange(This, hwnd, wparam); | 
|  | } | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam) | 
|  | { | 
|  | NMHDR *nmhdr = (NMHDR*)lparam; | 
|  |  | 
|  | switch(nmhdr->code) | 
|  | { | 
|  | case TBN_DROPDOWN:        return notifysink_on_tvn_dropdown(This, lparam); | 
|  | } | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) | 
|  | { | 
|  | FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA); | 
|  | HWND hwnd_child; | 
|  | RECT rc; | 
|  |  | 
|  | switch(message) | 
|  | { | 
|  | case WM_NCCREATE:         return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam); | 
|  | case WM_COMMAND:          return notifysink_on_wm_command(This, hwnd, wparam, lparam); | 
|  | case WM_NOTIFY:           return notifysink_on_wm_notify(This, hwnd, wparam, lparam); | 
|  | case WM_SIZE: | 
|  | hwnd_child = GetPropW(hwnd, notifysink_childW); | 
|  | GetClientRect(hwnd, &rc); | 
|  | SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | return DefWindowProcW(hwnd, message, wparam, lparam); | 
|  | } | 
|  |  | 
|  | static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id, | 
|  | LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags, | 
|  | DWORD ctrl_exflags, UINT height, customctrl **ppctrl) | 
|  | { | 
|  | HWND ns_hwnd, control_hwnd; | 
|  | DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS; | 
|  | customctrl *ctrl; | 
|  |  | 
|  | if(get_cctrl(This, id)) | 
|  | return E_UNEXPECTED; /* Duplicate id */ | 
|  |  | 
|  | ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags, | 
|  | 0, 0, This->cctrl_width, height, This->cctrls_hwnd, | 
|  | (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This); | 
|  | control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags, | 
|  | 0, 0, This->cctrl_width, height, ns_hwnd, | 
|  | (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0); | 
|  |  | 
|  | if(!ns_hwnd || !control_hwnd) | 
|  | { | 
|  | ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd); | 
|  | DestroyWindow(ns_hwnd); | 
|  | DestroyWindow(control_hwnd); | 
|  |  | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | SetPropW(ns_hwnd, notifysink_childW, control_hwnd); | 
|  |  | 
|  | ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl)); | 
|  | if(!ctrl) | 
|  | return E_OUTOFMEMORY; | 
|  |  | 
|  | ctrl->hwnd = control_hwnd; | 
|  | ctrl->wrapper_hwnd = ns_hwnd; | 
|  | ctrl->id = id; | 
|  | ctrl->dlgid = This->cctrl_next_dlgid; | 
|  | ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE; | 
|  | list_add_tail(&This->cctrls, &ctrl->entry); | 
|  | if(ppctrl) *ppctrl = ctrl; | 
|  |  | 
|  | This->cctrl_next_dlgid++; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * Container functions. | 
|  | */ | 
|  | static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width) | 
|  | { | 
|  | UINT container_height; | 
|  | UINT column_width; | 
|  | UINT nr_of_cols; | 
|  | UINT max_control_height, total_height = 0; | 
|  | UINT cur_col_pos, cur_row_pos; | 
|  | customctrl *ctrl; | 
|  | BOOL fits_height; | 
|  | static const UINT col_indent = 100; /* The first column is indented 100px */ | 
|  | static const UINT cspacing = 90;    /* Columns are spaced with 90px */ | 
|  | static const UINT rspacing = 4;     /* Rows are spaced with 4 px. */ | 
|  |  | 
|  | /* Given the new width of the container, this function determines the | 
|  | * needed height of the container and places the controls according to | 
|  | * the new layout. Returns the new height. | 
|  | */ | 
|  |  | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | column_width = This->cctrl_width + cspacing; | 
|  | nr_of_cols = (container_width - col_indent + cspacing) / column_width; | 
|  |  | 
|  | /* We don't need to do anything unless the number of visible columns has changed. */ | 
|  | if(nr_of_cols == This->cctrls_cols) | 
|  | { | 
|  | RECT rc; | 
|  | GetWindowRect(This->cctrls_hwnd, &rc); | 
|  | return rc.bottom - rc.top; | 
|  | } | 
|  |  | 
|  | This->cctrls_cols = nr_of_cols; | 
|  |  | 
|  | /* Get the size of the tallest control, and the total size of | 
|  | * all the controls to figure out the number of slots we need. | 
|  | */ | 
|  | max_control_height = 0; | 
|  | LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) | 
|  | { | 
|  | if(ctrl->cdcstate & CDCS_VISIBLE) | 
|  | { | 
|  | RECT rc; | 
|  | UINT control_height; | 
|  | GetWindowRect(ctrl->wrapper_hwnd, &rc); | 
|  | control_height = rc.bottom - rc.top; | 
|  | max_control_height = max(max_control_height, control_height); | 
|  |  | 
|  | total_height +=  control_height + rspacing; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(!total_height) | 
|  | return 0; | 
|  |  | 
|  | container_height = max(total_height / nr_of_cols, max_control_height + rspacing); | 
|  | TRACE("Guess: container_height: %d\n",container_height); | 
|  |  | 
|  | /* Incrementally increase container_height until all the controls | 
|  | * fit. | 
|  | */ | 
|  | do { | 
|  | UINT columns_needed = 1; | 
|  | cur_row_pos = 0; | 
|  |  | 
|  | fits_height = TRUE; | 
|  | LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) | 
|  | { | 
|  | if(ctrl->cdcstate & CDCS_VISIBLE) | 
|  | { | 
|  | RECT rc; | 
|  | UINT control_height; | 
|  | GetWindowRect(ctrl->wrapper_hwnd, &rc); | 
|  | control_height = rc.bottom - rc.top; | 
|  |  | 
|  | if(cur_row_pos + control_height > container_height) | 
|  | { | 
|  | if(++columns_needed > nr_of_cols) | 
|  | { | 
|  | container_height += 1; | 
|  | fits_height = FALSE; | 
|  | break; | 
|  | } | 
|  | cur_row_pos = 0; | 
|  | } | 
|  |  | 
|  | cur_row_pos += control_height + rspacing; | 
|  | } | 
|  | } | 
|  | } while(!fits_height); | 
|  |  | 
|  | TRACE("Final container height: %d\n", container_height); | 
|  |  | 
|  | /* Move the controls to their final destination | 
|  | */ | 
|  | cur_col_pos = col_indent, cur_row_pos = 0; | 
|  | LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) | 
|  | { | 
|  | if(ctrl->cdcstate & CDCS_VISIBLE) | 
|  | { | 
|  | RECT rc; | 
|  | UINT control_height; | 
|  | GetWindowRect(ctrl->wrapper_hwnd, &rc); | 
|  | control_height = rc.bottom - rc.top; | 
|  |  | 
|  | if(cur_row_pos + control_height > container_height) | 
|  | { | 
|  | cur_row_pos = 0; | 
|  | cur_col_pos += This->cctrl_width + cspacing; | 
|  | } | 
|  |  | 
|  | SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos, cur_row_pos, 0, 0, | 
|  | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); | 
|  |  | 
|  | cur_row_pos += control_height + rspacing; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Sanity check */ | 
|  | if(cur_row_pos + This->cctrl_width > container_width) | 
|  | ERR("-- Failed to place controls properly.\n"); | 
|  |  | 
|  | return container_height; | 
|  | } | 
|  |  | 
|  | static void ctrl_container_reparent(FileDialogImpl *This, HWND parent) | 
|  | { | 
|  | LONG wndstyle; | 
|  |  | 
|  | if(parent) | 
|  | { | 
|  | customctrl *ctrl; | 
|  | HFONT font; | 
|  |  | 
|  | wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE); | 
|  | wndstyle &= ~(WS_POPUP); | 
|  | wndstyle |= WS_CHILD; | 
|  | SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle); | 
|  |  | 
|  | SetParent(This->cctrls_hwnd, parent); | 
|  | ShowWindow(This->cctrls_hwnd, TRUE); | 
|  |  | 
|  | /* Set the fonts to match the dialog font. */ | 
|  | font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0); | 
|  | if(!font) | 
|  | ERR("Failed to get font handle from dialog.\n"); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry) | 
|  | { | 
|  | if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE); | 
|  | customctrl_resize(This, ctrl); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | ShowWindow(This->cctrls_hwnd, FALSE); | 
|  |  | 
|  | wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE); | 
|  | wndstyle &= ~(WS_CHILD); | 
|  | wndstyle |= WS_POPUP; | 
|  | SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle); | 
|  |  | 
|  | SetParent(This->cctrls_hwnd, NULL); | 
|  | } | 
|  | } | 
|  |  | 
|  | static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs) | 
|  | { | 
|  | FileDialogImpl *This = crs->lpCreateParams; | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This) | 
|  | { | 
|  | customctrl *cur1, *cur2; | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry) | 
|  | { | 
|  | TRACE("Freeing control %p\n", cur1); | 
|  | list_remove(&cur1->entry); | 
|  |  | 
|  | if(cur1->type == IDLG_CCTRL_MENU) | 
|  | { | 
|  | TBBUTTON tbb; | 
|  | SendMessageW(cur1->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb); | 
|  | DestroyMenu((HMENU)tbb.dwData); | 
|  | } | 
|  |  | 
|  | DestroyWindow(cur1->hwnd); | 
|  | HeapFree(GetProcessHeap(), 0, cur1); | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam) | 
|  | { | 
|  | FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA); | 
|  |  | 
|  | switch(umessage) | 
|  | { | 
|  | case WM_NCCREATE:         return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam); | 
|  | case WM_DESTROY:          return ctrl_container_on_wm_destroy(This); | 
|  | default:                  return DefWindowProcW(hwnd, umessage, wparam, lparam); | 
|  | } | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | static HRESULT init_custom_controls(FileDialogImpl *This) | 
|  | { | 
|  | WNDCLASSW wc; | 
|  | static const WCHAR ctrl_container_classname[] = | 
|  | {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0}; | 
|  |  | 
|  | InitCommonControlsEx(NULL); | 
|  |  | 
|  | This->cctrl_width = 160;      /* Controls have a fixed width */ | 
|  | This->cctrl_def_height = 23; | 
|  | This->cctrls_cols = 0; | 
|  |  | 
|  | This->cctrl_next_dlgid = 0x2000; | 
|  | list_init(&This->cctrls); | 
|  |  | 
|  | if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) ) | 
|  | { | 
|  | wc.style            = CS_HREDRAW | CS_VREDRAW; | 
|  | wc.lpfnWndProc      = ctrl_container_wndproc; | 
|  | wc.cbClsExtra       = 0; | 
|  | wc.cbWndExtra       = 0; | 
|  | wc.hInstance        = COMDLG32_hInstance; | 
|  | wc.hIcon            = 0; | 
|  | wc.hCursor          = LoadCursorW(0, (LPWSTR)IDC_ARROW); | 
|  | wc.hbrBackground    = (HBRUSH)(COLOR_BTNFACE + 1); | 
|  | wc.lpszMenuName     = NULL; | 
|  | wc.lpszClassName    = ctrl_container_classname; | 
|  |  | 
|  | if(!RegisterClassW(&wc)) return E_FAIL; | 
|  | } | 
|  |  | 
|  | This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL, | 
|  | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, | 
|  | 0, 0, 0, 0, NULL, 0, | 
|  | COMDLG32_hInstance, (void*)This); | 
|  | if(!This->cctrls_hwnd) | 
|  | return E_FAIL; | 
|  |  | 
|  | SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP); | 
|  |  | 
|  | /* Register class for  */ | 
|  | if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) || | 
|  | wc.hInstance != COMDLG32_hInstance) | 
|  | { | 
|  | wc.style            = CS_HREDRAW | CS_VREDRAW; | 
|  | wc.lpfnWndProc      = notifysink_proc; | 
|  | wc.cbClsExtra       = 0; | 
|  | wc.cbWndExtra       = 0; | 
|  | wc.hInstance        = COMDLG32_hInstance; | 
|  | wc.hIcon            = 0; | 
|  | wc.hCursor          = LoadCursorW(0, (LPWSTR)IDC_ARROW); | 
|  | wc.hbrBackground    = (HBRUSH)(COLOR_BTNFACE + 1); | 
|  | wc.lpszMenuName     = NULL; | 
|  | wc.lpszClassName    = floatnotifysinkW; | 
|  |  | 
|  | if (!RegisterClassW(&wc)) | 
|  | ERR("Failed to register FloatNotifySink window class.\n"); | 
|  | } | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * 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, customctrls_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 custom controls */ | 
|  | customctrls_rc.left = dialog_rc.left + vspacing; | 
|  | customctrls_rc.right = dialog_rc.right - vspacing; | 
|  | customctrls_rc.bottom = filename_rc.top - hspacing; | 
|  | customctrls_rc.top = customctrls_rc.bottom - | 
|  | ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left); | 
|  |  | 
|  | /* 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 = customctrls_rc.top - hspacing; | 
|  |  | 
|  | /**** | 
|  | * Move everything to the right place. | 
|  | */ | 
|  |  | 
|  | /* FIXME: The Save Dialog uses a slightly different layout. */ | 
|  | hdwp = BeginDeferWindowPos(7); | 
|  |  | 
|  | if(hdwp && This->peb) | 
|  | IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc); | 
|  |  | 
|  | if(hdwp && This->cctrls_hwnd) | 
|  | DeferWindowPos(hdwp, This->cctrls_hwnd, NULL, | 
|  | customctrls_rc.left, customctrls_rc.top, | 
|  | customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top, | 
|  | SWP_NOZORDER | SWP_NOACTIVATE); | 
|  |  | 
|  | /* 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, FALSE); | 
|  | } | 
|  |  | 
|  | if(This->custom_cancelbutton && | 
|  | (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL))) | 
|  | { | 
|  | SetWindowTextW(hitem, This->custom_cancelbutton); | 
|  | ctrl_resize(hitem, 50, 250, FALSE); | 
|  | } | 
|  |  | 
|  | if(This->custom_filenamelabel && | 
|  | (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC))) | 
|  | { | 
|  | SetWindowTextW(hitem, This->custom_filenamelabel); | 
|  | ctrl_resize(hitem, 50, 250, FALSE); | 
|  | } | 
|  | } | 
|  |  | 
|  | 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); | 
|  |  | 
|  | ctrl_container_reparent(This, This->dlg_hwnd); | 
|  | 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; | 
|  | } | 
|  |  | 
|  | ctrl_container_reparent(This, 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; | 
|  | LPWSTR filename; | 
|  | UINT prev_index = This->filetypeindex; | 
|  |  | 
|  | This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0); | 
|  | TRACE("File type selection changed to %d.\n", This->filetypeindex); | 
|  |  | 
|  | if(prev_index == This->filetypeindex) | 
|  | return FALSE; | 
|  |  | 
|  | hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv); | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | IShellView_Refresh(psv); | 
|  | IShellView_Release(psv); | 
|  | } | 
|  |  | 
|  | if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename)) | 
|  | { | 
|  | WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext; | 
|  |  | 
|  | ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec); | 
|  | if(ext) | 
|  | { | 
|  | lstrcpyW(buf, filename); | 
|  |  | 
|  | if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec)) | 
|  | PathRemoveExtensionW(buf); | 
|  |  | 
|  | lstrcatW(buf, ext); | 
|  | set_file_name(This, buf); | 
|  | } | 
|  | CoTaskMemFree(filename); | 
|  | } | 
|  | } | 
|  |  | 
|  | 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 if(IsEqualGUID(&IID_IOleWindow, riid)) | 
|  | { | 
|  | *ppvObject = &This->IOleWindow_iface; | 
|  | } | 
|  | else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) || | 
|  | IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt)) | 
|  | { | 
|  | *ppvObject = &This->IFileDialogCustomize_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); | 
|  |  | 
|  | DestroyWindow(This->cctrls_hwnd); | 
|  |  | 
|  | 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->default_ext); | 
|  | 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 (%s)\n", iface, debugstr_w(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 (%s)\n", This, debugstr_w(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 (%s)\n", This, debugstr_w(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 (%s)\n", This, debugstr_w(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); | 
|  | TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension)); | 
|  |  | 
|  | LocalFree(This->default_ext); | 
|  | This->default_ext = StrDupW(pszDefaultExtension); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | 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 (%s)\n", This, debugstr_w(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); | 
|  | IShellItem *psi; | 
|  | HRESULT hr; | 
|  | TRACE("%p (%p)\n", This, pidlFolder); | 
|  |  | 
|  | hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi); | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | hr = events_OnFolderChanging(This, psi); | 
|  | IShellItem_Release(psi); | 
|  |  | 
|  | /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */ | 
|  | if(hr == S_FALSE) | 
|  | hr = E_FAIL; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  | else | 
|  | ERR("Failed to convert pidl (%p) to a shellitem.\n", 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; | 
|  | } | 
|  |  | 
|  | events_OnFolderChange(This); | 
|  |  | 
|  | 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)); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | 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); | 
|  | events_OnSelectionChange(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 | 
|  | }; | 
|  |  | 
|  | /************************************************************************** | 
|  | * IOleWindow implementation | 
|  | */ | 
|  | static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface) | 
|  | { | 
|  | return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IOleWindow(iface); | 
|  | return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IOleWindow(iface); | 
|  | return IFileDialog2_AddRef(&This->IFileDialog2_iface); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IOleWindow(iface); | 
|  | return IFileDialog2_Release(&This->IFileDialog2_iface); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IOleWindow(iface); | 
|  | FIXME("Stub: %p (%d)\n", This, fEnterMOde); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IOleWindow(iface); | 
|  | TRACE("%p (%p)\n", This, phwnd); | 
|  | *phwnd = This->dlg_hwnd; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static const IOleWindowVtbl vt_IOleWindow = { | 
|  | IOleWindow_fnQueryInterface, | 
|  | IOleWindow_fnAddRef, | 
|  | IOleWindow_fnRelease, | 
|  | IOleWindow_fnGetWindow, | 
|  | IOleWindow_fnContextSensitiveHelp | 
|  | }; | 
|  |  | 
|  | /************************************************************************** | 
|  | * IFileDialogCustomize implementation | 
|  | */ | 
|  | static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface) | 
|  | { | 
|  | return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface, | 
|  | REFIID riid, void **ppvObject) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | return IFileDialog2_AddRef(&This->IFileDialog2_iface); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | return IFileDialog2_Release(&This->IFileDialog2_iface); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | FIXME("stub - %p (%d)\n", This, dwIDCtl); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | LPCWSTR pszLabel) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl; | 
|  | TBBUTTON tbb; | 
|  | HRESULT hr; | 
|  | TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel); | 
|  |  | 
|  | hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW, | 
|  | TBSTYLE_FLAT | CCS_NODIVIDER, 0, | 
|  | This->cctrl_def_height, &ctrl); | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0); | 
|  | ctrl->type = IDLG_CCTRL_MENU; | 
|  |  | 
|  | /* Add the actual button with a popup menu. */ | 
|  | tbb.iBitmap = I_IMAGENONE; | 
|  | tbb.dwData = (DWORD_PTR)CreatePopupMenu(); | 
|  | tbb.iString = (DWORD_PTR)pszLabel; | 
|  | tbb.fsState = TBSTATE_ENABLED; | 
|  | tbb.fsStyle = BTNS_WHOLEDROPDOWN; | 
|  | tbb.idCommand = 1; | 
|  |  | 
|  | SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb); | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | LPCWSTR pszLabel) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl; | 
|  | HRESULT hr; | 
|  | TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel); | 
|  |  | 
|  | hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0, | 
|  | This->cctrl_def_height, &ctrl); | 
|  | if(SUCCEEDED(hr)) | 
|  | ctrl->type = IDLG_CCTRL_PUSHBUTTON; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl; | 
|  | HRESULT hr; | 
|  | TRACE("%p (%d)\n", This, dwIDCtl); | 
|  |  | 
|  | hr =  cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0, | 
|  | This->cctrl_def_height, &ctrl); | 
|  | if(SUCCEEDED(hr)) | 
|  | ctrl->type = IDLG_CCTRL_COMBOBOX; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | FIXME("stub - %p (%d)\n", This, dwIDCtl); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | LPCWSTR pszLabel, | 
|  | BOOL bChecked) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl; | 
|  | HRESULT hr; | 
|  | TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked); | 
|  |  | 
|  | hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX, 0, | 
|  | This->cctrl_def_height, &ctrl); | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | ctrl->type = IDLG_CCTRL_CHECKBUTTON; | 
|  | SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0); | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | LPCWSTR pszText) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl; | 
|  | HRESULT hr; | 
|  | TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText); | 
|  |  | 
|  | hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE, | 
|  | This->cctrl_def_height, &ctrl); | 
|  | if(SUCCEEDED(hr)) | 
|  | ctrl->type = IDLG_CCTRL_EDITBOX; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl; | 
|  | HRESULT hr; | 
|  | TRACE("%p (%d)\n", This, dwIDCtl); | 
|  |  | 
|  | hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0, | 
|  | GetSystemMetrics(SM_CYEDGE), &ctrl); | 
|  | if(SUCCEEDED(hr)) | 
|  | ctrl->type = IDLG_CCTRL_SEPARATOR; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | LPCWSTR pszText) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl; | 
|  | HRESULT hr; | 
|  | TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText); | 
|  |  | 
|  | hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0, | 
|  | This->cctrl_def_height, &ctrl); | 
|  | if(SUCCEEDED(hr)) | 
|  | ctrl->type = IDLG_CCTRL_TEXT; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | LPCWSTR pszLabel) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl = get_cctrl(This, dwIDCtl); | 
|  | TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel); | 
|  |  | 
|  | if(!ctrl) return E_INVALIDARG; | 
|  |  | 
|  | switch(ctrl->type) | 
|  | { | 
|  | case IDLG_CCTRL_MENU: | 
|  | case IDLG_CCTRL_PUSHBUTTON: | 
|  | case IDLG_CCTRL_CHECKBUTTON: | 
|  | case IDLG_CCTRL_TEXT: | 
|  | SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | CDCONTROLSTATEF *pdwState) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl = get_cctrl(This, dwIDCtl); | 
|  | TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState); | 
|  |  | 
|  | if(!ctrl) return E_NOTIMPL; | 
|  |  | 
|  | *pdwState = ctrl->cdcstate; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | CDCONTROLSTATEF dwState) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl = get_cctrl(This,dwIDCtl); | 
|  | TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState); | 
|  |  | 
|  | if(ctrl) | 
|  | { | 
|  | LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE); | 
|  |  | 
|  | if(dwState & CDCS_ENABLED) | 
|  | wndstyle &= ~(WS_DISABLED); | 
|  | else | 
|  | wndstyle |= WS_DISABLED; | 
|  |  | 
|  | if(dwState & CDCS_VISIBLE) | 
|  | wndstyle |= WS_VISIBLE; | 
|  | else | 
|  | wndstyle &= ~(WS_VISIBLE); | 
|  |  | 
|  | SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle); | 
|  |  | 
|  | /* We save the state separately since at least one application | 
|  | * relies on being able to hide a control. */ | 
|  | ctrl->cdcstate = dwState; | 
|  | } | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | WCHAR **ppszText) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl = get_cctrl(This, dwIDCtl); | 
|  | WCHAR len, *text; | 
|  | TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText); | 
|  |  | 
|  | if(!ctrl || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0))) | 
|  | return E_FAIL; | 
|  |  | 
|  | text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1)); | 
|  | if(!text) return E_FAIL; | 
|  |  | 
|  | SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text); | 
|  | *ppszText = text; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | LPCWSTR pszText) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl = get_cctrl(This, dwIDCtl); | 
|  | TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText)); | 
|  |  | 
|  | if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX) | 
|  | return E_FAIL; | 
|  |  | 
|  | SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | BOOL *pbChecked) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl = get_cctrl(This, dwIDCtl); | 
|  | TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked); | 
|  |  | 
|  | if(ctrl) | 
|  | *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | BOOL bChecked) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl = get_cctrl(This, dwIDCtl); | 
|  | TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked); | 
|  |  | 
|  | if(ctrl) | 
|  | SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem) | 
|  | { | 
|  | UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0); | 
|  | UINT i; | 
|  | if(!count || (count == CB_ERR)) | 
|  | return -1; | 
|  |  | 
|  | for(i = 0; i < count; i++) | 
|  | if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem) | 
|  | return i; | 
|  |  | 
|  | TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | DWORD dwIDItem, | 
|  | LPCWSTR pszLabel) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl = get_cctrl(This, dwIDCtl); | 
|  | TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel)); | 
|  |  | 
|  | if(!ctrl) return E_FAIL; | 
|  |  | 
|  | switch(ctrl->type) | 
|  | { | 
|  | case IDLG_CCTRL_COMBOBOX: | 
|  | { | 
|  | UINT index; | 
|  |  | 
|  | if(get_combobox_index_from_id(ctrl->hwnd, dwIDItem) != -1) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel); | 
|  | SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  | case IDLG_CCTRL_MENU: | 
|  | { | 
|  | TBBUTTON tbb; | 
|  | SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb); | 
|  |  | 
|  | if(GetMenuState((HMENU)tbb.dwData, dwIDItem, MF_BYCOMMAND) != -1) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | AppendMenuW((HMENU)tbb.dwData, MF_STRING, dwIDItem, pszLabel); | 
|  | return S_OK; | 
|  | } | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | return E_NOINTERFACE; /* win7 */ | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | DWORD dwIDItem) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl = get_cctrl(This, dwIDCtl); | 
|  | TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem); | 
|  |  | 
|  | if(!ctrl) return E_FAIL; | 
|  |  | 
|  | switch(ctrl->type) | 
|  | { | 
|  | case IDLG_CCTRL_COMBOBOX: | 
|  | { | 
|  | UINT i, count = SendMessageW(ctrl->hwnd, CB_GETCOUNT, 0, 0); | 
|  | if(!count || (count == CB_ERR)) | 
|  | return E_FAIL; | 
|  |  | 
|  | for(i = 0; i < count; i++) | 
|  | if(SendMessageW(ctrl->hwnd, CB_GETITEMDATA, i, 0) == dwIDItem) | 
|  | { | 
|  | if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, i, 0) == CB_ERR) | 
|  | return E_FAIL; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | return E_UNEXPECTED; | 
|  | } | 
|  | case IDLG_CCTRL_MENU: | 
|  | { | 
|  | TBBUTTON tbb; | 
|  | HMENU hmenu; | 
|  | SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb); | 
|  | hmenu = (HMENU)tbb.dwData; | 
|  |  | 
|  | if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND)) | 
|  | return E_UNEXPECTED; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | TRACE("%p (%d)\n", This, dwIDCtl); | 
|  |  | 
|  | /* Not implemented by native */ | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | DWORD dwIDItem, | 
|  | CDCONTROLSTATEF *pdwState) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | FIXME("stub - %p\n", This); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | DWORD dwIDItem, | 
|  | CDCONTROLSTATEF dwState) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | FIXME("stub - %p\n", This); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | DWORD *pdwIDItem) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl = get_cctrl(This, dwIDCtl); | 
|  | TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem); | 
|  |  | 
|  | if(!ctrl) return E_FAIL; | 
|  |  | 
|  | switch(ctrl->type) | 
|  | { | 
|  | case IDLG_CCTRL_COMBOBOX: | 
|  | { | 
|  | UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0); | 
|  | if(index == CB_ERR) | 
|  | return E_FAIL; | 
|  |  | 
|  | *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0); | 
|  | return S_OK; | 
|  | } | 
|  | default: | 
|  | FIXME("Unsupported control type %d\n", ctrl->type); | 
|  | } | 
|  |  | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | DWORD dwIDItem) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | customctrl *ctrl = get_cctrl(This, dwIDCtl); | 
|  | TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem); | 
|  |  | 
|  | if(!ctrl) return E_INVALIDARG; | 
|  |  | 
|  | switch(ctrl->type) | 
|  | { | 
|  | case IDLG_CCTRL_COMBOBOX: | 
|  | { | 
|  | UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem); | 
|  |  | 
|  | if(index == -1) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR) | 
|  | return E_FAIL; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  | default: | 
|  | FIXME("Unsupported control type %d\n", ctrl->type); | 
|  | } | 
|  |  | 
|  | return E_INVALIDARG; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | LPCWSTR pszLabel) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | FIXME("stub - %p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel)); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | FIXME("stub - %p\n", This); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | FIXME("stub - %p (%d)\n", This, dwIDCtl); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface, | 
|  | DWORD dwIDCtl, | 
|  | DWORD dwIDItem, | 
|  | LPCWSTR pszLabel) | 
|  | { | 
|  | FileDialogImpl *This = impl_from_IFileDialogCustomize(iface); | 
|  | FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel)); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = { | 
|  | IFileDialogCustomize_fnQueryInterface, | 
|  | IFileDialogCustomize_fnAddRef, | 
|  | IFileDialogCustomize_fnRelease, | 
|  | IFileDialogCustomize_fnEnableOpenDropDown, | 
|  | IFileDialogCustomize_fnAddMenu, | 
|  | IFileDialogCustomize_fnAddPushButton, | 
|  | IFileDialogCustomize_fnAddComboBox, | 
|  | IFileDialogCustomize_fnAddRadioButtonList, | 
|  | IFileDialogCustomize_fnAddCheckButton, | 
|  | IFileDialogCustomize_fnAddEditBox, | 
|  | IFileDialogCustomize_fnAddSeparator, | 
|  | IFileDialogCustomize_fnAddText, | 
|  | IFileDialogCustomize_fnSetControlLabel, | 
|  | IFileDialogCustomize_fnGetControlState, | 
|  | IFileDialogCustomize_fnSetControlState, | 
|  | IFileDialogCustomize_fnGetEditBoxText, | 
|  | IFileDialogCustomize_fnSetEditBoxText, | 
|  | IFileDialogCustomize_fnGetCheckButtonState, | 
|  | IFileDialogCustomize_fnSetCheckButtonState, | 
|  | IFileDialogCustomize_fnAddControlItem, | 
|  | IFileDialogCustomize_fnRemoveControlItem, | 
|  | IFileDialogCustomize_fnRemoveAllControlItems, | 
|  | IFileDialogCustomize_fnGetControlItemState, | 
|  | IFileDialogCustomize_fnSetControlItemState, | 
|  | IFileDialogCustomize_fnGetSelectedControlItem, | 
|  | IFileDialogCustomize_fnSetSelectedControlItem, | 
|  | IFileDialogCustomize_fnStartVisualGroup, | 
|  | IFileDialogCustomize_fnEndVisualGroup, | 
|  | IFileDialogCustomize_fnMakeProminent, | 
|  | IFileDialogCustomize_fnSetControlItemText | 
|  | }; | 
|  |  | 
|  | 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; | 
|  | fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow; | 
|  | fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize; | 
|  |  | 
|  | 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->default_ext = 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 = init_custom_controls(fdimpl); | 
|  | if(FAILED(hr)) | 
|  | { | 
|  | ERR("Failed to initialize custom controls (0x%08x).\n", hr); | 
|  | IUnknown_Release((IUnknown*)fdimpl); | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | 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); | 
|  | } |