winex11: Ignore X11 errors happening on the clipboard display connection.
[wine.git] / dlls / comdlg32 / itemdlg.c
blob8c2b9bc6965cb4f04c351e2c53ff1c3a3d918c11
1 /*
2 * Common Item Dialog
4 * Copyright 2010,2011 David Hedberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "wingdi.h"
30 #include "winreg.h"
31 #include "shlwapi.h"
33 #include "commdlg.h"
34 #include "cdlg.h"
35 #include "filedlgbrowser.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
40 #define IDC_NAV_TOOLBAR 200
41 #define IDC_NAVBACK 201
42 #define IDC_NAVFORWARD 202
44 #include <initguid.h>
45 /* This seems to be another version of IID_IFileDialogCustomize. If
46 * there is any difference I have yet to find it. */
47 DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F);
49 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
51 static const WCHAR notifysink_childW[] = {'n','f','s','_','c','h','i','l','d',0};
52 static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0};
53 static const WCHAR radiobuttonlistW[] = {'R','a','d','i','o','B','u','t','t','o','n','L','i','s','t',0};
55 enum ITEMDLG_TYPE {
56 ITEMDLG_TYPE_OPEN,
57 ITEMDLG_TYPE_SAVE
60 enum ITEMDLG_CCTRL_TYPE {
61 IDLG_CCTRL_MENU,
62 IDLG_CCTRL_PUSHBUTTON,
63 IDLG_CCTRL_COMBOBOX,
64 IDLG_CCTRL_RADIOBUTTONLIST,
65 IDLG_CCTRL_CHECKBUTTON,
66 IDLG_CCTRL_EDITBOX,
67 IDLG_CCTRL_SEPARATOR,
68 IDLG_CCTRL_TEXT,
69 IDLG_CCTRL_OPENDROPDOWN,
70 IDLG_CCTRL_VISUALGROUP
73 typedef struct cctrl_item {
74 DWORD id, parent_id;
75 LPWSTR label;
76 CDCONTROLSTATEF cdcstate;
77 HWND hwnd;
78 struct list entry;
79 } cctrl_item;
81 typedef struct {
82 HWND hwnd, wrapper_hwnd;
83 UINT id, dlgid;
84 enum ITEMDLG_CCTRL_TYPE type;
85 CDCONTROLSTATEF cdcstate;
86 struct list entry;
88 struct list sub_cctrls;
89 struct list sub_cctrls_entry;
90 struct list sub_items;
91 } customctrl;
93 typedef struct {
94 struct list entry;
95 IFileDialogEvents *pfde;
96 DWORD cookie;
97 } events_client;
99 typedef struct FileDialogImpl {
100 IFileDialog2 IFileDialog2_iface;
101 union {
102 IFileOpenDialog IFileOpenDialog_iface;
103 IFileSaveDialog IFileSaveDialog_iface;
104 } u;
105 enum ITEMDLG_TYPE dlg_type;
106 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
107 IServiceProvider IServiceProvider_iface;
108 ICommDlgBrowser3 ICommDlgBrowser3_iface;
109 IOleWindow IOleWindow_iface;
110 IFileDialogCustomize IFileDialogCustomize_iface;
111 LONG ref;
113 FILEOPENDIALOGOPTIONS options;
114 COMDLG_FILTERSPEC *filterspecs;
115 UINT filterspec_count;
116 UINT filetypeindex;
118 struct list events_clients;
119 DWORD events_next_cookie;
121 IShellItemArray *psia_selection;
122 IShellItemArray *psia_results;
123 IShellItem *psi_defaultfolder;
124 IShellItem *psi_setfolder;
125 IShellItem *psi_folder;
127 HWND dlg_hwnd;
128 IExplorerBrowser *peb;
129 DWORD ebevents_cookie;
131 LPWSTR set_filename;
132 LPWSTR default_ext;
133 LPWSTR custom_title;
134 LPWSTR custom_okbutton;
135 LPWSTR custom_cancelbutton;
136 LPWSTR custom_filenamelabel;
138 UINT cctrl_width, cctrl_def_height, cctrls_cols;
139 UINT cctrl_indent;
140 HWND cctrls_hwnd;
141 struct list cctrls;
142 UINT_PTR cctrl_next_dlgid;
143 customctrl *cctrl_active_vg;
145 HMENU hmenu_opendropdown;
146 customctrl cctrl_opendropdown;
147 HFONT hfont_opendropdown;
148 BOOL opendropdown_has_selection;
149 DWORD opendropdown_selection;
151 GUID client_guid;
152 } FileDialogImpl;
154 /**************************************************************************
155 * Event wrappers.
157 static HRESULT events_OnFileOk(FileDialogImpl *This)
159 events_client *cursor;
160 HRESULT hr = S_OK;
161 TRACE("%p\n", This);
163 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
165 TRACE("Notifying %p\n", cursor);
166 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
167 if(FAILED(hr) && hr != E_NOTIMPL)
168 break;
171 if(hr == E_NOTIMPL)
172 hr = S_OK;
174 return hr;
177 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
179 events_client *cursor;
180 HRESULT hr = S_OK;
181 TRACE("%p (%p)\n", This, folder);
183 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
185 TRACE("Notifying %p\n", cursor);
186 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
187 if(FAILED(hr) && hr != E_NOTIMPL)
188 break;
191 if(hr == E_NOTIMPL)
192 hr = S_OK;
194 return hr;
197 static void events_OnFolderChange(FileDialogImpl *This)
199 events_client *cursor;
200 TRACE("%p\n", This);
202 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
204 TRACE("Notifying %p\n", cursor);
205 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
209 static void events_OnSelectionChange(FileDialogImpl *This)
211 events_client *cursor;
212 TRACE("%p\n", This);
214 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
216 TRACE("Notifying %p\n", cursor);
217 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
221 static void events_OnTypeChange(FileDialogImpl *This)
223 events_client *cursor;
224 TRACE("%p\n", This);
226 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
228 TRACE("Notifying %p\n", cursor);
229 IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
233 static HRESULT events_OnOverwrite(FileDialogImpl *This, IShellItem *shellitem)
235 events_client *cursor;
236 HRESULT hr = S_OK;
237 FDE_OVERWRITE_RESPONSE response = FDEOR_DEFAULT;
238 TRACE("%p %p\n", This, shellitem);
240 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
242 TRACE("Notifying %p\n", cursor);
243 hr = IFileDialogEvents_OnOverwrite(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, shellitem, &response);
244 TRACE("<-- hr=%x response=%u\n", hr, response);
245 if(FAILED(hr) && hr != E_NOTIMPL)
246 break;
249 if(hr == E_NOTIMPL)
250 hr = S_OK;
252 if(SUCCEEDED(hr))
254 if (response == FDEOR_DEFAULT)
256 WCHAR buf[100];
257 int answer;
259 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, buf, 100);
260 answer = MessageBoxW(This->dlg_hwnd, buf, This->custom_title,
261 MB_YESNO | MB_ICONEXCLAMATION);
262 if (answer == IDNO || answer == IDCANCEL)
264 hr = E_FAIL;
267 else if (response == FDEOR_REFUSE)
268 hr = E_FAIL;
271 return hr;
274 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
276 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
279 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
281 events_client *cursor;
282 TRACE("%p\n", This);
284 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
286 IFileDialogControlEvents *pfdce;
287 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
289 TRACE("Notifying %p\n", cursor);
290 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
291 IFileDialogControlEvents_Release(pfdce);
295 return S_OK;
298 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
300 events_client *cursor;
301 TRACE("%p %i %i\n", This, ctl_id, item_id);
303 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
305 IFileDialogControlEvents *pfdce;
306 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
308 TRACE("Notifying %p\n", cursor);
309 IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
310 IFileDialogControlEvents_Release(pfdce);
314 return S_OK;
317 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
319 events_client *cursor;
320 TRACE("%p\n", This);
322 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
324 IFileDialogControlEvents *pfdce;
325 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
327 TRACE("Notifying %p\n", cursor);
328 IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
329 IFileDialogControlEvents_Release(pfdce);
333 return S_OK;
336 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
337 DWORD ctl_id)
339 events_client *cursor;
340 TRACE("%p\n", This);
342 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
344 IFileDialogControlEvents *pfdce;
345 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
347 TRACE("Notifying %p\n", cursor);
348 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
349 IFileDialogControlEvents_Release(pfdce);
353 return S_OK;
356 /**************************************************************************
357 * Helper functions.
359 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
361 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
362 UINT len;
364 if(!hwnd_edit)
366 if(This->set_filename)
368 len = lstrlenW(This->set_filename);
369 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
370 lstrcpyW(*str, This->set_filename);
371 return len;
373 return 0;
376 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
377 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
378 if(!*str)
379 return 0;
381 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
382 return len;
385 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
387 if(This->set_filename)
388 LocalFree(This->set_filename);
390 This->set_filename = str ? StrDupW(str) : NULL;
392 return SetDlgItemTextW(This->dlg_hwnd, IDC_FILENAME, This->set_filename);
395 static void fill_filename_from_selection(FileDialogImpl *This)
397 IShellItem *psi;
398 LPWSTR *names;
399 HRESULT hr;
400 UINT item_count, valid_count;
401 UINT len_total, i;
403 if(!This->psia_selection)
404 return;
406 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
407 if(FAILED(hr) || !item_count)
408 return;
410 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
412 /* Get names of the selected items */
413 valid_count = 0; len_total = 0;
414 for(i = 0; i < item_count; i++)
416 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
417 if(SUCCEEDED(hr))
419 UINT attr;
421 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
422 if(SUCCEEDED(hr) &&
423 (( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
424 (!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
425 continue;
427 hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
428 if(SUCCEEDED(hr))
430 len_total += lstrlenW(names[valid_count]) + 3;
431 valid_count++;
433 IShellItem_Release(psi);
437 if(valid_count == 1)
439 set_file_name(This, names[0]);
440 CoTaskMemFree(names[0]);
442 else if(valid_count > 1)
444 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
445 LPWSTR cur_point = string;
447 for(i = 0; i < valid_count; i++)
449 LPWSTR file = names[i];
450 *cur_point++ = '\"';
451 lstrcpyW(cur_point, file);
452 cur_point += lstrlenW(file);
453 *cur_point++ = '\"';
454 *cur_point++ = ' ';
455 CoTaskMemFree(file);
457 *(cur_point-1) = '\0';
459 set_file_name(This, string);
460 HeapFree(GetProcessHeap(), 0, string);
463 HeapFree(GetProcessHeap(), 0, names);
464 return;
467 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
469 WCHAR *endpos, *ext;
471 lstrcpyW(buf, spec);
472 if( (endpos = StrChrW(buf, ';')) )
473 *endpos = '\0';
475 ext = PathFindExtensionW(buf);
476 if(StrChrW(ext, '*'))
477 return NULL;
479 return ext;
482 static BOOL shell_item_exists(IShellItem* shellitem)
484 LPWSTR filename;
485 HRESULT hr;
486 BOOL result;
488 hr = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &filename);
489 if (SUCCEEDED(hr))
491 /* FIXME: Implement SFGAO_VALIDATE in Wine and use it instead. */
492 result = (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES);
493 CoTaskMemFree(filename);
495 else
497 SFGAOF attributes;
498 result = SUCCEEDED(IShellItem_GetAttributes(shellitem, SFGAO_VALIDATE, &attributes));
501 return result;
504 static HRESULT on_default_action(FileDialogImpl *This)
506 IShellFolder *psf_parent, *psf_desktop;
507 LPITEMIDLIST *pidla;
508 LPITEMIDLIST current_folder;
509 LPWSTR fn_iter, files = NULL, tmp_files;
510 UINT file_count = 0, len, i;
511 int open_action;
512 HRESULT hr, ret = E_FAIL;
514 len = get_file_name(This, &tmp_files);
515 if(len)
517 UINT size_used;
518 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
519 CoTaskMemFree(tmp_files);
521 if(!file_count) return E_FAIL;
523 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
524 if(FAILED(hr))
526 ERR("Failed to get pidl for current directory.\n");
527 HeapFree(GetProcessHeap(), 0, files);
528 return hr;
531 TRACE("Acting on %d file(s).\n", file_count);
533 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
534 open_action = ONOPEN_OPEN;
535 fn_iter = files;
537 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
539 WCHAR canon_filename[MAX_PATH];
540 psf_parent = NULL;
542 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
544 if( (This->options & FOS_NOVALIDATE) &&
545 !(This->options & FOS_FILEMUSTEXIST) )
546 open_action = ONOPEN_OPEN;
547 else
548 open_action = ONOPEN_BROWSE;
550 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
551 This->options & ~FOS_FILEMUSTEXIST,
552 (This->dlg_type == ITEMDLG_TYPE_SAVE),
553 open_action);
555 /* Add the proper extension */
556 if(open_action == ONOPEN_OPEN)
558 static const WCHAR dotW[] = {'.',0};
560 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
562 WCHAR extbuf[MAX_PATH], *newext = NULL;
564 if(This->filterspec_count)
566 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
568 else if(This->default_ext)
570 lstrcpyW(extbuf, dotW);
571 lstrcatW(extbuf, This->default_ext);
572 newext = extbuf;
575 if(newext)
577 WCHAR *ext = PathFindExtensionW(canon_filename);
578 if(lstrcmpW(ext, newext))
579 lstrcatW(canon_filename, newext);
582 else
584 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
585 !PathFileExistsW(canon_filename))
587 if(This->default_ext)
589 lstrcatW(canon_filename, dotW);
590 lstrcatW(canon_filename, This->default_ext);
592 if(!PathFileExistsW(canon_filename))
594 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
595 open_action = ONOPEN_BROWSE;
598 else
600 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
601 open_action = ONOPEN_BROWSE;
607 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
609 if(psf_parent && !(open_action == ONOPEN_BROWSE))
610 IShellFolder_Release(psf_parent);
612 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
615 HeapFree(GetProcessHeap(), 0, files);
616 ILFree(current_folder);
618 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
619 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
621 switch(open_action)
623 case ONOPEN_SEARCH:
624 FIXME("Filtering not implemented.\n");
625 break;
627 case ONOPEN_BROWSE:
628 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
629 if(FAILED(hr))
630 ERR("Failed to browse to directory: %08x\n", hr);
632 IShellFolder_Release(psf_parent);
633 break;
635 case ONOPEN_OPEN:
636 hr = SHGetDesktopFolder(&psf_desktop);
637 if(SUCCEEDED(hr))
639 if(This->psia_results)
641 IShellItemArray_Release(This->psia_results);
642 This->psia_results = NULL;
645 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
646 &This->psia_results);
648 IShellFolder_Release(psf_desktop);
650 if(FAILED(hr))
651 break;
653 if(This->options & FOS_PICKFOLDERS)
655 SFGAOF attributes;
656 hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
657 if(hr != S_OK)
659 WCHAR buf[64];
660 LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, sizeof(buf)/sizeof(WCHAR));
662 MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
664 IShellItemArray_Release(This->psia_results);
665 This->psia_results = NULL;
666 break;
670 if((This->options & FOS_OVERWRITEPROMPT) && This->dlg_type == ITEMDLG_TYPE_SAVE)
672 IShellItem *shellitem;
674 for (i=0; SUCCEEDED(hr) && i<file_count; i++)
676 hr = IShellItemArray_GetItemAt(This->psia_results, i, &shellitem);
677 if (SUCCEEDED(hr))
679 if (shell_item_exists(shellitem))
680 hr = events_OnOverwrite(This, shellitem);
682 IShellItem_Release(shellitem);
686 if (FAILED(hr))
687 break;
690 if(events_OnFileOk(This) == S_OK)
691 ret = S_OK;
693 break;
695 default:
696 ERR("Failed.\n");
697 break;
700 /* Clean up */
701 for(i = 0; i < file_count; i++)
702 ILFree(pidla[i]);
703 HeapFree(GetProcessHeap(), 0, pidla);
705 /* Success closes the dialog */
706 return ret;
709 static void show_opendropdown(FileDialogImpl *This)
711 HWND open_hwnd;
712 RECT open_rc;
713 MSG msg;
715 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
717 GetWindowRect(open_hwnd, &open_rc);
719 if (TrackPopupMenu(This->hmenu_opendropdown, 0, open_rc.left, open_rc.bottom, 0, This->dlg_hwnd, NULL) &&
720 PeekMessageW(&msg, This->dlg_hwnd, WM_MENUCOMMAND, WM_MENUCOMMAND, PM_REMOVE))
722 MENUITEMINFOW mii;
724 This->opendropdown_has_selection = TRUE;
726 mii.cbSize = sizeof(mii);
727 mii.fMask = MIIM_ID;
728 GetMenuItemInfoW((HMENU)msg.lParam, msg.wParam, TRUE, &mii);
729 This->opendropdown_selection = mii.wID;
731 if(SUCCEEDED(on_default_action(This)))
732 EndDialog(This->dlg_hwnd, S_OK);
733 else
734 This->opendropdown_has_selection = FALSE;
738 /**************************************************************************
739 * Control item functions.
742 static void item_free(cctrl_item *item)
744 DestroyWindow(item->hwnd);
745 HeapFree(GetProcessHeap(), 0, item->label);
746 HeapFree(GetProcessHeap(), 0, item);
749 static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF visible_flags, DWORD* position)
751 DWORD dummy;
752 cctrl_item* item;
754 if (!position) position = &dummy;
756 *position = 0;
758 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
760 if (item->id == itemid)
761 return item;
763 if ((item->cdcstate & visible_flags) == visible_flags)
764 (*position)++;
767 return NULL;
770 static cctrl_item* get_first_item(customctrl* parent)
772 cctrl_item* item;
774 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
776 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
777 return item;
780 return NULL;
783 static HRESULT add_item(customctrl* parent, DWORD itemid, LPCWSTR label, cctrl_item** result)
785 cctrl_item* item;
786 LPWSTR label_copy;
788 if (get_item(parent, itemid, 0, NULL))
789 return E_INVALIDARG;
791 item = HeapAlloc(GetProcessHeap(), 0, sizeof(*item));
792 label_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(label)+1)*sizeof(WCHAR));
794 if (!item || !label_copy)
796 HeapFree(GetProcessHeap(), 0, item);
797 HeapFree(GetProcessHeap(), 0, label_copy);
798 return E_OUTOFMEMORY;
801 item->id = itemid;
802 item->parent_id = parent->id;
803 lstrcpyW(label_copy, label);
804 item->label = label_copy;
805 item->cdcstate = CDCS_VISIBLE|CDCS_ENABLED;
806 item->hwnd = NULL;
807 list_add_tail(&parent->sub_items, &item->entry);
809 *result = item;
811 return S_OK;
814 /**************************************************************************
815 * Control functions.
817 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
819 customctrl *ctrl, *sub_ctrl;
821 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
823 if(ctrl->dlgid == dlgid)
824 return ctrl;
826 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
827 if(sub_ctrl->dlgid == dlgid)
828 return sub_ctrl;
831 ERR("Failed to find control with dialog id %d\n", dlgid);
832 return NULL;
835 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
837 customctrl *ctrl, *sub_ctrl;
839 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
841 if(ctrl->id == ctlid)
842 return ctrl;
844 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
845 if(sub_ctrl->id == ctlid)
846 return sub_ctrl;
849 if (This->hmenu_opendropdown && This->cctrl_opendropdown.id == ctlid)
850 return &This->cctrl_opendropdown;
852 TRACE("No existing control with control id %d\n", ctlid);
853 return NULL;
856 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
858 LPWSTR text;
859 UINT len, final_width;
860 UINT lines, final_height;
861 SIZE size;
862 RECT rc;
863 HDC hdc;
864 WCHAR *c;
866 TRACE("\n");
868 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
869 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
870 if(!text) return;
871 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
873 hdc = GetDC(hctrl);
874 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
875 ReleaseDC(hctrl, hdc);
877 if(len && multiline)
879 /* FIXME: line-wrap */
880 for(lines = 1, c = text; *c != '\0'; c++)
881 if(*c == '\n') lines++;
883 final_height = size.cy*lines + 2*4;
885 else
887 GetWindowRect(hctrl, &rc);
888 final_height = rc.bottom - rc.top;
891 final_width = min(max(size.cx, min_width) + 4, max_width);
892 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
893 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
895 HeapFree(GetProcessHeap(), 0, text);
898 static UINT ctrl_get_height(customctrl *ctrl) {
899 RECT rc;
900 GetWindowRect(ctrl->wrapper_hwnd, &rc);
901 return rc.bottom - rc.top;
904 static void ctrl_free(customctrl *ctrl)
906 customctrl *sub_cur1, *sub_cur2;
907 cctrl_item *item_cur1, *item_cur2;
909 TRACE("Freeing control %p\n", ctrl);
910 if(ctrl->type == IDLG_CCTRL_MENU)
912 TBBUTTON tbb;
913 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
914 DestroyMenu((HMENU)tbb.dwData);
917 LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
919 list_remove(&sub_cur1->sub_cctrls_entry);
920 ctrl_free(sub_cur1);
923 LIST_FOR_EACH_ENTRY_SAFE(item_cur1, item_cur2, &ctrl->sub_items, cctrl_item, entry)
925 list_remove(&item_cur1->entry);
926 item_free(item_cur1);
929 DestroyWindow(ctrl->hwnd);
930 HeapFree(GetProcessHeap(), 0, ctrl);
933 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
935 RECT rc;
936 UINT total_height;
937 UINT max_width;
938 customctrl *sub_ctrl;
940 switch(ctrl->type)
942 case IDLG_CCTRL_PUSHBUTTON:
943 case IDLG_CCTRL_COMBOBOX:
944 case IDLG_CCTRL_CHECKBUTTON:
945 case IDLG_CCTRL_TEXT:
946 ctrl_resize(ctrl->hwnd, 160, 160, TRUE);
947 GetWindowRect(ctrl->hwnd, &rc);
948 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
949 SWP_NOZORDER|SWP_NOMOVE);
950 break;
951 case IDLG_CCTRL_VISUALGROUP:
952 total_height = 0;
953 ctrl_resize(ctrl->hwnd, 0, This->cctrl_indent, TRUE);
955 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
957 customctrl_resize(This, sub_ctrl);
958 SetWindowPos(sub_ctrl->wrapper_hwnd, NULL, This->cctrl_indent, total_height, 0, 0,
959 SWP_NOZORDER|SWP_NOSIZE);
961 total_height += ctrl_get_height(sub_ctrl);
964 /* The label should be right adjusted */
966 UINT width, height;
968 GetWindowRect(ctrl->hwnd, &rc);
969 width = rc.right - rc.left;
970 height = rc.bottom - rc.top;
972 SetWindowPos(ctrl->hwnd, NULL, This->cctrl_indent - width, 0, width, height, SWP_NOZORDER);
975 /* Resize the wrapper window to fit all the sub controls */
976 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, This->cctrl_width + This->cctrl_indent, total_height,
977 SWP_NOZORDER|SWP_NOMOVE);
978 break;
979 case IDLG_CCTRL_RADIOBUTTONLIST:
981 cctrl_item* item;
983 total_height = 0;
984 max_width = 0;
986 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
988 ctrl_resize(item->hwnd, 160, 160, TRUE);
989 SetWindowPos(item->hwnd, NULL, 0, total_height, 0, 0,
990 SWP_NOZORDER|SWP_NOSIZE);
992 GetWindowRect(item->hwnd, &rc);
994 total_height += rc.bottom - rc.top;
995 max_width = max(rc.right - rc.left, max_width);
998 SetWindowPos(ctrl->hwnd, NULL, 0, 0, max_width, total_height,
999 SWP_NOZORDER|SWP_NOMOVE);
1001 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, max_width, total_height,
1002 SWP_NOZORDER|SWP_NOMOVE);
1004 break;
1006 case IDLG_CCTRL_EDITBOX:
1007 case IDLG_CCTRL_SEPARATOR:
1008 case IDLG_CCTRL_MENU:
1009 case IDLG_CCTRL_OPENDROPDOWN:
1010 /* Nothing */
1011 break;
1015 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
1017 FileDialogImpl *This = crs->lpCreateParams;
1018 TRACE("%p\n", This);
1020 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1021 return TRUE;
1024 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1026 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1028 TRACE("%p, %lx\n", This, wparam);
1030 if(ctrl)
1032 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
1034 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
1035 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
1037 else
1038 cctrl_event_OnButtonClicked(This, ctrl->id);
1041 return TRUE;
1044 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1046 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1047 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
1049 if(ctrl)
1051 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
1052 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
1054 cctrl_event_OnItemSelected(This, ctrl->id, selid);
1056 return TRUE;
1059 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
1061 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
1062 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
1063 POINT pt = { 0, nmtb->rcButton.bottom };
1064 TBBUTTON tbb;
1065 UINT idcmd;
1067 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
1069 if(ctrl)
1071 cctrl_event_OnControlActivating(This,ctrl->id);
1073 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1074 ClientToScreen(ctrl->hwnd, &pt);
1075 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
1076 if(idcmd)
1077 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
1080 return TBDDRET_DEFAULT;
1083 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1085 switch(HIWORD(wparam))
1087 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
1088 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
1091 return FALSE;
1094 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1096 NMHDR *nmhdr = (NMHDR*)lparam;
1098 switch(nmhdr->code)
1100 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
1103 return FALSE;
1106 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1108 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1109 customctrl *ctrl;
1110 HWND hwnd_child;
1111 RECT rc;
1113 switch(message)
1115 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
1116 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
1117 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
1118 case WM_SIZE:
1119 hwnd_child = GetPropW(hwnd, notifysink_childW);
1120 ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA);
1121 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
1123 GetClientRect(hwnd, &rc);
1124 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1126 return TRUE;
1129 return DefWindowProcW(hwnd, message, wparam, lparam);
1132 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
1133 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
1134 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
1136 HWND ns_hwnd, control_hwnd, parent_hwnd;
1137 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
1138 customctrl *ctrl;
1140 if(get_cctrl(This, id))
1141 return E_UNEXPECTED; /* Duplicate id */
1143 if(This->cctrl_active_vg)
1144 parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
1145 else
1146 parent_hwnd = This->cctrls_hwnd;
1148 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
1149 0, 0, This->cctrl_width, height, parent_hwnd,
1150 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
1151 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
1152 0, 0, This->cctrl_width, height, ns_hwnd,
1153 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
1155 if(!ns_hwnd || !control_hwnd)
1157 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
1158 DestroyWindow(ns_hwnd);
1159 DestroyWindow(control_hwnd);
1161 return E_FAIL;
1164 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
1166 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
1167 if(!ctrl)
1168 return E_OUTOFMEMORY;
1170 ctrl->hwnd = control_hwnd;
1171 ctrl->wrapper_hwnd = ns_hwnd;
1172 ctrl->id = id;
1173 ctrl->dlgid = This->cctrl_next_dlgid;
1174 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
1175 list_init(&ctrl->sub_cctrls);
1176 list_init(&ctrl->sub_items);
1178 if(This->cctrl_active_vg)
1179 list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
1180 else
1181 list_add_tail(&This->cctrls, &ctrl->entry);
1183 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl);
1185 if(ppctrl) *ppctrl = ctrl;
1187 This->cctrl_next_dlgid++;
1188 return S_OK;
1191 /**************************************************************************
1192 * Container functions.
1194 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
1196 UINT container_height;
1197 UINT column_width;
1198 UINT nr_of_cols;
1199 UINT max_control_height, total_height = 0;
1200 UINT cur_col_pos, cur_row_pos;
1201 customctrl *ctrl;
1202 BOOL fits_height;
1203 static const UINT cspacing = 90; /* Columns are spaced with 90px */
1204 static const UINT rspacing = 4; /* Rows are spaced with 4 px. */
1206 /* Given the new width of the container, this function determines the
1207 * needed height of the container and places the controls according to
1208 * the new layout. Returns the new height.
1211 TRACE("%p\n", This);
1213 column_width = This->cctrl_width + cspacing;
1214 nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
1216 /* We don't need to do anything unless the number of visible columns has changed. */
1217 if(nr_of_cols == This->cctrls_cols)
1219 RECT rc;
1220 GetWindowRect(This->cctrls_hwnd, &rc);
1221 return rc.bottom - rc.top;
1224 This->cctrls_cols = nr_of_cols;
1226 /* Get the size of the tallest control, and the total size of
1227 * all the controls to figure out the number of slots we need.
1229 max_control_height = 0;
1230 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1232 if(ctrl->cdcstate & CDCS_VISIBLE)
1234 UINT control_height = ctrl_get_height(ctrl);
1235 max_control_height = max(max_control_height, control_height);
1237 total_height += control_height + rspacing;
1241 if(!total_height)
1242 return 0;
1244 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
1245 TRACE("Guess: container_height: %d\n",container_height);
1247 /* Incrementally increase container_height until all the controls
1248 * fit.
1250 do {
1251 UINT columns_needed = 1;
1252 cur_row_pos = 0;
1254 fits_height = TRUE;
1255 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1257 if(ctrl->cdcstate & CDCS_VISIBLE)
1259 UINT control_height = ctrl_get_height(ctrl);
1261 if(cur_row_pos + control_height > container_height)
1263 if(++columns_needed > nr_of_cols)
1265 container_height += 1;
1266 fits_height = FALSE;
1267 break;
1269 cur_row_pos = 0;
1272 cur_row_pos += control_height + rspacing;
1275 } while(!fits_height);
1277 TRACE("Final container height: %d\n", container_height);
1279 /* Move the controls to their final destination
1281 cur_col_pos = 0, cur_row_pos = 0;
1282 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1284 if(ctrl->cdcstate & CDCS_VISIBLE)
1286 RECT rc;
1287 UINT control_height, control_indent;
1288 GetWindowRect(ctrl->wrapper_hwnd, &rc);
1289 control_height = rc.bottom - rc.top;
1291 if(cur_row_pos + control_height > container_height)
1293 cur_row_pos = 0;
1294 cur_col_pos += This->cctrl_width + cspacing;
1298 if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
1299 control_indent = 0;
1300 else
1301 control_indent = This->cctrl_indent;
1303 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
1304 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1306 cur_row_pos += control_height + rspacing;
1310 /* Sanity check */
1311 if(cur_row_pos + This->cctrl_width > container_width)
1312 ERR("-- Failed to place controls properly.\n");
1314 return container_height;
1317 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
1319 LONG wndstyle;
1321 if(parent)
1323 customctrl *ctrl, *sub_ctrl;
1324 HFONT font;
1326 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1327 wndstyle &= ~(WS_POPUP);
1328 wndstyle |= WS_CHILD;
1329 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1331 SetParent(This->cctrls_hwnd, parent);
1332 ShowWindow(This->cctrls_hwnd, TRUE);
1334 /* Set the fonts to match the dialog font. */
1335 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
1336 if(!font)
1337 ERR("Failed to get font handle from dialog.\n");
1339 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1341 if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1343 /* If this is a VisualGroup */
1344 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1346 if(font) SendMessageW(sub_ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1349 if (ctrl->type == IDLG_CCTRL_RADIOBUTTONLIST)
1351 cctrl_item* item;
1352 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1354 if (font) SendMessageW(item->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1358 customctrl_resize(This, ctrl);
1361 else
1363 ShowWindow(This->cctrls_hwnd, FALSE);
1365 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1366 wndstyle &= ~(WS_CHILD);
1367 wndstyle |= WS_POPUP;
1368 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1370 SetParent(This->cctrls_hwnd, NULL);
1374 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
1376 FileDialogImpl *This = crs->lpCreateParams;
1377 TRACE("%p\n", This);
1379 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1380 return TRUE;
1383 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
1385 customctrl *cur1, *cur2;
1386 TRACE("%p\n", This);
1388 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1390 list_remove(&cur1->entry);
1391 ctrl_free(cur1);
1394 return TRUE;
1397 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1399 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1401 switch(umessage)
1403 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1404 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1405 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1408 return FALSE;
1411 static void radiobuttonlist_set_selected_item(FileDialogImpl *This, customctrl *ctrl, cctrl_item *item)
1413 cctrl_item *cursor;
1415 LIST_FOR_EACH_ENTRY(cursor, &ctrl->sub_items, cctrl_item, entry)
1417 SendMessageW(cursor->hwnd, BM_SETCHECK, (cursor == item) ? BST_CHECKED : BST_UNCHECKED, 0);
1421 static LRESULT radiobuttonlist_on_bn_clicked(FileDialogImpl *This, HWND hwnd, HWND child)
1423 DWORD ctrl_id = (DWORD)GetWindowLongPtrW(hwnd, GWLP_ID);
1424 customctrl *ctrl;
1425 cctrl_item *item;
1426 BOOL found_item=FALSE;
1428 ctrl = get_cctrl_from_dlgid(This, ctrl_id);
1430 if (!ctrl)
1432 ERR("Can't find this control\n");
1433 return 0;
1436 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1438 if (item->hwnd == child)
1440 found_item = TRUE;
1441 break;
1445 if (!found_item)
1447 ERR("Can't find control item\n");
1448 return 0;
1451 radiobuttonlist_set_selected_item(This, ctrl, item);
1453 cctrl_event_OnItemSelected(This, ctrl->id, item->id);
1455 return 0;
1458 static LRESULT radiobuttonlist_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1460 switch(HIWORD(wparam))
1462 case BN_CLICKED: return radiobuttonlist_on_bn_clicked(This, hwnd, (HWND)lparam);
1465 return FALSE;
1468 static LRESULT CALLBACK radiobuttonlist_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1470 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1472 switch(message)
1474 case WM_COMMAND: return radiobuttonlist_on_wm_command(This, hwnd, wparam, lparam);
1477 return DefWindowProcW(hwnd, message, wparam, lparam);
1480 static HRESULT init_custom_controls(FileDialogImpl *This)
1482 WNDCLASSW wc;
1483 static const WCHAR ctrl_container_classname[] =
1484 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1486 InitCommonControlsEx(NULL);
1488 This->cctrl_width = 160; /* Controls have a fixed width */
1489 This->cctrl_indent = 100;
1490 This->cctrl_def_height = 23;
1491 This->cctrls_cols = 0;
1493 This->cctrl_next_dlgid = 0x2000;
1494 list_init(&This->cctrls);
1495 This->cctrl_active_vg = NULL;
1497 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1499 wc.style = CS_HREDRAW | CS_VREDRAW;
1500 wc.lpfnWndProc = ctrl_container_wndproc;
1501 wc.cbClsExtra = 0;
1502 wc.cbWndExtra = 0;
1503 wc.hInstance = COMDLG32_hInstance;
1504 wc.hIcon = 0;
1505 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1506 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1507 wc.lpszMenuName = NULL;
1508 wc.lpszClassName = ctrl_container_classname;
1510 if(!RegisterClassW(&wc)) return E_FAIL;
1513 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1514 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1515 0, 0, 0, 0, NULL, 0,
1516 COMDLG32_hInstance, This);
1517 if(!This->cctrls_hwnd)
1518 return E_FAIL;
1520 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1522 /* Register class for */
1523 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1524 wc.hInstance != COMDLG32_hInstance)
1526 wc.style = CS_HREDRAW | CS_VREDRAW;
1527 wc.lpfnWndProc = notifysink_proc;
1528 wc.cbClsExtra = 0;
1529 wc.cbWndExtra = 0;
1530 wc.hInstance = COMDLG32_hInstance;
1531 wc.hIcon = 0;
1532 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1533 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1534 wc.lpszMenuName = NULL;
1535 wc.lpszClassName = floatnotifysinkW;
1537 if (!RegisterClassW(&wc))
1538 ERR("Failed to register FloatNotifySink window class.\n");
1541 if( !GetClassInfoW(COMDLG32_hInstance, radiobuttonlistW, &wc) ||
1542 wc.hInstance != COMDLG32_hInstance)
1544 wc.style = CS_HREDRAW | CS_VREDRAW;
1545 wc.lpfnWndProc = radiobuttonlist_proc;
1546 wc.cbClsExtra = 0;
1547 wc.cbWndExtra = 0;
1548 wc.hInstance = COMDLG32_hInstance;
1549 wc.hIcon = 0;
1550 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1551 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1552 wc.lpszMenuName = NULL;
1553 wc.lpszClassName = radiobuttonlistW;
1555 if (!RegisterClassW(&wc))
1556 ERR("Failed to register RadioButtonList window class.\n");
1559 return S_OK;
1562 /**************************************************************************
1563 * Window related functions.
1565 static BOOL update_open_dropdown(FileDialogImpl *This)
1567 /* Show or hide the open dropdown button as appropriate */
1568 BOOL show=FALSE, showing;
1569 HWND open_hwnd, dropdown_hwnd;
1571 if (This->hmenu_opendropdown)
1573 INT num_visible_items=0;
1574 cctrl_item* item;
1576 LIST_FOR_EACH_ENTRY(item, &This->cctrl_opendropdown.sub_items, cctrl_item, entry)
1578 if (item->cdcstate & CDCS_VISIBLE)
1580 num_visible_items++;
1581 if (num_visible_items >= 2)
1583 show = TRUE;
1584 break;
1590 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1591 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1593 showing = (GetWindowLongPtrW(dropdown_hwnd, GWL_STYLE) & WS_VISIBLE) != 0;
1595 if (showing != show)
1597 RECT open_rc, dropdown_rc;
1599 GetWindowRect(open_hwnd, &open_rc);
1600 GetWindowRect(dropdown_hwnd, &dropdown_rc);
1602 if (show)
1604 ShowWindow(dropdown_hwnd, SW_SHOW);
1606 SetWindowPos(open_hwnd, NULL, 0, 0,
1607 (open_rc.right - open_rc.left) - (dropdown_rc.right - dropdown_rc.left),
1608 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1610 else
1612 ShowWindow(dropdown_hwnd, SW_HIDE);
1614 SetWindowPos(open_hwnd, NULL, 0, 0,
1615 (open_rc.right - open_rc.left) + (dropdown_rc.right - dropdown_rc.left),
1616 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1620 return show;
1623 static void update_layout(FileDialogImpl *This)
1625 HDWP hdwp;
1626 HWND hwnd;
1627 RECT dialog_rc;
1628 RECT cancel_rc, dropdown_rc, open_rc;
1629 RECT filetype_rc, filename_rc, filenamelabel_rc;
1630 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1631 static const UINT vspacing = 4, hspacing = 4;
1632 static const UINT min_width = 320, min_height = 200;
1633 BOOL show_dropdown;
1635 if (!GetClientRect(This->dlg_hwnd, &dialog_rc))
1637 TRACE("Invalid dialog window, not updating layout\n");
1638 return;
1641 if(dialog_rc.right < min_width || dialog_rc.bottom < min_height)
1643 TRACE("Dialog size (%d, %d) too small, not updating layout\n", dialog_rc.right, dialog_rc.bottom);
1644 return;
1647 /****
1648 * Calculate the size of the dialog and all the parts.
1651 /* Cancel button */
1652 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1653 if(hwnd)
1655 int cancel_width, cancel_height;
1656 GetWindowRect(hwnd, &cancel_rc);
1657 cancel_width = cancel_rc.right - cancel_rc.left;
1658 cancel_height = cancel_rc.bottom - cancel_rc.top;
1660 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1661 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1662 cancel_rc.right = cancel_rc.left + cancel_width;
1663 cancel_rc.bottom = cancel_rc.top + cancel_height;
1666 /* Open/Save dropdown */
1667 show_dropdown = update_open_dropdown(This);
1669 if(show_dropdown)
1671 int dropdown_width, dropdown_height;
1672 hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1674 GetWindowRect(hwnd, &dropdown_rc);
1675 dropdown_width = dropdown_rc.right - dropdown_rc.left;
1676 dropdown_height = dropdown_rc.bottom - dropdown_rc.top;
1678 dropdown_rc.left = cancel_rc.left - dropdown_width - hspacing;
1679 dropdown_rc.top = cancel_rc.top;
1680 dropdown_rc.right = dropdown_rc.left + dropdown_width;
1681 dropdown_rc.bottom = dropdown_rc.top + dropdown_height;
1683 else
1685 dropdown_rc.left = dropdown_rc.right = cancel_rc.left - hspacing;
1686 dropdown_rc.top = cancel_rc.top;
1687 dropdown_rc.bottom = cancel_rc.bottom;
1690 /* Open/Save button */
1691 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1692 if(hwnd)
1694 int open_width, open_height;
1695 GetWindowRect(hwnd, &open_rc);
1696 open_width = open_rc.right - open_rc.left;
1697 open_height = open_rc.bottom - open_rc.top;
1699 open_rc.left = dropdown_rc.left - open_width;
1700 open_rc.top = dropdown_rc.top;
1701 open_rc.right = open_rc.left + open_width;
1702 open_rc.bottom = open_rc.top + open_height;
1705 /* The filetype combobox. */
1706 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1707 if(hwnd)
1709 int filetype_width, filetype_height;
1710 GetWindowRect(hwnd, &filetype_rc);
1712 filetype_width = filetype_rc.right - filetype_rc.left;
1713 filetype_height = filetype_rc.bottom - filetype_rc.top;
1715 filetype_rc.right = cancel_rc.right;
1717 filetype_rc.left = filetype_rc.right - filetype_width;
1718 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1719 filetype_rc.bottom = filetype_rc.top + filetype_height;
1721 if(!This->filterspec_count)
1722 filetype_rc.left = filetype_rc.right;
1725 /* Filename label. */
1726 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1727 if(hwnd)
1729 int filetypelabel_width, filetypelabel_height;
1730 GetWindowRect(hwnd, &filenamelabel_rc);
1732 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1733 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1735 filenamelabel_rc.left = 160; /* FIXME */
1736 filenamelabel_rc.top = filetype_rc.top;
1737 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1738 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1741 /* Filename edit box. */
1742 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1743 if(hwnd)
1745 int filename_width, filename_height;
1746 GetWindowRect(hwnd, &filename_rc);
1748 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1749 filename_height = filename_rc.bottom - filename_rc.top;
1751 filename_rc.left = filenamelabel_rc.right + hspacing;
1752 filename_rc.top = filetype_rc.top;
1753 filename_rc.right = filename_rc.left + filename_width;
1754 filename_rc.bottom = filename_rc.top + filename_height;
1757 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1758 if(hwnd)
1760 GetWindowRect(hwnd, &toolbar_rc);
1761 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1764 /* The custom controls */
1765 customctrls_rc.left = dialog_rc.left + hspacing;
1766 customctrls_rc.right = dialog_rc.right - hspacing;
1767 customctrls_rc.bottom = filename_rc.top - vspacing;
1768 customctrls_rc.top = customctrls_rc.bottom -
1769 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1771 /* The ExplorerBrowser control. */
1772 ebrowser_rc.left = dialog_rc.left + hspacing;
1773 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1774 ebrowser_rc.right = dialog_rc.right - hspacing;
1775 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1777 /****
1778 * Move everything to the right place.
1781 /* FIXME: The Save Dialog uses a slightly different layout. */
1782 hdwp = BeginDeferWindowPos(7);
1784 if(hdwp && This->peb)
1785 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1787 if(hdwp && This->cctrls_hwnd)
1788 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1789 customctrls_rc.left, customctrls_rc.top,
1790 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1791 SWP_NOZORDER | SWP_NOACTIVATE);
1793 /* The default controls */
1794 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1795 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1796 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1798 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1799 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1800 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1801 SWP_NOZORDER | SWP_NOACTIVATE);
1803 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1804 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1805 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1807 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1808 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1809 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1811 if(hdwp && This->hmenu_opendropdown && (hwnd = GetDlgItem(This->dlg_hwnd, psh1)))
1812 DeferWindowPos(hdwp, hwnd, NULL, dropdown_rc.left, dropdown_rc.top, 0, 0,
1813 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1815 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1816 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1817 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1819 if(hdwp)
1820 EndDeferWindowPos(hdwp);
1821 else
1822 ERR("Failed to position dialog controls.\n");
1824 return;
1827 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1829 IShellItem *psi_folder;
1830 IObjectWithSite *client;
1831 FOLDERSETTINGS fos;
1832 RECT rc = {0};
1833 HRESULT hr;
1835 /* Create ExplorerBrowser instance */
1836 OleInitialize(NULL);
1838 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1839 &IID_IExplorerBrowser, (void**)&This->peb);
1840 if(FAILED(hr))
1842 ERR("Failed to instantiate ExplorerBrowser control.\n");
1843 return hr;
1846 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES | EBO_NOBORDER);
1848 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1849 if(FAILED(hr))
1851 ERR("Failed to initialize the ExplorerBrowser control.\n");
1852 IExplorerBrowser_Release(This->peb);
1853 This->peb = NULL;
1854 return hr;
1856 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1857 if(FAILED(hr))
1858 ERR("Advise (ExplorerBrowser) failed.\n");
1860 /* Get previous options? */
1861 fos.ViewMode = fos.fFlags = 0;
1862 if(!(This->options & FOS_ALLOWMULTISELECT))
1863 fos.fFlags |= FWF_SINGLESEL;
1865 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1867 hr = IExplorerBrowser_QueryInterface(This->peb, &IID_IObjectWithSite, (void**)&client);
1868 if (hr == S_OK)
1870 hr = IObjectWithSite_SetSite(client, (IUnknown*)&This->IFileDialog2_iface);
1871 IObjectWithSite_Release(client);
1872 if(FAILED(hr))
1873 ERR("SetSite failed, 0x%08x\n", hr);
1876 /* Browse somewhere */
1877 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1878 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1880 return S_OK;
1883 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1885 HWND htoolbar;
1886 TBADDBITMAP tbab;
1887 TBBUTTON button[2];
1889 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1890 0, 0, 0, 0,
1891 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1893 tbab.hInst = HINST_COMMCTRL;
1894 tbab.nID = IDB_HIST_LARGE_COLOR;
1895 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1897 button[0].iBitmap = HIST_BACK;
1898 button[0].idCommand = IDC_NAVBACK;
1899 button[0].fsState = TBSTATE_ENABLED;
1900 button[0].fsStyle = BTNS_BUTTON;
1901 button[0].dwData = 0;
1902 button[0].iString = 0;
1904 button[1].iBitmap = HIST_FORWARD;
1905 button[1].idCommand = IDC_NAVFORWARD;
1906 button[1].fsState = TBSTATE_ENABLED;
1907 button[1].fsStyle = BTNS_BUTTON;
1908 button[1].dwData = 0;
1909 button[1].iString = 0;
1911 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1912 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1913 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1916 static void update_control_text(FileDialogImpl *This)
1918 HWND hitem;
1919 LPCWSTR custom_okbutton;
1920 cctrl_item* item;
1922 if(This->custom_title)
1923 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1925 if(This->hmenu_opendropdown && (item = get_first_item(&This->cctrl_opendropdown)))
1926 custom_okbutton = item->label;
1927 else
1928 custom_okbutton = This->custom_okbutton;
1930 if(custom_okbutton &&
1931 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1933 SetWindowTextW(hitem, custom_okbutton);
1934 ctrl_resize(hitem, 50, 250, FALSE);
1937 if(This->custom_cancelbutton &&
1938 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1940 SetWindowTextW(hitem, This->custom_cancelbutton);
1941 ctrl_resize(hitem, 50, 250, FALSE);
1944 if(This->custom_filenamelabel &&
1945 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1947 SetWindowTextW(hitem, This->custom_filenamelabel);
1948 ctrl_resize(hitem, 50, 250, FALSE);
1952 static LRESULT CALLBACK dropdown_subclass_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1954 static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
1955 static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
1957 if (umessage == WM_LBUTTONDOWN)
1959 FileDialogImpl *This = (FileDialogImpl*)GetPropW(hwnd, prop_this);
1961 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
1962 show_opendropdown(This);
1963 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
1965 return 0;
1968 return CallWindowProcW((WNDPROC)GetPropW(hwnd, prop_oldwndproc), hwnd, umessage, wparam, lparam);
1971 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1973 FileDialogImpl *This = (FileDialogImpl*)lParam;
1974 HWND hitem;
1976 TRACE("(%p, %p)\n", This, hwnd);
1978 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1979 This->dlg_hwnd = hwnd;
1981 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1982 if(hitem) ShowWindow(hitem, SW_HIDE);
1984 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1985 if(hitem) ShowWindow(hitem, SW_HIDE);
1987 /* Fill filetypes combobox, or hide it. */
1988 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1989 if(This->filterspec_count)
1991 HDC hdc;
1992 HFONT font;
1993 SIZE size;
1994 UINT i, maxwidth = 0;
1996 hdc = GetDC(hitem);
1997 font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
1998 SelectObject(hdc, font);
2000 for(i = 0; i < This->filterspec_count; i++)
2002 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
2004 if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
2005 maxwidth = max(maxwidth, size.cx);
2007 ReleaseDC(hitem, hdc);
2009 if(maxwidth > 0)
2011 maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
2012 SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
2014 else
2015 ERR("Failed to calculate width of filetype dropdown\n");
2017 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
2019 else
2020 ShowWindow(hitem, SW_HIDE);
2022 if(This->set_filename &&
2023 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
2024 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
2026 if(This->hmenu_opendropdown)
2028 HWND dropdown_hwnd;
2029 LOGFONTW lfw, lfw_marlett;
2030 HFONT dialog_font;
2031 static const WCHAR marlett[] = {'M','a','r','l','e','t','t',0};
2032 static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
2033 static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
2035 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
2037 /* Change dropdown button font to Marlett */
2038 dialog_font = (HFONT)SendMessageW(dropdown_hwnd, WM_GETFONT, 0, 0);
2040 GetObjectW(dialog_font, sizeof(lfw), &lfw);
2042 memset(&lfw_marlett, 0, sizeof(lfw_marlett));
2043 lstrcpyW(lfw_marlett.lfFaceName, marlett);
2044 lfw_marlett.lfHeight = lfw.lfHeight;
2045 lfw_marlett.lfCharSet = SYMBOL_CHARSET;
2047 This->hfont_opendropdown = CreateFontIndirectW(&lfw_marlett);
2049 SendMessageW(dropdown_hwnd, WM_SETFONT, (LPARAM)This->hfont_opendropdown, 0);
2051 /* Subclass button so we can handle LBUTTONDOWN */
2052 SetPropW(dropdown_hwnd, prop_this, (HANDLE)This);
2053 SetPropW(dropdown_hwnd, prop_oldwndproc,
2054 (HANDLE)SetWindowLongPtrW(dropdown_hwnd, GWLP_WNDPROC, (LONG_PTR)dropdown_subclass_proc));
2057 ctrl_container_reparent(This, This->dlg_hwnd);
2058 init_explorerbrowser(This);
2059 init_toolbar(This, hwnd);
2060 update_control_text(This);
2061 update_layout(This);
2063 if(This->filterspec_count)
2064 events_OnTypeChange(This);
2066 if ((hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)))
2067 SetFocus(hitem);
2069 return FALSE;
2072 static LRESULT on_wm_size(FileDialogImpl *This)
2074 update_layout(This);
2075 return FALSE;
2078 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
2080 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
2081 TRACE("%p (%p)\n", This, mmi);
2083 /* FIXME */
2084 mmi->ptMinTrackSize.x = 640;
2085 mmi->ptMinTrackSize.y = 480;
2087 return FALSE;
2090 static LRESULT on_wm_destroy(FileDialogImpl *This)
2092 TRACE("%p\n", This);
2094 if(This->peb)
2096 IExplorerBrowser_Destroy(This->peb);
2097 IExplorerBrowser_Release(This->peb);
2098 This->peb = NULL;
2101 ctrl_container_reparent(This, NULL);
2102 This->dlg_hwnd = NULL;
2104 DeleteObject(This->hfont_opendropdown);
2105 This->hfont_opendropdown = NULL;
2107 return TRUE;
2110 static LRESULT on_idok(FileDialogImpl *This)
2112 TRACE("%p\n", This);
2114 if(SUCCEEDED(on_default_action(This)))
2115 EndDialog(This->dlg_hwnd, S_OK);
2117 return FALSE;
2120 static LRESULT on_idcancel(FileDialogImpl *This)
2122 TRACE("%p\n", This);
2124 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
2126 return FALSE;
2129 static LRESULT on_command_opendropdown(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2131 if(HIWORD(wparam) == BN_CLICKED)
2133 HWND hwnd = (HWND)lparam;
2134 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
2135 show_opendropdown(This);
2136 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
2139 return FALSE;
2142 static LRESULT on_browse_back(FileDialogImpl *This)
2144 TRACE("%p\n", This);
2145 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
2146 return FALSE;
2149 static LRESULT on_browse_forward(FileDialogImpl *This)
2151 TRACE("%p\n", This);
2152 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
2153 return FALSE;
2156 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2158 if(HIWORD(wparam) == CBN_SELCHANGE)
2160 IShellView *psv;
2161 HRESULT hr;
2162 LPWSTR filename;
2163 UINT prev_index = This->filetypeindex;
2165 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
2166 TRACE("File type selection changed to %d.\n", This->filetypeindex);
2168 if(prev_index == This->filetypeindex)
2169 return FALSE;
2171 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
2172 if(SUCCEEDED(hr))
2174 IShellView_Refresh(psv);
2175 IShellView_Release(psv);
2178 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
2180 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
2182 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
2183 if(ext)
2185 lstrcpyW(buf, filename);
2187 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
2188 PathRemoveExtensionW(buf);
2190 lstrcatW(buf, ext);
2191 set_file_name(This, buf);
2193 CoTaskMemFree(filename);
2196 /* The documentation claims that OnTypeChange is called only
2197 * when the dialog is opened, but this is obviously not the
2198 * case. */
2199 events_OnTypeChange(This);
2202 return FALSE;
2205 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2207 switch(LOWORD(wparam))
2209 case IDOK: return on_idok(This);
2210 case IDCANCEL: return on_idcancel(This);
2211 case psh1: return on_command_opendropdown(This, wparam, lparam);
2212 case IDC_NAVBACK: return on_browse_back(This);
2213 case IDC_NAVFORWARD: return on_browse_forward(This);
2214 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
2215 default: TRACE("Unknown command.\n");
2217 return FALSE;
2220 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
2222 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
2224 switch(umessage)
2226 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
2227 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
2228 case WM_SIZE: return on_wm_size(This);
2229 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
2230 case WM_DESTROY: return on_wm_destroy(This);
2233 return FALSE;
2236 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
2238 INT_PTR res;
2240 SetLastError(0);
2241 res = DialogBoxParamW(COMDLG32_hInstance,
2242 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
2243 parent, itemdlg_dlgproc, (LPARAM)This);
2244 This->dlg_hwnd = NULL;
2245 if(res == -1)
2247 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
2248 return E_FAIL;
2251 TRACE("Returning 0x%08x\n", (HRESULT)res);
2252 return (HRESULT)res;
2255 /**************************************************************************
2256 * IFileDialog implementation
2258 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
2260 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
2263 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
2264 REFIID riid,
2265 void **ppvObject)
2267 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2268 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2270 *ppvObject = NULL;
2271 if(IsEqualGUID(riid, &IID_IUnknown) ||
2272 IsEqualGUID(riid, &IID_IFileDialog) ||
2273 IsEqualGUID(riid, &IID_IFileDialog2))
2275 *ppvObject = iface;
2277 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
2279 *ppvObject = &This->u.IFileOpenDialog_iface;
2281 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
2283 *ppvObject = &This->u.IFileSaveDialog_iface;
2285 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
2287 *ppvObject = &This->IExplorerBrowserEvents_iface;
2289 else if(IsEqualGUID(riid, &IID_IServiceProvider))
2291 *ppvObject = &This->IServiceProvider_iface;
2293 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
2294 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
2295 IsEqualGUID(&IID_ICommDlgBrowser, riid))
2297 *ppvObject = &This->ICommDlgBrowser3_iface;
2299 else if(IsEqualGUID(&IID_IOleWindow, riid))
2301 *ppvObject = &This->IOleWindow_iface;
2303 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
2304 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
2306 *ppvObject = &This->IFileDialogCustomize_iface;
2308 else
2309 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
2311 if(*ppvObject)
2313 IUnknown_AddRef((IUnknown*)*ppvObject);
2314 return S_OK;
2317 return E_NOINTERFACE;
2320 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
2322 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2323 LONG ref = InterlockedIncrement(&This->ref);
2324 TRACE("%p - ref %d\n", This, ref);
2326 return ref;
2329 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
2331 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2332 LONG ref = InterlockedDecrement(&This->ref);
2333 TRACE("%p - ref %d\n", This, ref);
2335 if(!ref)
2337 UINT i;
2338 for(i = 0; i < This->filterspec_count; i++)
2340 LocalFree((void*)This->filterspecs[i].pszName);
2341 LocalFree((void*)This->filterspecs[i].pszSpec);
2343 HeapFree(GetProcessHeap(), 0, This->filterspecs);
2345 DestroyWindow(This->cctrls_hwnd);
2347 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
2348 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
2349 if(This->psi_folder) IShellItem_Release(This->psi_folder);
2350 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
2351 if(This->psia_results) IShellItemArray_Release(This->psia_results);
2353 LocalFree(This->set_filename);
2354 LocalFree(This->default_ext);
2355 LocalFree(This->custom_title);
2356 LocalFree(This->custom_okbutton);
2357 LocalFree(This->custom_cancelbutton);
2358 LocalFree(This->custom_filenamelabel);
2360 DestroyMenu(This->hmenu_opendropdown);
2361 DeleteObject(This->hfont_opendropdown);
2363 HeapFree(GetProcessHeap(), 0, This);
2366 return ref;
2369 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
2371 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2372 TRACE("%p (%p)\n", iface, hwndOwner);
2374 This->opendropdown_has_selection = FALSE;
2376 return create_dialog(This, hwndOwner);
2379 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
2380 const COMDLG_FILTERSPEC *rgFilterSpec)
2382 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2383 UINT i;
2384 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
2386 if(This->filterspecs)
2387 return E_UNEXPECTED;
2389 if(!rgFilterSpec)
2390 return E_INVALIDARG;
2392 if(!cFileTypes)
2393 return S_OK;
2395 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
2396 for(i = 0; i < cFileTypes; i++)
2398 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
2399 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
2401 This->filterspec_count = cFileTypes;
2403 return S_OK;
2406 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
2408 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2409 TRACE("%p (%d)\n", This, iFileType);
2411 if(!This->filterspecs)
2412 return E_FAIL;
2414 iFileType = max(iFileType, 1);
2415 iFileType = min(iFileType, This->filterspec_count);
2416 This->filetypeindex = iFileType-1;
2418 return S_OK;
2421 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
2423 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2424 TRACE("%p (%p)\n", This, piFileType);
2426 if(!piFileType)
2427 return E_INVALIDARG;
2429 if(This->filterspec_count == 0)
2430 *piFileType = 0;
2431 else
2432 *piFileType = This->filetypeindex + 1;
2434 return S_OK;
2437 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
2439 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2440 events_client *client;
2441 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
2443 if(!pfde || !pdwCookie)
2444 return E_INVALIDARG;
2446 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
2447 client->pfde = pfde;
2448 client->cookie = ++This->events_next_cookie;
2450 IFileDialogEvents_AddRef(pfde);
2451 *pdwCookie = client->cookie;
2453 list_add_tail(&This->events_clients, &client->entry);
2455 return S_OK;
2458 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
2460 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2461 events_client *client, *found = NULL;
2462 TRACE("%p (%d)\n", This, dwCookie);
2464 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
2466 if(client->cookie == dwCookie)
2468 found = client;
2469 break;
2473 if(found)
2475 list_remove(&found->entry);
2476 IFileDialogEvents_Release(found->pfde);
2477 HeapFree(GetProcessHeap(), 0, found);
2478 return S_OK;
2481 return E_INVALIDARG;
2484 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
2486 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2487 TRACE("%p (0x%x)\n", This, fos);
2489 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
2491 WCHAR buf[30];
2492 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, sizeof(buf)/sizeof(WCHAR));
2493 IFileDialog2_SetTitle(iface, buf);
2496 This->options = fos;
2498 return S_OK;
2501 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
2503 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2504 TRACE("%p (%p)\n", This, pfos);
2506 if(!pfos)
2507 return E_INVALIDARG;
2509 *pfos = This->options;
2511 return S_OK;
2514 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
2516 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2517 TRACE("%p (%p)\n", This, psi);
2518 if(This->psi_defaultfolder)
2519 IShellItem_Release(This->psi_defaultfolder);
2521 This->psi_defaultfolder = psi;
2523 if(This->psi_defaultfolder)
2524 IShellItem_AddRef(This->psi_defaultfolder);
2526 return S_OK;
2529 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
2531 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2532 TRACE("%p (%p)\n", This, psi);
2533 if(This->psi_setfolder)
2534 IShellItem_Release(This->psi_setfolder);
2536 This->psi_setfolder = psi;
2538 if(This->psi_setfolder)
2539 IShellItem_AddRef(This->psi_setfolder);
2541 return S_OK;
2544 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
2546 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2547 TRACE("%p (%p)\n", This, ppsi);
2548 if(!ppsi)
2549 return E_INVALIDARG;
2551 /* FIXME:
2552 If the dialog is shown, return the current(ly selected) folder. */
2554 *ppsi = NULL;
2555 if(This->psi_folder)
2556 *ppsi = This->psi_folder;
2557 else if(This->psi_setfolder)
2558 *ppsi = This->psi_setfolder;
2559 else if(This->psi_defaultfolder)
2560 *ppsi = This->psi_defaultfolder;
2562 if(*ppsi)
2564 IShellItem_AddRef(*ppsi);
2565 return S_OK;
2568 return E_FAIL;
2571 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
2573 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2574 HRESULT hr;
2575 TRACE("%p (%p)\n", This, ppsi);
2577 if(!ppsi)
2578 return E_INVALIDARG;
2580 if(This->psia_selection)
2582 /* FIXME: Check filename edit box */
2583 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2584 return hr;
2587 return E_FAIL;
2590 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
2592 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2593 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2595 set_file_name(This, pszName);
2597 return S_OK;
2600 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
2602 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2603 TRACE("%p (%p)\n", iface, pszName);
2605 if(!pszName)
2606 return E_INVALIDARG;
2608 *pszName = NULL;
2609 get_file_name(This, pszName);
2610 return *pszName ? S_OK : E_FAIL;
2613 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
2615 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2616 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2618 LocalFree(This->custom_title);
2619 This->custom_title = StrDupW(pszTitle);
2620 update_control_text(This);
2622 return S_OK;
2625 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
2627 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2628 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2630 LocalFree(This->custom_okbutton);
2631 This->custom_okbutton = StrDupW(pszText);
2632 update_control_text(This);
2633 update_layout(This);
2635 return S_OK;
2638 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2640 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2641 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2643 LocalFree(This->custom_filenamelabel);
2644 This->custom_filenamelabel = StrDupW(pszLabel);
2645 update_control_text(This);
2646 update_layout(This);
2648 return S_OK;
2651 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
2653 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2654 HRESULT hr;
2655 TRACE("%p (%p)\n", This, ppsi);
2657 if(!ppsi)
2658 return E_INVALIDARG;
2660 if(This->psia_results)
2662 UINT item_count;
2663 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2664 if(SUCCEEDED(hr))
2666 if(item_count != 1)
2667 return E_FAIL;
2669 /* Adds a reference. */
2670 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2673 return hr;
2676 return E_UNEXPECTED;
2679 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2681 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2682 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2683 return S_OK;
2686 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2688 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2689 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2691 LocalFree(This->default_ext);
2692 This->default_ext = StrDupW(pszDefaultExtension);
2694 return S_OK;
2697 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2699 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2700 TRACE("%p (0x%08x)\n", This, hr);
2702 if(This->dlg_hwnd)
2703 EndDialog(This->dlg_hwnd, hr);
2705 return S_OK;
2708 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2710 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2711 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2712 This->client_guid = *guid;
2713 return S_OK;
2716 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2718 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2719 FIXME("stub - %p\n", This);
2720 return E_NOTIMPL;
2723 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2725 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2726 FIXME("stub - %p (%p)\n", This, pFilter);
2727 return E_NOTIMPL;
2730 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2732 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2733 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2735 LocalFree(This->custom_cancelbutton);
2736 This->custom_cancelbutton = StrDupW(pszLabel);
2737 update_control_text(This);
2738 update_layout(This);
2740 return S_OK;
2743 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2745 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2746 FIXME("stub - %p (%p)\n", This, psi);
2747 return E_NOTIMPL;
2750 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2751 IFileDialog2_fnQueryInterface,
2752 IFileDialog2_fnAddRef,
2753 IFileDialog2_fnRelease,
2754 IFileDialog2_fnShow,
2755 IFileDialog2_fnSetFileTypes,
2756 IFileDialog2_fnSetFileTypeIndex,
2757 IFileDialog2_fnGetFileTypeIndex,
2758 IFileDialog2_fnAdvise,
2759 IFileDialog2_fnUnadvise,
2760 IFileDialog2_fnSetOptions,
2761 IFileDialog2_fnGetOptions,
2762 IFileDialog2_fnSetDefaultFolder,
2763 IFileDialog2_fnSetFolder,
2764 IFileDialog2_fnGetFolder,
2765 IFileDialog2_fnGetCurrentSelection,
2766 IFileDialog2_fnSetFileName,
2767 IFileDialog2_fnGetFileName,
2768 IFileDialog2_fnSetTitle,
2769 IFileDialog2_fnSetOkButtonLabel,
2770 IFileDialog2_fnSetFileNameLabel,
2771 IFileDialog2_fnGetResult,
2772 IFileDialog2_fnAddPlace,
2773 IFileDialog2_fnSetDefaultExtension,
2774 IFileDialog2_fnClose,
2775 IFileDialog2_fnSetClientGuid,
2776 IFileDialog2_fnClearClientData,
2777 IFileDialog2_fnSetFilter,
2778 IFileDialog2_fnSetCancelButtonLabel,
2779 IFileDialog2_fnSetNavigationRoot
2782 /**************************************************************************
2783 * IFileOpenDialog
2785 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2787 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2790 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2791 REFIID riid, void **ppvObject)
2793 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2794 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2797 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2799 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2800 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2803 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2805 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2806 return IFileDialog2_Release(&This->IFileDialog2_iface);
2809 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2811 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2812 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2815 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2816 const COMDLG_FILTERSPEC *rgFilterSpec)
2818 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2819 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2822 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2824 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2825 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2828 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2830 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2831 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2834 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2835 DWORD *pdwCookie)
2837 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2838 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2841 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2843 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2844 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2847 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2849 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2850 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2853 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2855 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2856 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2859 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2861 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2862 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2865 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2867 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2868 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2871 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2873 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2874 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2877 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2879 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2880 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2883 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2885 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2886 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2889 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2891 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2892 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2895 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2897 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2898 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2901 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2903 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2904 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2907 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2909 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2910 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2913 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2915 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2916 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2919 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2921 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2922 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2925 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2926 LPCWSTR pszDefaultExtension)
2928 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2929 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2932 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2934 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2935 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2938 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2940 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2941 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2944 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2946 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2947 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2950 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2952 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2953 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2956 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2958 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2959 TRACE("%p (%p)\n", This, ppenum);
2961 *ppenum = This->psia_results;
2963 if(*ppenum)
2965 IShellItemArray_AddRef(*ppenum);
2966 return S_OK;
2969 return E_FAIL;
2972 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2974 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2975 TRACE("%p (%p)\n", This, ppsai);
2977 if(This->psia_selection)
2979 *ppsai = This->psia_selection;
2980 IShellItemArray_AddRef(*ppsai);
2981 return S_OK;
2984 return E_FAIL;
2987 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2988 IFileOpenDialog_fnQueryInterface,
2989 IFileOpenDialog_fnAddRef,
2990 IFileOpenDialog_fnRelease,
2991 IFileOpenDialog_fnShow,
2992 IFileOpenDialog_fnSetFileTypes,
2993 IFileOpenDialog_fnSetFileTypeIndex,
2994 IFileOpenDialog_fnGetFileTypeIndex,
2995 IFileOpenDialog_fnAdvise,
2996 IFileOpenDialog_fnUnadvise,
2997 IFileOpenDialog_fnSetOptions,
2998 IFileOpenDialog_fnGetOptions,
2999 IFileOpenDialog_fnSetDefaultFolder,
3000 IFileOpenDialog_fnSetFolder,
3001 IFileOpenDialog_fnGetFolder,
3002 IFileOpenDialog_fnGetCurrentSelection,
3003 IFileOpenDialog_fnSetFileName,
3004 IFileOpenDialog_fnGetFileName,
3005 IFileOpenDialog_fnSetTitle,
3006 IFileOpenDialog_fnSetOkButtonLabel,
3007 IFileOpenDialog_fnSetFileNameLabel,
3008 IFileOpenDialog_fnGetResult,
3009 IFileOpenDialog_fnAddPlace,
3010 IFileOpenDialog_fnSetDefaultExtension,
3011 IFileOpenDialog_fnClose,
3012 IFileOpenDialog_fnSetClientGuid,
3013 IFileOpenDialog_fnClearClientData,
3014 IFileOpenDialog_fnSetFilter,
3015 IFileOpenDialog_fnGetResults,
3016 IFileOpenDialog_fnGetSelectedItems
3019 /**************************************************************************
3020 * IFileSaveDialog
3022 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
3024 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
3027 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
3028 REFIID riid,
3029 void **ppvObject)
3031 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3032 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3035 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
3037 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3038 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3041 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
3043 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3044 return IFileDialog2_Release(&This->IFileDialog2_iface);
3047 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
3049 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3050 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
3053 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
3054 const COMDLG_FILTERSPEC *rgFilterSpec)
3056 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3057 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
3060 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
3062 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3063 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
3066 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
3068 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3069 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
3072 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
3073 DWORD *pdwCookie)
3075 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3076 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
3079 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
3081 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3082 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
3085 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
3087 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3088 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
3091 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
3093 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3094 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
3097 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
3099 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3100 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
3103 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
3105 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3106 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
3109 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
3111 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3112 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
3115 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
3117 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3118 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
3121 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
3123 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3124 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
3127 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
3129 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3130 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
3133 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
3135 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3136 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
3139 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
3141 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3142 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
3145 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
3147 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3148 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
3151 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
3153 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3154 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
3157 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
3159 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3160 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
3163 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
3164 LPCWSTR pszDefaultExtension)
3166 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3167 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
3170 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
3172 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3173 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
3176 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
3178 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3179 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
3182 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
3184 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3185 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
3188 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
3190 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3191 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
3194 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
3196 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3197 FIXME("stub - %p (%p)\n", This, psi);
3198 return E_NOTIMPL;
3201 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
3203 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3204 FIXME("stub - %p (%p)\n", This, pStore);
3205 return E_NOTIMPL;
3208 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
3209 IPropertyDescriptionList *pList,
3210 BOOL fAppendDefault)
3212 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3213 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
3214 return E_NOTIMPL;
3217 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
3219 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3220 FIXME("stub - %p (%p)\n", This, ppStore);
3221 return E_NOTIMPL;
3224 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
3225 IShellItem *psi,
3226 IPropertyStore *pStore,
3227 HWND hwnd,
3228 IFileOperationProgressSink *pSink)
3230 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3231 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
3232 return E_NOTIMPL;
3235 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
3236 IFileSaveDialog_fnQueryInterface,
3237 IFileSaveDialog_fnAddRef,
3238 IFileSaveDialog_fnRelease,
3239 IFileSaveDialog_fnShow,
3240 IFileSaveDialog_fnSetFileTypes,
3241 IFileSaveDialog_fnSetFileTypeIndex,
3242 IFileSaveDialog_fnGetFileTypeIndex,
3243 IFileSaveDialog_fnAdvise,
3244 IFileSaveDialog_fnUnadvise,
3245 IFileSaveDialog_fnSetOptions,
3246 IFileSaveDialog_fnGetOptions,
3247 IFileSaveDialog_fnSetDefaultFolder,
3248 IFileSaveDialog_fnSetFolder,
3249 IFileSaveDialog_fnGetFolder,
3250 IFileSaveDialog_fnGetCurrentSelection,
3251 IFileSaveDialog_fnSetFileName,
3252 IFileSaveDialog_fnGetFileName,
3253 IFileSaveDialog_fnSetTitle,
3254 IFileSaveDialog_fnSetOkButtonLabel,
3255 IFileSaveDialog_fnSetFileNameLabel,
3256 IFileSaveDialog_fnGetResult,
3257 IFileSaveDialog_fnAddPlace,
3258 IFileSaveDialog_fnSetDefaultExtension,
3259 IFileSaveDialog_fnClose,
3260 IFileSaveDialog_fnSetClientGuid,
3261 IFileSaveDialog_fnClearClientData,
3262 IFileSaveDialog_fnSetFilter,
3263 IFileSaveDialog_fnSetSaveAsItem,
3264 IFileSaveDialog_fnSetProperties,
3265 IFileSaveDialog_fnSetCollectedProperties,
3266 IFileSaveDialog_fnGetProperties,
3267 IFileSaveDialog_fnApplyProperties
3270 /**************************************************************************
3271 * IExplorerBrowserEvents implementation
3273 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
3275 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
3278 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
3279 REFIID riid, void **ppvObject)
3281 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3282 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
3284 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3287 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
3289 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3290 TRACE("%p\n", This);
3291 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3294 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
3296 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3297 TRACE("%p\n", This);
3298 return IFileDialog2_Release(&This->IFileDialog2_iface);
3301 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
3302 PCIDLIST_ABSOLUTE pidlFolder)
3304 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3305 IShellItem *psi;
3306 HRESULT hr;
3307 TRACE("%p (%p)\n", This, pidlFolder);
3309 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
3310 if(SUCCEEDED(hr))
3312 hr = events_OnFolderChanging(This, psi);
3313 IShellItem_Release(psi);
3315 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
3316 if(hr == S_FALSE)
3317 hr = E_FAIL;
3319 return hr;
3321 else
3322 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
3324 return S_OK;
3327 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
3328 IShellView *psv)
3330 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3331 TRACE("%p (%p)\n", This, psv);
3332 return S_OK;
3335 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
3336 PCIDLIST_ABSOLUTE pidlFolder)
3338 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3339 HRESULT hr;
3340 TRACE("%p (%p)\n", This, pidlFolder);
3342 if(This->psi_folder)
3343 IShellItem_Release(This->psi_folder);
3345 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
3346 if(FAILED(hr))
3348 ERR("Failed to get the current folder.\n");
3349 This->psi_folder = NULL;
3352 events_OnFolderChange(This);
3354 return S_OK;
3357 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
3358 PCIDLIST_ABSOLUTE pidlFolder)
3360 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3361 TRACE("%p (%p)\n", This, pidlFolder);
3362 return S_OK;
3365 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
3366 IExplorerBrowserEvents_fnQueryInterface,
3367 IExplorerBrowserEvents_fnAddRef,
3368 IExplorerBrowserEvents_fnRelease,
3369 IExplorerBrowserEvents_fnOnNavigationPending,
3370 IExplorerBrowserEvents_fnOnViewCreated,
3371 IExplorerBrowserEvents_fnOnNavigationComplete,
3372 IExplorerBrowserEvents_fnOnNavigationFailed
3375 /**************************************************************************
3376 * IServiceProvider implementation
3378 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
3380 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
3383 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
3384 REFIID riid, void **ppvObject)
3386 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3387 TRACE("%p\n", This);
3388 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3391 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
3393 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3394 TRACE("%p\n", This);
3395 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3398 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
3400 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3401 TRACE("%p\n", This);
3402 return IFileDialog2_Release(&This->IFileDialog2_iface);
3405 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
3406 REFGUID guidService,
3407 REFIID riid, void **ppv)
3409 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3410 HRESULT hr = E_NOTIMPL;
3411 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
3413 *ppv = NULL;
3414 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
3415 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
3416 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
3417 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
3418 else
3419 FIXME("Interface %s requested from unknown service %s\n",
3420 debugstr_guid(riid), debugstr_guid(guidService));
3422 return hr;
3425 static const IServiceProviderVtbl vt_IServiceProvider = {
3426 IServiceProvider_fnQueryInterface,
3427 IServiceProvider_fnAddRef,
3428 IServiceProvider_fnRelease,
3429 IServiceProvider_fnQueryService
3432 /**************************************************************************
3433 * ICommDlgBrowser3 implementation
3435 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
3437 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
3440 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
3441 REFIID riid, void **ppvObject)
3443 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3444 TRACE("%p\n", This);
3445 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3448 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
3450 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3451 TRACE("%p\n", This);
3452 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3455 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
3457 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3458 TRACE("%p\n", This);
3459 return IFileDialog2_Release(&This->IFileDialog2_iface);
3462 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
3463 IShellView *shv)
3465 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3466 HRESULT hr;
3467 TRACE("%p (%p)\n", This, shv);
3469 hr = on_default_action(This);
3471 if(SUCCEEDED(hr))
3472 EndDialog(This->dlg_hwnd, S_OK);
3474 return S_OK;
3477 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
3478 IShellView *shv, ULONG uChange )
3480 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3481 IDataObject *new_selection;
3482 HRESULT hr;
3483 TRACE("%p (%p, %x)\n", This, shv, uChange);
3485 switch(uChange)
3487 case CDBOSC_SELCHANGE:
3488 if(This->psia_selection)
3490 IShellItemArray_Release(This->psia_selection);
3491 This->psia_selection = NULL;
3494 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
3495 if(SUCCEEDED(hr))
3497 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
3498 (void**)&This->psia_selection);
3499 if(SUCCEEDED(hr))
3501 fill_filename_from_selection(This);
3502 events_OnSelectionChange(This);
3505 IDataObject_Release(new_selection);
3507 break;
3508 default:
3509 TRACE("Unhandled state change\n");
3511 return S_OK;
3514 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
3515 IShellView *shv, LPCITEMIDLIST pidl)
3517 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3518 IShellItem *psi;
3519 LPWSTR filename;
3520 LPITEMIDLIST parent_pidl;
3521 HRESULT hr;
3522 ULONG attr;
3523 TRACE("%p (%p, %p)\n", This, shv, pidl);
3525 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
3526 return S_OK;
3528 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3529 if(SUCCEEDED(hr))
3531 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3532 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3533 ILFree(parent_pidl);
3534 ILFree(full_pidl);
3536 if(FAILED(hr))
3538 ERR("Failed to get shellitem (%08x).\n", hr);
3539 return S_OK;
3542 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3543 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3545 IShellItem_Release(psi);
3546 return S_OK;
3549 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
3551 IShellItem_Release(psi);
3552 return S_FALSE;
3555 hr = S_OK;
3556 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
3558 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
3559 hr = S_FALSE;
3560 CoTaskMemFree(filename);
3563 IShellItem_Release(psi);
3564 return hr;
3567 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
3568 IShellView *ppshv, DWORD dwNotifyType)
3570 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3571 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
3572 return E_NOTIMPL;
3575 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
3576 IShellView *pshv,
3577 LPWSTR pszText, int cchMax)
3579 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3580 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
3581 return E_NOTIMPL;
3584 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
3586 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3587 FIXME("Stub: %p (%p)\n", This, pdwFlags);
3588 return E_NOTIMPL;
3591 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
3592 IShellView *pshv, int iColumn)
3594 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3595 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
3596 return E_NOTIMPL;
3599 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
3600 LPWSTR pszFileSpec, int cchFileSpec)
3602 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3603 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
3604 return E_NOTIMPL;
3607 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
3608 IShellView *pshv)
3610 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3611 FIXME("Stub: %p (%p)\n", This, pshv);
3612 return E_NOTIMPL;
3615 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
3616 ICommDlgBrowser3_fnQueryInterface,
3617 ICommDlgBrowser3_fnAddRef,
3618 ICommDlgBrowser3_fnRelease,
3619 ICommDlgBrowser3_fnOnDefaultCommand,
3620 ICommDlgBrowser3_fnOnStateChange,
3621 ICommDlgBrowser3_fnIncludeObject,
3622 ICommDlgBrowser3_fnNotify,
3623 ICommDlgBrowser3_fnGetDefaultMenuText,
3624 ICommDlgBrowser3_fnGetViewFlags,
3625 ICommDlgBrowser3_fnOnColumnClicked,
3626 ICommDlgBrowser3_fnGetCurrentFilter,
3627 ICommDlgBrowser3_fnOnPreviewCreated
3630 /**************************************************************************
3631 * IOleWindow implementation
3633 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
3635 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
3638 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
3640 FileDialogImpl *This = impl_from_IOleWindow(iface);
3641 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3644 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
3646 FileDialogImpl *This = impl_from_IOleWindow(iface);
3647 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3650 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
3652 FileDialogImpl *This = impl_from_IOleWindow(iface);
3653 return IFileDialog2_Release(&This->IFileDialog2_iface);
3656 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
3658 FileDialogImpl *This = impl_from_IOleWindow(iface);
3659 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
3660 return E_NOTIMPL;
3663 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
3665 FileDialogImpl *This = impl_from_IOleWindow(iface);
3666 TRACE("%p (%p)\n", This, phwnd);
3667 *phwnd = This->dlg_hwnd;
3668 return S_OK;
3671 static const IOleWindowVtbl vt_IOleWindow = {
3672 IOleWindow_fnQueryInterface,
3673 IOleWindow_fnAddRef,
3674 IOleWindow_fnRelease,
3675 IOleWindow_fnGetWindow,
3676 IOleWindow_fnContextSensitiveHelp
3679 /**************************************************************************
3680 * IFileDialogCustomize implementation
3682 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3684 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3687 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3688 REFIID riid, void **ppvObject)
3690 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3691 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3694 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3696 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3697 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3700 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3702 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3703 return IFileDialog2_Release(&This->IFileDialog2_iface);
3706 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3707 DWORD dwIDCtl)
3709 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3710 MENUINFO mi;
3711 TRACE("%p (%d)\n", This, dwIDCtl);
3713 if (This->hmenu_opendropdown || get_cctrl(This, dwIDCtl))
3714 return E_UNEXPECTED;
3716 This->hmenu_opendropdown = CreatePopupMenu();
3718 if (!This->hmenu_opendropdown)
3719 return E_OUTOFMEMORY;
3721 mi.cbSize = sizeof(mi);
3722 mi.fMask = MIM_STYLE;
3723 mi.dwStyle = MNS_NOTIFYBYPOS;
3724 SetMenuInfo(This->hmenu_opendropdown, &mi);
3726 This->cctrl_opendropdown.hwnd = NULL;
3727 This->cctrl_opendropdown.wrapper_hwnd = NULL;
3728 This->cctrl_opendropdown.id = dwIDCtl;
3729 This->cctrl_opendropdown.dlgid = 0;
3730 This->cctrl_opendropdown.type = IDLG_CCTRL_OPENDROPDOWN;
3731 This->cctrl_opendropdown.cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
3732 list_init(&This->cctrl_opendropdown.sub_cctrls);
3733 list_init(&This->cctrl_opendropdown.sub_items);
3735 return S_OK;
3738 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3739 DWORD dwIDCtl,
3740 LPCWSTR pszLabel)
3742 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3743 customctrl *ctrl;
3744 TBBUTTON tbb;
3745 HRESULT hr;
3746 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3748 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3749 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3750 This->cctrl_def_height, &ctrl);
3751 if(SUCCEEDED(hr))
3753 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3754 ctrl->type = IDLG_CCTRL_MENU;
3756 /* Add the actual button with a popup menu. */
3757 tbb.iBitmap = I_IMAGENONE;
3758 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3759 tbb.iString = (DWORD_PTR)pszLabel;
3760 tbb.fsState = TBSTATE_ENABLED;
3761 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3762 tbb.idCommand = 1;
3764 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3767 return hr;
3770 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3771 DWORD dwIDCtl,
3772 LPCWSTR pszLabel)
3774 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3775 customctrl *ctrl;
3776 HRESULT hr;
3777 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3779 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3780 This->cctrl_def_height, &ctrl);
3781 if(SUCCEEDED(hr))
3782 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3784 return hr;
3787 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3788 DWORD dwIDCtl)
3790 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3791 customctrl *ctrl;
3792 HRESULT hr;
3793 TRACE("%p (%d)\n", This, dwIDCtl);
3795 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3796 This->cctrl_def_height, &ctrl);
3797 if(SUCCEEDED(hr))
3798 ctrl->type = IDLG_CCTRL_COMBOBOX;
3800 return hr;
3803 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3804 DWORD dwIDCtl)
3806 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3807 customctrl *ctrl;
3808 HRESULT hr;
3809 TRACE("%p (%d)\n", This, dwIDCtl);
3811 hr = cctrl_create_new(This, dwIDCtl, NULL, radiobuttonlistW, 0, 0, 0, &ctrl);
3812 if(SUCCEEDED(hr))
3814 ctrl->type = IDLG_CCTRL_RADIOBUTTONLIST;
3815 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)This);
3818 return hr;
3821 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3822 DWORD dwIDCtl,
3823 LPCWSTR pszLabel,
3824 BOOL bChecked)
3826 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3827 customctrl *ctrl;
3828 HRESULT hr;
3829 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3831 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0,
3832 This->cctrl_def_height, &ctrl);
3833 if(SUCCEEDED(hr))
3835 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3836 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3839 return hr;
3842 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3843 DWORD dwIDCtl,
3844 LPCWSTR pszText)
3846 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3847 customctrl *ctrl;
3848 HRESULT hr;
3849 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3851 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3852 This->cctrl_def_height, &ctrl);
3853 if(SUCCEEDED(hr))
3854 ctrl->type = IDLG_CCTRL_EDITBOX;
3856 return hr;
3859 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3860 DWORD dwIDCtl)
3862 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3863 customctrl *ctrl;
3864 HRESULT hr;
3865 TRACE("%p (%d)\n", This, dwIDCtl);
3867 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3868 GetSystemMetrics(SM_CYEDGE), &ctrl);
3869 if(SUCCEEDED(hr))
3870 ctrl->type = IDLG_CCTRL_SEPARATOR;
3872 return hr;
3875 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3876 DWORD dwIDCtl,
3877 LPCWSTR pszText)
3879 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3880 customctrl *ctrl;
3881 HRESULT hr;
3882 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3884 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3885 This->cctrl_def_height, &ctrl);
3886 if(SUCCEEDED(hr))
3887 ctrl->type = IDLG_CCTRL_TEXT;
3889 return hr;
3892 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3893 DWORD dwIDCtl,
3894 LPCWSTR pszLabel)
3896 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3897 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3898 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3900 if(!ctrl) return E_INVALIDARG;
3902 switch(ctrl->type)
3904 case IDLG_CCTRL_MENU:
3905 case IDLG_CCTRL_PUSHBUTTON:
3906 case IDLG_CCTRL_CHECKBUTTON:
3907 case IDLG_CCTRL_TEXT:
3908 case IDLG_CCTRL_VISUALGROUP:
3909 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3910 break;
3911 case IDLG_CCTRL_OPENDROPDOWN:
3912 return E_NOTIMPL;
3913 default:
3914 break;
3917 return S_OK;
3920 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3921 DWORD dwIDCtl,
3922 CDCONTROLSTATEF *pdwState)
3924 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3925 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3926 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3928 if(!ctrl || ctrl->type == IDLG_CCTRL_OPENDROPDOWN) return E_NOTIMPL;
3930 *pdwState = ctrl->cdcstate;
3931 return S_OK;
3934 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3935 DWORD dwIDCtl,
3936 CDCONTROLSTATEF dwState)
3938 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3939 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3940 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3942 if(ctrl && ctrl->hwnd)
3944 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3946 if(dwState & CDCS_ENABLED)
3947 wndstyle &= ~(WS_DISABLED);
3948 else
3949 wndstyle |= WS_DISABLED;
3951 if(dwState & CDCS_VISIBLE)
3952 wndstyle |= WS_VISIBLE;
3953 else
3954 wndstyle &= ~(WS_VISIBLE);
3956 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3958 /* We save the state separately since at least one application
3959 * relies on being able to hide a control. */
3960 ctrl->cdcstate = dwState;
3963 return S_OK;
3966 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3967 DWORD dwIDCtl,
3968 WCHAR **ppszText)
3970 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3971 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3972 WCHAR len, *text;
3973 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
3975 if(!ctrl || !ctrl->hwnd || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3976 return E_FAIL;
3978 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3979 if(!text) return E_FAIL;
3981 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3982 *ppszText = text;
3983 return S_OK;
3986 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
3987 DWORD dwIDCtl,
3988 LPCWSTR pszText)
3990 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3991 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3992 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
3994 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
3995 return E_FAIL;
3997 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
3998 return S_OK;
4001 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
4002 DWORD dwIDCtl,
4003 BOOL *pbChecked)
4005 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4006 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4007 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
4009 if(ctrl && ctrl->hwnd)
4010 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
4012 return S_OK;
4015 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
4016 DWORD dwIDCtl,
4017 BOOL bChecked)
4019 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4020 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4021 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
4023 if(ctrl && ctrl->hwnd)
4024 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
4026 return S_OK;
4029 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
4031 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
4032 UINT i;
4033 if(!count || (count == CB_ERR))
4034 return -1;
4036 for(i = 0; i < count; i++)
4037 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
4038 return i;
4040 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
4041 return -1;
4044 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
4045 DWORD dwIDCtl,
4046 DWORD dwIDItem,
4047 LPCWSTR pszLabel)
4049 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4050 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4051 HRESULT hr;
4052 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4054 if(!ctrl) return E_FAIL;
4056 switch(ctrl->type)
4058 case IDLG_CCTRL_COMBOBOX:
4060 UINT index;
4061 cctrl_item* item;
4063 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4065 if (FAILED(hr)) return hr;
4067 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
4068 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
4070 return S_OK;
4072 case IDLG_CCTRL_MENU:
4073 case IDLG_CCTRL_OPENDROPDOWN:
4075 cctrl_item* item;
4076 HMENU hmenu;
4078 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4080 if (FAILED(hr)) return hr;
4082 if (ctrl->type == IDLG_CCTRL_MENU)
4084 TBBUTTON tbb;
4085 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4086 hmenu = (HMENU)tbb.dwData;
4088 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4089 hmenu = This->hmenu_opendropdown;
4091 AppendMenuW(hmenu, MF_STRING, dwIDItem, pszLabel);
4092 return S_OK;
4094 case IDLG_CCTRL_RADIOBUTTONLIST:
4096 cctrl_item* item;
4098 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4100 if (SUCCEEDED(hr))
4102 item->hwnd = CreateWindowExW(0, WC_BUTTONW, pszLabel,
4103 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|BS_RADIOBUTTON|BS_MULTILINE,
4104 0, 0, 0, 0, ctrl->hwnd, ULongToHandle(dwIDItem), COMDLG32_hInstance, 0);
4106 if (!item->hwnd)
4108 ERR("Failed to create radio button\n");
4109 list_remove(&item->entry);
4110 item_free(item);
4111 return E_FAIL;
4115 return hr;
4117 default:
4118 break;
4121 return E_NOINTERFACE; /* win7 */
4124 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
4125 DWORD dwIDCtl,
4126 DWORD dwIDItem)
4128 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4129 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4130 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
4132 if(!ctrl) return E_FAIL;
4134 switch(ctrl->type)
4136 case IDLG_CCTRL_COMBOBOX:
4138 cctrl_item* item;
4139 DWORD position;
4141 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4143 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
4145 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0) == CB_ERR)
4146 return E_FAIL;
4149 list_remove(&item->entry);
4150 item_free(item);
4152 return S_OK;
4154 case IDLG_CCTRL_MENU:
4155 case IDLG_CCTRL_OPENDROPDOWN:
4157 HMENU hmenu;
4158 cctrl_item* item;
4160 item = get_item(ctrl, dwIDItem, 0, NULL);
4162 if (!item)
4163 return E_UNEXPECTED;
4165 if (item->cdcstate & CDCS_VISIBLE)
4167 if (ctrl->type == IDLG_CCTRL_MENU)
4169 TBBUTTON tbb;
4170 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4171 hmenu = (HMENU)tbb.dwData;
4173 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4174 hmenu = This->hmenu_opendropdown;
4176 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
4177 return E_UNEXPECTED;
4180 list_remove(&item->entry);
4181 item_free(item);
4183 return S_OK;
4185 case IDLG_CCTRL_RADIOBUTTONLIST:
4187 cctrl_item* item;
4189 item = get_item(ctrl, dwIDItem, 0, NULL);
4191 if (!item)
4192 return E_UNEXPECTED;
4194 list_remove(&item->entry);
4195 item_free(item);
4197 return S_OK;
4199 default:
4200 break;
4203 return E_FAIL;
4206 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
4207 DWORD dwIDCtl)
4209 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4210 TRACE("%p (%d)\n", This, dwIDCtl);
4212 /* Not implemented by native */
4213 return E_NOTIMPL;
4216 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
4217 DWORD dwIDCtl,
4218 DWORD dwIDItem,
4219 CDCONTROLSTATEF *pdwState)
4221 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4222 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4223 TRACE("%p (%d, %d, %p)\n", This, dwIDCtl, dwIDItem, pdwState);
4225 if(!ctrl) return E_FAIL;
4227 switch(ctrl->type)
4229 case IDLG_CCTRL_COMBOBOX:
4230 case IDLG_CCTRL_MENU:
4231 case IDLG_CCTRL_OPENDROPDOWN:
4232 case IDLG_CCTRL_RADIOBUTTONLIST:
4234 cctrl_item* item;
4236 item = get_item(ctrl, dwIDItem, 0, NULL);
4238 if (!item)
4239 return E_UNEXPECTED;
4241 *pdwState = item->cdcstate;
4243 return S_OK;
4245 default:
4246 break;
4249 return E_FAIL;
4252 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
4253 DWORD dwIDCtl,
4254 DWORD dwIDItem,
4255 CDCONTROLSTATEF dwState)
4257 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4258 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4259 TRACE("%p (%d, %d, %x)\n", This, dwIDCtl, dwIDItem, dwState);
4261 if(!ctrl) return E_FAIL;
4263 switch(ctrl->type)
4265 case IDLG_CCTRL_COMBOBOX:
4267 cctrl_item* item;
4268 BOOL visible, was_visible;
4269 DWORD position;
4271 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4273 if (!item)
4274 return E_UNEXPECTED;
4276 visible = ((dwState & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4277 was_visible = ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4279 if (visible && !was_visible)
4281 SendMessageW(ctrl->hwnd, CB_INSERTSTRING, position, (LPARAM)item->label);
4282 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, position, dwIDItem);
4284 else if (!visible && was_visible)
4286 SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0);
4289 item->cdcstate = dwState;
4291 return S_OK;
4293 case IDLG_CCTRL_MENU:
4294 case IDLG_CCTRL_OPENDROPDOWN:
4296 HMENU hmenu;
4297 cctrl_item* item;
4298 CDCONTROLSTATEF prev_state;
4299 DWORD position;
4301 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, &position);
4303 if (!item)
4304 return E_UNEXPECTED;
4306 prev_state = item->cdcstate;
4308 if (ctrl->type == IDLG_CCTRL_MENU)
4310 TBBUTTON tbb;
4311 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4312 hmenu = (HMENU)tbb.dwData;
4314 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4315 hmenu = This->hmenu_opendropdown;
4317 if (dwState & CDCS_VISIBLE)
4319 if (prev_state & CDCS_VISIBLE)
4321 /* change state */
4322 EnableMenuItem(hmenu, dwIDItem,
4323 MF_BYCOMMAND|((dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED));
4325 else
4327 /* show item */
4328 MENUITEMINFOW mii;
4330 mii.cbSize = sizeof(mii);
4331 mii.fMask = MIIM_ID|MIIM_STATE|MIIM_STRING;
4332 mii.fState = (dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED;
4333 mii.wID = dwIDItem;
4334 mii.dwTypeData = item->label;
4336 InsertMenuItemW(hmenu, position, TRUE, &mii);
4339 else if (prev_state & CDCS_VISIBLE)
4341 /* hide item */
4342 DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND);
4345 item->cdcstate = dwState;
4347 if (ctrl->type == IDLG_CCTRL_OPENDROPDOWN)
4349 update_control_text(This);
4350 update_layout(This);
4353 return S_OK;
4355 case IDLG_CCTRL_RADIOBUTTONLIST:
4357 cctrl_item* item;
4359 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, NULL);
4361 if (!item)
4362 return E_UNEXPECTED;
4364 /* Oddly, native allows setting this but doesn't seem to do anything with it. */
4365 item->cdcstate = dwState;
4367 return S_OK;
4369 default:
4370 break;
4373 return E_FAIL;
4376 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
4377 DWORD dwIDCtl,
4378 DWORD *pdwIDItem)
4380 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4381 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4382 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
4384 if(!ctrl) return E_FAIL;
4386 switch(ctrl->type)
4388 case IDLG_CCTRL_COMBOBOX:
4390 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
4391 if(index == CB_ERR)
4392 return E_FAIL;
4394 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
4395 return S_OK;
4397 case IDLG_CCTRL_OPENDROPDOWN:
4398 if (This->opendropdown_has_selection)
4400 *pdwIDItem = This->opendropdown_selection;
4401 return S_OK;
4403 else
4405 /* Return first enabled item. */
4406 cctrl_item* item = get_first_item(ctrl);
4408 if (item)
4410 *pdwIDItem = item->id;
4411 return S_OK;
4414 WARN("no enabled items in open dropdown\n");
4415 return E_FAIL;
4417 case IDLG_CCTRL_RADIOBUTTONLIST:
4419 cctrl_item* item;
4421 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
4423 if (SendMessageW(item->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED)
4425 *pdwIDItem = item->id;
4426 return S_OK;
4430 WARN("no checked items in radio button list\n");
4431 return E_FAIL;
4433 default:
4434 FIXME("Unsupported control type %d\n", ctrl->type);
4437 return E_NOTIMPL;
4440 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
4441 DWORD dwIDCtl,
4442 DWORD dwIDItem)
4444 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4445 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4446 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
4448 if(!ctrl) return E_INVALIDARG;
4450 switch(ctrl->type)
4452 case IDLG_CCTRL_COMBOBOX:
4454 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
4456 if(index == -1)
4457 return E_INVALIDARG;
4459 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
4460 return E_FAIL;
4462 return S_OK;
4464 case IDLG_CCTRL_RADIOBUTTONLIST:
4466 cctrl_item* item;
4468 item = get_item(ctrl, dwIDItem, 0, NULL);
4470 if (item)
4472 radiobuttonlist_set_selected_item(This, ctrl, item);
4473 return S_OK;
4476 return E_INVALIDARG;
4478 default:
4479 FIXME("Unsupported control type %d\n", ctrl->type);
4482 return E_INVALIDARG;
4485 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
4486 DWORD dwIDCtl,
4487 LPCWSTR pszLabel)
4489 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4490 customctrl *vg;
4491 HRESULT hr;
4492 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
4494 if(This->cctrl_active_vg)
4495 return E_UNEXPECTED;
4497 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0,
4498 This->cctrl_def_height, &vg);
4499 if(SUCCEEDED(hr))
4501 vg->type = IDLG_CCTRL_VISUALGROUP;
4502 This->cctrl_active_vg = vg;
4505 return hr;
4508 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
4510 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4511 TRACE("%p\n", This);
4513 This->cctrl_active_vg = NULL;
4515 return S_OK;
4518 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
4519 DWORD dwIDCtl)
4521 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4522 FIXME("stub - %p (%d)\n", This, dwIDCtl);
4523 return S_OK;
4526 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
4527 DWORD dwIDCtl,
4528 DWORD dwIDItem,
4529 LPCWSTR pszLabel)
4531 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4532 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4533 return E_NOTIMPL;
4536 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
4537 IFileDialogCustomize_fnQueryInterface,
4538 IFileDialogCustomize_fnAddRef,
4539 IFileDialogCustomize_fnRelease,
4540 IFileDialogCustomize_fnEnableOpenDropDown,
4541 IFileDialogCustomize_fnAddMenu,
4542 IFileDialogCustomize_fnAddPushButton,
4543 IFileDialogCustomize_fnAddComboBox,
4544 IFileDialogCustomize_fnAddRadioButtonList,
4545 IFileDialogCustomize_fnAddCheckButton,
4546 IFileDialogCustomize_fnAddEditBox,
4547 IFileDialogCustomize_fnAddSeparator,
4548 IFileDialogCustomize_fnAddText,
4549 IFileDialogCustomize_fnSetControlLabel,
4550 IFileDialogCustomize_fnGetControlState,
4551 IFileDialogCustomize_fnSetControlState,
4552 IFileDialogCustomize_fnGetEditBoxText,
4553 IFileDialogCustomize_fnSetEditBoxText,
4554 IFileDialogCustomize_fnGetCheckButtonState,
4555 IFileDialogCustomize_fnSetCheckButtonState,
4556 IFileDialogCustomize_fnAddControlItem,
4557 IFileDialogCustomize_fnRemoveControlItem,
4558 IFileDialogCustomize_fnRemoveAllControlItems,
4559 IFileDialogCustomize_fnGetControlItemState,
4560 IFileDialogCustomize_fnSetControlItemState,
4561 IFileDialogCustomize_fnGetSelectedControlItem,
4562 IFileDialogCustomize_fnSetSelectedControlItem,
4563 IFileDialogCustomize_fnStartVisualGroup,
4564 IFileDialogCustomize_fnEndVisualGroup,
4565 IFileDialogCustomize_fnMakeProminent,
4566 IFileDialogCustomize_fnSetControlItemText
4569 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
4571 FileDialogImpl *fdimpl;
4572 HRESULT hr;
4573 IShellFolder *psf;
4574 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
4576 if(!ppv)
4577 return E_POINTER;
4578 if(pUnkOuter)
4579 return CLASS_E_NOAGGREGATION;
4581 fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
4582 if(!fdimpl)
4583 return E_OUTOFMEMORY;
4585 fdimpl->ref = 1;
4586 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
4587 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
4588 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
4589 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
4590 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
4591 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
4593 if(type == ITEMDLG_TYPE_OPEN)
4595 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
4596 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
4597 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
4598 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
4600 else
4602 WCHAR buf[16];
4603 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
4604 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
4605 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
4607 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
4608 fdimpl->custom_title = StrDupW(buf);
4609 fdimpl->custom_okbutton = StrDupW(buf);
4612 fdimpl->filterspecs = NULL;
4613 fdimpl->filterspec_count = 0;
4614 fdimpl->filetypeindex = 0;
4616 fdimpl->psia_selection = fdimpl->psia_results = NULL;
4617 fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
4619 list_init(&fdimpl->events_clients);
4620 fdimpl->events_next_cookie = 0;
4622 fdimpl->dlg_hwnd = NULL;
4623 fdimpl->peb = NULL;
4625 fdimpl->set_filename = NULL;
4626 fdimpl->default_ext = NULL;
4627 fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL;
4629 fdimpl->client_guid = GUID_NULL;
4631 fdimpl->hmenu_opendropdown = NULL;
4632 fdimpl->hfont_opendropdown = NULL;
4634 /* FIXME: The default folder setting should be restored for the
4635 * application if it was previously set. */
4636 SHGetDesktopFolder(&psf);
4637 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
4638 IShellFolder_Release(psf);
4640 hr = init_custom_controls(fdimpl);
4641 if(FAILED(hr))
4643 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
4644 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4645 return E_FAIL;
4648 hr = IFileDialog2_QueryInterface(&fdimpl->IFileDialog2_iface, riid, ppv);
4649 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4650 return hr;
4653 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4655 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
4658 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4660 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);