uiautomationcore: Implement UiaGetPropertyValue.
[wine.git] / dlls / comdlg32 / itemdlg.c
blob95778c2f35802d54918f17e73bf85207c6dc819a
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 enum ITEMDLG_TYPE {
52 ITEMDLG_TYPE_OPEN,
53 ITEMDLG_TYPE_SAVE
56 enum ITEMDLG_CCTRL_TYPE {
57 IDLG_CCTRL_MENU,
58 IDLG_CCTRL_PUSHBUTTON,
59 IDLG_CCTRL_COMBOBOX,
60 IDLG_CCTRL_RADIOBUTTONLIST,
61 IDLG_CCTRL_CHECKBUTTON,
62 IDLG_CCTRL_EDITBOX,
63 IDLG_CCTRL_SEPARATOR,
64 IDLG_CCTRL_TEXT,
65 IDLG_CCTRL_OPENDROPDOWN,
66 IDLG_CCTRL_VISUALGROUP
69 typedef struct cctrl_item {
70 DWORD id, parent_id;
71 LPWSTR label;
72 CDCONTROLSTATEF cdcstate;
73 HWND hwnd;
74 struct list entry;
75 } cctrl_item;
77 typedef struct {
78 HWND hwnd, wrapper_hwnd;
79 UINT id, dlgid;
80 enum ITEMDLG_CCTRL_TYPE type;
81 CDCONTROLSTATEF cdcstate;
82 struct list entry;
84 struct list sub_cctrls;
85 struct list sub_cctrls_entry;
86 struct list sub_items;
87 } customctrl;
89 typedef struct {
90 struct list entry;
91 IFileDialogEvents *pfde;
92 DWORD cookie;
93 } events_client;
95 typedef struct FileDialogImpl {
96 IFileDialog2 IFileDialog2_iface;
97 union {
98 IFileOpenDialog IFileOpenDialog_iface;
99 IFileSaveDialog IFileSaveDialog_iface;
100 } u;
101 enum ITEMDLG_TYPE dlg_type;
102 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
103 IServiceProvider IServiceProvider_iface;
104 ICommDlgBrowser3 ICommDlgBrowser3_iface;
105 IOleWindow IOleWindow_iface;
106 IFileDialogCustomize IFileDialogCustomize_iface;
107 LONG ref;
109 FILEOPENDIALOGOPTIONS options;
110 COMDLG_FILTERSPEC *filterspecs;
111 UINT filterspec_count;
112 UINT filetypeindex;
114 struct list events_clients;
115 DWORD events_next_cookie;
117 IShellItemArray *psia_selection;
118 IShellItemArray *psia_results;
119 IShellItem *psi_defaultfolder;
120 IShellItem *psi_setfolder;
121 IShellItem *psi_folder;
123 HWND dlg_hwnd;
124 IExplorerBrowser *peb;
125 DWORD ebevents_cookie;
127 LPWSTR set_filename;
128 LPWSTR default_ext;
129 LPWSTR custom_title;
130 LPWSTR custom_okbutton;
131 LPWSTR custom_cancelbutton;
132 LPWSTR custom_filenamelabel;
134 UINT cctrl_width, cctrl_def_height, cctrls_cols;
135 UINT cctrl_indent, dpi_x, dpi_y;
136 HWND cctrls_hwnd;
137 struct list cctrls;
138 UINT_PTR cctrl_next_dlgid;
139 customctrl *cctrl_active_vg;
141 HMENU hmenu_opendropdown;
142 customctrl cctrl_opendropdown;
143 HFONT hfont_opendropdown;
144 BOOL opendropdown_has_selection;
145 DWORD opendropdown_selection;
147 GUID client_guid;
148 } FileDialogImpl;
150 /**************************************************************************
151 * Event wrappers.
153 static HRESULT events_OnFileOk(FileDialogImpl *This)
155 events_client *cursor;
156 HRESULT hr = S_OK;
157 TRACE("%p\n", This);
159 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
161 TRACE("Notifying %p\n", cursor);
162 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
163 if(FAILED(hr) && hr != E_NOTIMPL)
164 break;
167 if(hr == E_NOTIMPL)
168 hr = S_OK;
170 return hr;
173 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
175 events_client *cursor;
176 HRESULT hr = S_OK;
177 TRACE("%p (%p)\n", This, folder);
179 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
181 TRACE("Notifying %p\n", cursor);
182 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
183 if(FAILED(hr) && hr != E_NOTIMPL)
184 break;
187 if(hr == E_NOTIMPL)
188 hr = S_OK;
190 return hr;
193 static void events_OnFolderChange(FileDialogImpl *This)
195 events_client *cursor;
196 TRACE("%p\n", This);
198 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
200 TRACE("Notifying %p\n", cursor);
201 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
205 static void events_OnSelectionChange(FileDialogImpl *This)
207 events_client *cursor;
208 TRACE("%p\n", This);
210 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
212 TRACE("Notifying %p\n", cursor);
213 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
217 static void events_OnTypeChange(FileDialogImpl *This)
219 events_client *cursor;
220 TRACE("%p\n", This);
222 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
224 TRACE("Notifying %p\n", cursor);
225 IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
229 static HRESULT events_OnOverwrite(FileDialogImpl *This, IShellItem *shellitem)
231 events_client *cursor;
232 HRESULT hr = S_OK;
233 FDE_OVERWRITE_RESPONSE response = FDEOR_DEFAULT;
234 TRACE("%p %p\n", This, shellitem);
236 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
238 TRACE("Notifying %p\n", cursor);
239 hr = IFileDialogEvents_OnOverwrite(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, shellitem, &response);
240 TRACE("<-- hr=%lx response=%u\n", hr, response);
241 if(FAILED(hr) && hr != E_NOTIMPL)
242 break;
245 if(hr == E_NOTIMPL)
246 hr = S_OK;
248 if(SUCCEEDED(hr))
250 if (response == FDEOR_DEFAULT)
252 WCHAR buf[100];
253 int answer;
255 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, buf, 100);
256 answer = MessageBoxW(This->dlg_hwnd, buf, This->custom_title,
257 MB_YESNO | MB_ICONEXCLAMATION);
258 if (answer == IDNO || answer == IDCANCEL)
260 hr = E_FAIL;
263 else if (response == FDEOR_REFUSE)
264 hr = E_FAIL;
267 return hr;
270 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
272 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
275 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
277 events_client *cursor;
278 TRACE("%p\n", This);
280 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
282 IFileDialogControlEvents *pfdce;
283 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
285 TRACE("Notifying %p\n", cursor);
286 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
287 IFileDialogControlEvents_Release(pfdce);
291 return S_OK;
294 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
296 events_client *cursor;
297 TRACE("%p %li %li\n", This, ctl_id, item_id);
299 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
301 IFileDialogControlEvents *pfdce;
302 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
304 TRACE("Notifying %p\n", cursor);
305 IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
306 IFileDialogControlEvents_Release(pfdce);
310 return S_OK;
313 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
315 events_client *cursor;
316 TRACE("%p\n", This);
318 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
320 IFileDialogControlEvents *pfdce;
321 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
323 TRACE("Notifying %p\n", cursor);
324 IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
325 IFileDialogControlEvents_Release(pfdce);
329 return S_OK;
332 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
333 DWORD ctl_id)
335 events_client *cursor;
336 TRACE("%p\n", This);
338 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
340 IFileDialogControlEvents *pfdce;
341 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
343 TRACE("Notifying %p\n", cursor);
344 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
345 IFileDialogControlEvents_Release(pfdce);
349 return S_OK;
352 /**************************************************************************
353 * Helper functions.
355 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
357 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
358 UINT len;
360 if(!hwnd_edit)
362 if(This->set_filename)
364 len = lstrlenW(This->set_filename);
365 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
366 lstrcpyW(*str, This->set_filename);
367 return len;
369 return 0;
372 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
373 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
374 if(!*str)
375 return 0;
377 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
378 return len;
381 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
383 if(This->set_filename)
384 LocalFree(This->set_filename);
386 This->set_filename = str ? StrDupW(str) : NULL;
388 return SetDlgItemTextW(This->dlg_hwnd, IDC_FILENAME, This->set_filename);
391 static void fill_filename_from_selection(FileDialogImpl *This)
393 IShellItem *psi;
394 LPWSTR *names;
395 HRESULT hr;
396 DWORD item_count;
397 UINT valid_count;
398 UINT len_total, i;
400 if(!This->psia_selection)
401 return;
403 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
404 if(FAILED(hr) || !item_count)
405 return;
407 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
409 /* Get names of the selected items */
410 valid_count = 0; len_total = 0;
411 for(i = 0; i < item_count; i++)
413 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
414 if(SUCCEEDED(hr))
416 DWORD attr;
418 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
419 if(SUCCEEDED(hr) &&
420 (( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
421 (!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
422 continue;
424 hr = IShellItem_GetDisplayName(psi, (This->options & FOS_PICKFOLDERS) ? SIGDN_FILESYSPATH : SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
425 if(SUCCEEDED(hr))
427 len_total += lstrlenW(names[valid_count]) + 3;
428 valid_count++;
430 IShellItem_Release(psi);
434 if(valid_count == 1)
436 set_file_name(This, names[0]);
437 CoTaskMemFree(names[0]);
439 else if(valid_count > 1)
441 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
442 LPWSTR cur_point = string;
444 for(i = 0; i < valid_count; i++)
446 LPWSTR file = names[i];
447 *cur_point++ = '\"';
448 lstrcpyW(cur_point, file);
449 cur_point += lstrlenW(file);
450 *cur_point++ = '\"';
451 *cur_point++ = ' ';
452 CoTaskMemFree(file);
454 *(cur_point-1) = '\0';
456 set_file_name(This, string);
457 HeapFree(GetProcessHeap(), 0, string);
460 HeapFree(GetProcessHeap(), 0, names);
461 return;
464 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
466 WCHAR *endpos, *ext;
468 lstrcpyW(buf, spec);
469 if( (endpos = StrChrW(buf, ';')) )
470 *endpos = '\0';
472 ext = PathFindExtensionW(buf);
473 if(StrChrW(ext, '*'))
474 return NULL;
476 return ext;
479 static BOOL shell_item_exists(IShellItem* shellitem)
481 LPWSTR filename;
482 HRESULT hr;
483 BOOL result;
485 hr = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &filename);
486 if (SUCCEEDED(hr))
488 /* FIXME: Implement SFGAO_VALIDATE in Wine and use it instead. */
489 result = (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES);
490 CoTaskMemFree(filename);
492 else
494 SFGAOF attributes;
495 result = SUCCEEDED(IShellItem_GetAttributes(shellitem, SFGAO_VALIDATE, &attributes));
498 return result;
501 static HRESULT on_default_action(FileDialogImpl *This)
503 IShellFolder *psf_parent, *psf_desktop;
504 LPITEMIDLIST *pidla;
505 LPITEMIDLIST current_folder;
506 LPWSTR fn_iter, files = NULL, tmp_files;
507 UINT file_count = 0, len, i;
508 int open_action;
509 HRESULT hr, ret = E_FAIL;
511 len = get_file_name(This, &tmp_files);
512 if(len)
514 UINT size_used;
515 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
516 CoTaskMemFree(tmp_files);
518 if(!file_count) return E_FAIL;
520 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
521 if(FAILED(hr))
523 ERR("Failed to get pidl for current directory.\n");
524 HeapFree(GetProcessHeap(), 0, files);
525 return hr;
528 TRACE("Acting on %d file(s).\n", file_count);
530 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
531 open_action = ONOPEN_OPEN;
532 fn_iter = files;
534 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
536 WCHAR canon_filename[MAX_PATH];
537 psf_parent = NULL;
539 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
541 if( (This->options & FOS_NOVALIDATE) &&
542 !(This->options & FOS_FILEMUSTEXIST) )
543 open_action = ONOPEN_OPEN;
544 else
545 open_action = ONOPEN_BROWSE;
547 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
548 This->options & ~FOS_FILEMUSTEXIST,
549 (This->dlg_type == ITEMDLG_TYPE_SAVE),
550 open_action);
552 /* Add the proper extension */
553 if(open_action == ONOPEN_OPEN)
555 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
557 WCHAR extbuf[MAX_PATH], *newext = NULL;
559 if(This->filterspec_count)
561 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
563 else if(This->default_ext)
565 lstrcpyW(extbuf, L".");
566 lstrcatW(extbuf, This->default_ext);
567 newext = extbuf;
570 if(newext)
572 WCHAR *ext = PathFindExtensionW(canon_filename);
573 if(lstrcmpW(ext, newext))
574 lstrcatW(canon_filename, newext);
577 else
579 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
580 !PathFileExistsW(canon_filename))
582 if(This->default_ext)
584 lstrcatW(canon_filename, L".");
585 lstrcatW(canon_filename, This->default_ext);
587 if(!PathFileExistsW(canon_filename))
589 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
590 open_action = ONOPEN_BROWSE;
593 else
595 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
596 open_action = ONOPEN_BROWSE;
602 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
604 if(psf_parent && !(open_action == ONOPEN_BROWSE))
605 IShellFolder_Release(psf_parent);
607 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
610 HeapFree(GetProcessHeap(), 0, files);
611 ILFree(current_folder);
613 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
614 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
616 switch(open_action)
618 case ONOPEN_SEARCH:
619 FIXME("Filtering not implemented.\n");
620 break;
622 case ONOPEN_BROWSE:
623 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
624 if(FAILED(hr))
625 ERR("Failed to browse to directory: %08lx\n", hr);
627 IShellFolder_Release(psf_parent);
628 break;
630 case ONOPEN_OPEN:
631 hr = SHGetDesktopFolder(&psf_desktop);
632 if(SUCCEEDED(hr))
634 if(This->psia_results)
636 IShellItemArray_Release(This->psia_results);
637 This->psia_results = NULL;
640 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
641 &This->psia_results);
643 IShellFolder_Release(psf_desktop);
645 if(FAILED(hr))
646 break;
648 if(This->options & FOS_PICKFOLDERS)
650 SFGAOF attributes;
651 hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
652 if(hr != S_OK)
654 WCHAR buf[64];
655 LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, ARRAY_SIZE(buf));
657 MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
659 IShellItemArray_Release(This->psia_results);
660 This->psia_results = NULL;
661 break;
665 if((This->options & FOS_OVERWRITEPROMPT) && This->dlg_type == ITEMDLG_TYPE_SAVE)
667 IShellItem *shellitem;
669 for (i=0; SUCCEEDED(hr) && i<file_count; i++)
671 hr = IShellItemArray_GetItemAt(This->psia_results, i, &shellitem);
672 if (SUCCEEDED(hr))
674 if (shell_item_exists(shellitem))
675 hr = events_OnOverwrite(This, shellitem);
677 IShellItem_Release(shellitem);
681 if (FAILED(hr))
682 break;
685 if(events_OnFileOk(This) == S_OK)
686 ret = S_OK;
688 break;
690 default:
691 ERR("Failed.\n");
692 break;
695 /* Clean up */
696 for(i = 0; i < file_count; i++)
697 ILFree(pidla[i]);
698 HeapFree(GetProcessHeap(), 0, pidla);
700 /* Success closes the dialog */
701 return ret;
704 static void show_opendropdown(FileDialogImpl *This)
706 HWND open_hwnd;
707 RECT open_rc;
708 MSG msg;
710 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
712 GetWindowRect(open_hwnd, &open_rc);
714 if (TrackPopupMenu(This->hmenu_opendropdown, 0, open_rc.left, open_rc.bottom, 0, This->dlg_hwnd, NULL) &&
715 PeekMessageW(&msg, This->dlg_hwnd, WM_MENUCOMMAND, WM_MENUCOMMAND, PM_REMOVE))
717 MENUITEMINFOW mii;
719 This->opendropdown_has_selection = TRUE;
721 mii.cbSize = sizeof(mii);
722 mii.fMask = MIIM_ID;
723 GetMenuItemInfoW((HMENU)msg.lParam, msg.wParam, TRUE, &mii);
724 This->opendropdown_selection = mii.wID;
726 if(SUCCEEDED(on_default_action(This)))
727 EndDialog(This->dlg_hwnd, S_OK);
728 else
729 This->opendropdown_has_selection = FALSE;
733 /**************************************************************************
734 * Control item functions.
737 static void item_free(cctrl_item *item)
739 DestroyWindow(item->hwnd);
740 HeapFree(GetProcessHeap(), 0, item->label);
741 HeapFree(GetProcessHeap(), 0, item);
744 static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF visible_flags, DWORD* position)
746 DWORD dummy;
747 cctrl_item* item;
749 if (!position) position = &dummy;
751 *position = 0;
753 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
755 if (item->id == itemid)
756 return item;
758 if ((item->cdcstate & visible_flags) == visible_flags)
759 (*position)++;
762 return NULL;
765 static cctrl_item* get_first_item(customctrl* parent)
767 cctrl_item* item;
769 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
771 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
772 return item;
775 return NULL;
778 static HRESULT add_item(customctrl* parent, DWORD itemid, LPCWSTR label, cctrl_item** result)
780 cctrl_item* item;
781 LPWSTR label_copy;
783 if (get_item(parent, itemid, 0, NULL))
784 return E_INVALIDARG;
786 item = HeapAlloc(GetProcessHeap(), 0, sizeof(*item));
787 label_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(label)+1)*sizeof(WCHAR));
789 if (!item || !label_copy)
791 HeapFree(GetProcessHeap(), 0, item);
792 HeapFree(GetProcessHeap(), 0, label_copy);
793 return E_OUTOFMEMORY;
796 item->id = itemid;
797 item->parent_id = parent->id;
798 lstrcpyW(label_copy, label);
799 item->label = label_copy;
800 item->cdcstate = CDCS_VISIBLE|CDCS_ENABLED;
801 item->hwnd = NULL;
802 list_add_tail(&parent->sub_items, &item->entry);
804 *result = item;
806 return S_OK;
809 /**************************************************************************
810 * Control functions.
812 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
814 customctrl *ctrl, *sub_ctrl;
816 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
818 if(ctrl->dlgid == dlgid)
819 return ctrl;
821 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
822 if(sub_ctrl->dlgid == dlgid)
823 return sub_ctrl;
826 ERR("Failed to find control with dialog id %ld\n", dlgid);
827 return NULL;
830 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
832 customctrl *ctrl, *sub_ctrl;
834 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
836 if(ctrl->id == ctlid)
837 return ctrl;
839 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
840 if(sub_ctrl->id == ctlid)
841 return sub_ctrl;
844 if (This->hmenu_opendropdown && This->cctrl_opendropdown.id == ctlid)
845 return &This->cctrl_opendropdown;
847 TRACE("No existing control with control id %ld\n", ctlid);
848 return NULL;
851 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
853 LPWSTR text;
854 UINT len, final_width;
855 UINT lines, final_height;
856 SIZE size;
857 RECT rc;
858 HDC hdc;
859 WCHAR *c;
860 HFONT font;
862 TRACE("\n");
864 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
865 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
866 if(!text) return;
867 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
869 hdc = GetDC(hctrl);
870 font = (HFONT)SendMessageW(hctrl, WM_GETFONT, 0, 0);
871 font = SelectObject(hdc, font);
872 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
873 SelectObject(hdc, font);
874 ReleaseDC(hctrl, hdc);
876 if(len && multiline)
878 /* FIXME: line-wrap */
879 for(lines = 1, c = text; *c != '\0'; c++)
880 if(*c == '\n') lines++;
882 final_height = size.cy*lines + 2*4;
884 else
886 GetWindowRect(hctrl, &rc);
887 final_height = rc.bottom - rc.top;
890 final_width = min(max(size.cx, min_width) + 4, max_width);
891 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
892 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
894 HeapFree(GetProcessHeap(), 0, text);
897 static UINT ctrl_get_height(customctrl *ctrl) {
898 RECT rc;
899 GetWindowRect(ctrl->wrapper_hwnd, &rc);
900 return rc.bottom - rc.top;
903 static void ctrl_free(customctrl *ctrl)
905 customctrl *sub_cur1, *sub_cur2;
906 cctrl_item *item_cur1, *item_cur2;
908 TRACE("Freeing control %p\n", ctrl);
909 if(ctrl->type == IDLG_CCTRL_MENU)
911 TBBUTTON tbb;
912 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
913 DestroyMenu((HMENU)tbb.dwData);
916 LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
918 list_remove(&sub_cur1->sub_cctrls_entry);
919 ctrl_free(sub_cur1);
922 LIST_FOR_EACH_ENTRY_SAFE(item_cur1, item_cur2, &ctrl->sub_items, cctrl_item, entry)
924 list_remove(&item_cur1->entry);
925 item_free(item_cur1);
928 DestroyWindow(ctrl->hwnd);
929 HeapFree(GetProcessHeap(), 0, ctrl);
932 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
934 RECT rc;
935 UINT total_height;
936 UINT max_width, size;
937 customctrl *sub_ctrl;
939 switch(ctrl->type)
941 case IDLG_CCTRL_PUSHBUTTON:
942 case IDLG_CCTRL_COMBOBOX:
943 case IDLG_CCTRL_CHECKBUTTON:
944 case IDLG_CCTRL_TEXT:
945 size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
946 ctrl_resize(ctrl->hwnd, size, size, 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 size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
989 ctrl_resize(item->hwnd, size, size, TRUE);
990 SetWindowPos(item->hwnd, NULL, 0, total_height, 0, 0,
991 SWP_NOZORDER|SWP_NOSIZE);
993 GetWindowRect(item->hwnd, &rc);
995 total_height += rc.bottom - rc.top;
996 max_width = max(rc.right - rc.left, max_width);
999 SetWindowPos(ctrl->hwnd, NULL, 0, 0, max_width, total_height,
1000 SWP_NOZORDER|SWP_NOMOVE);
1002 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, max_width, total_height,
1003 SWP_NOZORDER|SWP_NOMOVE);
1005 break;
1007 case IDLG_CCTRL_EDITBOX:
1008 case IDLG_CCTRL_SEPARATOR:
1009 case IDLG_CCTRL_MENU:
1010 case IDLG_CCTRL_OPENDROPDOWN:
1011 /* Nothing */
1012 break;
1016 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
1018 FileDialogImpl *This = crs->lpCreateParams;
1019 TRACE("%p\n", This);
1021 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1022 return TRUE;
1025 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1027 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1029 TRACE("%p, %Ix\n", This, wparam);
1031 if(ctrl)
1033 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
1035 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
1036 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
1038 else
1039 cctrl_event_OnButtonClicked(This, ctrl->id);
1042 return TRUE;
1045 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1047 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1048 TRACE("%p, %p (%Ix)\n", This, ctrl, wparam);
1050 if(ctrl)
1052 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
1053 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
1055 cctrl_event_OnItemSelected(This, ctrl->id, selid);
1057 return TRUE;
1060 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
1062 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
1063 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
1064 POINT pt = { 0, nmtb->rcButton.bottom };
1065 TBBUTTON tbb;
1066 UINT idcmd;
1068 TRACE("%p, %p (%Ix)\n", This, ctrl, lparam);
1070 if(ctrl)
1072 cctrl_event_OnControlActivating(This,ctrl->id);
1074 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1075 ClientToScreen(ctrl->hwnd, &pt);
1076 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
1077 if(idcmd)
1078 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
1081 return TBDDRET_DEFAULT;
1084 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1086 switch(HIWORD(wparam))
1088 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
1089 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
1092 return FALSE;
1095 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1097 NMHDR *nmhdr = (NMHDR*)lparam;
1099 switch(nmhdr->code)
1101 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
1104 return FALSE;
1107 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1109 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1110 customctrl *ctrl;
1111 HWND hwnd_child;
1112 RECT rc;
1114 switch(message)
1116 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
1117 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
1118 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
1119 case WM_SIZE:
1120 hwnd_child = GetPropW(hwnd, L"nfs_child");
1121 ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA);
1122 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
1124 GetClientRect(hwnd, &rc);
1125 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1127 return TRUE;
1130 return DefWindowProcW(hwnd, message, wparam, lparam);
1133 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
1134 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
1135 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
1137 HWND ns_hwnd, control_hwnd, parent_hwnd;
1138 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
1139 customctrl *ctrl;
1141 if(get_cctrl(This, id))
1142 return E_UNEXPECTED; /* Duplicate id */
1144 if(This->cctrl_active_vg)
1145 parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
1146 else
1147 parent_hwnd = This->cctrls_hwnd;
1149 ns_hwnd = CreateWindowExW(0, L"FloatNotifySink", NULL, wsflags,
1150 0, 0, This->cctrl_width, height, parent_hwnd,
1151 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
1152 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
1153 0, 0, This->cctrl_width, height, ns_hwnd,
1154 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
1156 if(!ns_hwnd || !control_hwnd)
1158 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
1159 DestroyWindow(ns_hwnd);
1160 DestroyWindow(control_hwnd);
1162 return E_FAIL;
1165 SetPropW(ns_hwnd, L"nfs_child", control_hwnd);
1167 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
1168 if(!ctrl)
1169 return E_OUTOFMEMORY;
1171 ctrl->hwnd = control_hwnd;
1172 ctrl->wrapper_hwnd = ns_hwnd;
1173 ctrl->id = id;
1174 ctrl->dlgid = This->cctrl_next_dlgid;
1175 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
1176 list_init(&ctrl->sub_cctrls);
1177 list_init(&ctrl->sub_items);
1179 if(This->cctrl_active_vg)
1180 list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
1181 else
1182 list_add_tail(&This->cctrls, &ctrl->entry);
1184 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl);
1186 if(ppctrl) *ppctrl = ctrl;
1188 This->cctrl_next_dlgid++;
1189 return S_OK;
1192 /**************************************************************************
1193 * Container functions.
1195 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
1197 UINT container_height;
1198 UINT column_width;
1199 UINT nr_of_cols;
1200 UINT max_control_height, total_height = 0;
1201 UINT cur_col_pos, cur_row_pos;
1202 customctrl *ctrl;
1203 BOOL fits_height;
1204 UINT cspacing = MulDiv(90, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Columns are spaced with 90px */
1205 UINT rspacing = MulDiv(4, This->dpi_y, USER_DEFAULT_SCREEN_DPI); /* Rows are spaced with 4 px. */
1207 /* Given the new width of the container, this function determines the
1208 * needed height of the container and places the controls according to
1209 * the new layout. Returns the new height.
1212 TRACE("%p\n", This);
1214 column_width = This->cctrl_width + cspacing;
1215 nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
1217 /* We don't need to do anything unless the number of visible columns has changed. */
1218 if(nr_of_cols == This->cctrls_cols)
1220 RECT rc;
1221 GetWindowRect(This->cctrls_hwnd, &rc);
1222 return rc.bottom - rc.top;
1225 This->cctrls_cols = nr_of_cols;
1227 /* Get the size of the tallest control, and the total size of
1228 * all the controls to figure out the number of slots we need.
1230 max_control_height = 0;
1231 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1233 if(ctrl->cdcstate & CDCS_VISIBLE)
1235 UINT control_height = ctrl_get_height(ctrl);
1236 max_control_height = max(max_control_height, control_height);
1238 total_height += control_height + rspacing;
1242 if(!total_height)
1243 return 0;
1245 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
1246 TRACE("Guess: container_height: %d\n",container_height);
1248 /* Incrementally increase container_height until all the controls
1249 * fit.
1251 do {
1252 UINT columns_needed = 1;
1253 cur_row_pos = 0;
1255 fits_height = TRUE;
1256 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1258 if(ctrl->cdcstate & CDCS_VISIBLE)
1260 UINT control_height = ctrl_get_height(ctrl);
1262 if(cur_row_pos + control_height > container_height)
1264 if(++columns_needed > nr_of_cols)
1266 container_height += 1;
1267 fits_height = FALSE;
1268 break;
1270 cur_row_pos = 0;
1273 cur_row_pos += control_height + rspacing;
1276 } while(!fits_height);
1278 TRACE("Final container height: %d\n", container_height);
1280 /* Move the controls to their final destination
1282 cur_col_pos = 0; cur_row_pos = 0;
1283 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1285 if(ctrl->cdcstate & CDCS_VISIBLE)
1287 RECT rc;
1288 UINT control_height, control_indent;
1289 GetWindowRect(ctrl->wrapper_hwnd, &rc);
1290 control_height = rc.bottom - rc.top;
1292 if(cur_row_pos + control_height > container_height)
1294 cur_row_pos = 0;
1295 cur_col_pos += This->cctrl_width + cspacing;
1299 if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
1300 control_indent = 0;
1301 else
1302 control_indent = This->cctrl_indent;
1304 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
1305 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1307 cur_row_pos += control_height + rspacing;
1311 /* Sanity check */
1312 if(cur_row_pos + This->cctrl_width > container_width)
1313 ERR("-- Failed to place controls properly.\n");
1315 return container_height;
1318 static void ctrl_set_font(customctrl *ctrl, HFONT font)
1320 customctrl *sub_ctrl;
1321 cctrl_item* item;
1323 SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1325 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1327 ctrl_set_font(sub_ctrl, font);
1330 if (ctrl->type == IDLG_CCTRL_RADIOBUTTONLIST)
1332 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1334 SendMessageW(item->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1339 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
1341 LONG wndstyle;
1343 if(parent)
1345 customctrl *ctrl;
1346 HFONT font;
1348 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1349 wndstyle &= ~(WS_POPUP);
1350 wndstyle |= WS_CHILD;
1351 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1353 SetParent(This->cctrls_hwnd, parent);
1354 ShowWindow(This->cctrls_hwnd, TRUE);
1356 /* Set the fonts to match the dialog font. */
1357 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
1358 if(!font)
1359 ERR("Failed to get font handle from dialog.\n");
1361 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1363 if(font) ctrl_set_font(ctrl, font);
1364 customctrl_resize(This, ctrl);
1367 else
1369 ShowWindow(This->cctrls_hwnd, FALSE);
1371 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1372 wndstyle &= ~(WS_CHILD);
1373 wndstyle |= WS_POPUP;
1374 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1376 SetParent(This->cctrls_hwnd, NULL);
1380 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
1382 FileDialogImpl *This = crs->lpCreateParams;
1383 TRACE("%p\n", This);
1385 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1386 return TRUE;
1389 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
1391 customctrl *cur1, *cur2;
1392 TRACE("%p\n", This);
1394 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1396 list_remove(&cur1->entry);
1397 ctrl_free(cur1);
1400 return TRUE;
1403 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1405 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1407 switch(umessage)
1409 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1410 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1411 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1414 return FALSE;
1417 static void radiobuttonlist_set_selected_item(FileDialogImpl *This, customctrl *ctrl, cctrl_item *item)
1419 cctrl_item *cursor;
1421 LIST_FOR_EACH_ENTRY(cursor, &ctrl->sub_items, cctrl_item, entry)
1423 SendMessageW(cursor->hwnd, BM_SETCHECK, (cursor == item) ? BST_CHECKED : BST_UNCHECKED, 0);
1427 static LRESULT radiobuttonlist_on_bn_clicked(FileDialogImpl *This, HWND hwnd, HWND child)
1429 DWORD ctrl_id = (DWORD)GetWindowLongPtrW(hwnd, GWLP_ID);
1430 customctrl *ctrl;
1431 cctrl_item *item;
1432 BOOL found_item=FALSE;
1434 ctrl = get_cctrl_from_dlgid(This, ctrl_id);
1436 if (!ctrl)
1438 ERR("Can't find this control\n");
1439 return 0;
1442 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1444 if (item->hwnd == child)
1446 found_item = TRUE;
1447 break;
1451 if (!found_item)
1453 ERR("Can't find control item\n");
1454 return 0;
1457 radiobuttonlist_set_selected_item(This, ctrl, item);
1459 cctrl_event_OnItemSelected(This, ctrl->id, item->id);
1461 return 0;
1464 static LRESULT radiobuttonlist_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1466 switch(HIWORD(wparam))
1468 case BN_CLICKED: return radiobuttonlist_on_bn_clicked(This, hwnd, (HWND)lparam);
1471 return FALSE;
1474 static LRESULT CALLBACK radiobuttonlist_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1476 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1478 switch(message)
1480 case WM_COMMAND: return radiobuttonlist_on_wm_command(This, hwnd, wparam, lparam);
1483 return DefWindowProcW(hwnd, message, wparam, lparam);
1486 static HRESULT init_custom_controls(FileDialogImpl *This)
1488 WNDCLASSW wc;
1489 HDC hdc;
1490 static const WCHAR ctrl_container_classname[] = L"idlg_container_pane";
1492 InitCommonControlsEx(NULL);
1494 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1496 wc.style = CS_HREDRAW | CS_VREDRAW;
1497 wc.lpfnWndProc = ctrl_container_wndproc;
1498 wc.cbClsExtra = 0;
1499 wc.cbWndExtra = 0;
1500 wc.hInstance = COMDLG32_hInstance;
1501 wc.hIcon = 0;
1502 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1503 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1504 wc.lpszMenuName = NULL;
1505 wc.lpszClassName = ctrl_container_classname;
1507 if(!RegisterClassW(&wc)) return E_FAIL;
1510 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1511 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1512 0, 0, 0, 0, NULL, 0,
1513 COMDLG32_hInstance, This);
1514 if(!This->cctrls_hwnd)
1515 return E_FAIL;
1517 hdc = GetDC(This->cctrls_hwnd);
1518 This->dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
1519 This->dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
1520 ReleaseDC(This->cctrls_hwnd, hdc);
1522 This->cctrl_width = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Controls have a fixed width */
1523 This->cctrl_indent = MulDiv(100, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1524 This->cctrl_def_height = MulDiv(23, This->dpi_y, USER_DEFAULT_SCREEN_DPI);
1525 This->cctrls_cols = 0;
1527 This->cctrl_next_dlgid = 0x2000;
1528 list_init(&This->cctrls);
1529 This->cctrl_active_vg = NULL;
1531 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1533 /* Register class for */
1534 if (!GetClassInfoW(COMDLG32_hInstance, L"FloatNotifySink", &wc) ||
1535 wc.hInstance != COMDLG32_hInstance)
1537 wc.style = CS_HREDRAW | CS_VREDRAW;
1538 wc.lpfnWndProc = notifysink_proc;
1539 wc.cbClsExtra = 0;
1540 wc.cbWndExtra = 0;
1541 wc.hInstance = COMDLG32_hInstance;
1542 wc.hIcon = 0;
1543 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1544 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1545 wc.lpszMenuName = NULL;
1546 wc.lpszClassName = L"FloatNotifySink";
1548 if (!RegisterClassW(&wc))
1549 ERR("Failed to register FloatNotifySink window class.\n");
1552 if (!GetClassInfoW(COMDLG32_hInstance, L"RadioButtonList", &wc) ||
1553 wc.hInstance != COMDLG32_hInstance)
1555 wc.style = CS_HREDRAW | CS_VREDRAW;
1556 wc.lpfnWndProc = radiobuttonlist_proc;
1557 wc.cbClsExtra = 0;
1558 wc.cbWndExtra = 0;
1559 wc.hInstance = COMDLG32_hInstance;
1560 wc.hIcon = 0;
1561 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1562 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1563 wc.lpszMenuName = NULL;
1564 wc.lpszClassName = L"RadioButtonList";
1566 if (!RegisterClassW(&wc))
1567 ERR("Failed to register RadioButtonList window class.\n");
1570 return S_OK;
1573 /**************************************************************************
1574 * Window related functions.
1576 static BOOL update_open_dropdown(FileDialogImpl *This)
1578 /* Show or hide the open dropdown button as appropriate */
1579 BOOL show=FALSE, showing;
1580 HWND open_hwnd, dropdown_hwnd;
1582 if (This->hmenu_opendropdown)
1584 INT num_visible_items=0;
1585 cctrl_item* item;
1587 LIST_FOR_EACH_ENTRY(item, &This->cctrl_opendropdown.sub_items, cctrl_item, entry)
1589 if (item->cdcstate & CDCS_VISIBLE)
1591 num_visible_items++;
1592 if (num_visible_items >= 2)
1594 show = TRUE;
1595 break;
1601 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1602 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1604 showing = (GetWindowLongPtrW(dropdown_hwnd, GWL_STYLE) & WS_VISIBLE) != 0;
1606 if (showing != show)
1608 RECT open_rc, dropdown_rc;
1610 GetWindowRect(open_hwnd, &open_rc);
1611 GetWindowRect(dropdown_hwnd, &dropdown_rc);
1613 if (show)
1615 ShowWindow(dropdown_hwnd, SW_SHOW);
1617 SetWindowPos(open_hwnd, NULL, 0, 0,
1618 (open_rc.right - open_rc.left) - (dropdown_rc.right - dropdown_rc.left),
1619 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1621 else
1623 ShowWindow(dropdown_hwnd, SW_HIDE);
1625 SetWindowPos(open_hwnd, NULL, 0, 0,
1626 (open_rc.right - open_rc.left) + (dropdown_rc.right - dropdown_rc.left),
1627 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1631 return show;
1634 static void update_layout(FileDialogImpl *This)
1636 HDWP hdwp;
1637 HWND hwnd;
1638 RECT dialog_rc;
1639 RECT cancel_rc, dropdown_rc, open_rc;
1640 RECT filetype_rc, filename_rc, filenamelabel_rc;
1641 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1642 static const UINT vspacing = 4, hspacing = 4;
1643 static const UINT min_width = 320, min_height = 200;
1644 BOOL show_dropdown;
1646 if (!GetClientRect(This->dlg_hwnd, &dialog_rc))
1648 TRACE("Invalid dialog window, not updating layout\n");
1649 return;
1652 if(dialog_rc.right < min_width || dialog_rc.bottom < min_height)
1654 TRACE("Dialog size (%ld, %ld) too small, not updating layout\n", dialog_rc.right, dialog_rc.bottom);
1655 return;
1658 /****
1659 * Calculate the size of the dialog and all the parts.
1662 /* Cancel button */
1663 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1664 if(hwnd)
1666 int cancel_width, cancel_height;
1667 GetWindowRect(hwnd, &cancel_rc);
1668 cancel_width = cancel_rc.right - cancel_rc.left;
1669 cancel_height = cancel_rc.bottom - cancel_rc.top;
1671 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1672 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1673 cancel_rc.right = cancel_rc.left + cancel_width;
1674 cancel_rc.bottom = cancel_rc.top + cancel_height;
1677 /* Open/Save dropdown */
1678 show_dropdown = update_open_dropdown(This);
1680 if(show_dropdown)
1682 int dropdown_width, dropdown_height;
1683 hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1685 GetWindowRect(hwnd, &dropdown_rc);
1686 dropdown_width = dropdown_rc.right - dropdown_rc.left;
1687 dropdown_height = dropdown_rc.bottom - dropdown_rc.top;
1689 dropdown_rc.left = cancel_rc.left - dropdown_width - hspacing;
1690 dropdown_rc.top = cancel_rc.top;
1691 dropdown_rc.right = dropdown_rc.left + dropdown_width;
1692 dropdown_rc.bottom = dropdown_rc.top + dropdown_height;
1694 else
1696 dropdown_rc.left = dropdown_rc.right = cancel_rc.left - hspacing;
1697 dropdown_rc.top = cancel_rc.top;
1698 dropdown_rc.bottom = cancel_rc.bottom;
1701 /* Open/Save button */
1702 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1703 if(hwnd)
1705 int open_width, open_height;
1706 GetWindowRect(hwnd, &open_rc);
1707 open_width = open_rc.right - open_rc.left;
1708 open_height = open_rc.bottom - open_rc.top;
1710 open_rc.left = dropdown_rc.left - open_width;
1711 open_rc.top = dropdown_rc.top;
1712 open_rc.right = open_rc.left + open_width;
1713 open_rc.bottom = open_rc.top + open_height;
1716 /* The filetype combobox. */
1717 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1718 if(hwnd)
1720 int filetype_width, filetype_height;
1721 GetWindowRect(hwnd, &filetype_rc);
1723 filetype_width = filetype_rc.right - filetype_rc.left;
1724 filetype_height = filetype_rc.bottom - filetype_rc.top;
1726 filetype_rc.right = cancel_rc.right;
1728 filetype_rc.left = filetype_rc.right - filetype_width;
1729 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1730 filetype_rc.bottom = filetype_rc.top + filetype_height;
1732 if(!This->filterspec_count)
1733 filetype_rc.left = filetype_rc.right;
1736 /* Filename label. */
1737 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1738 if(hwnd)
1740 int filetypelabel_width, filetypelabel_height;
1741 GetWindowRect(hwnd, &filenamelabel_rc);
1743 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1744 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1746 filenamelabel_rc.left = 160; /* FIXME */
1747 filenamelabel_rc.top = filetype_rc.top;
1748 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1749 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1752 /* Filename edit box. */
1753 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1754 if(hwnd)
1756 int filename_width, filename_height;
1757 GetWindowRect(hwnd, &filename_rc);
1759 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1760 filename_height = filename_rc.bottom - filename_rc.top;
1762 filename_rc.left = filenamelabel_rc.right + hspacing;
1763 filename_rc.top = filetype_rc.top;
1764 filename_rc.right = filename_rc.left + filename_width;
1765 filename_rc.bottom = filename_rc.top + filename_height;
1768 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1769 if(hwnd)
1771 GetWindowRect(hwnd, &toolbar_rc);
1772 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1775 /* The custom controls */
1776 customctrls_rc.left = dialog_rc.left + hspacing;
1777 customctrls_rc.right = dialog_rc.right - hspacing;
1778 customctrls_rc.bottom = filename_rc.top - vspacing;
1779 customctrls_rc.top = customctrls_rc.bottom -
1780 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1782 /* The ExplorerBrowser control. */
1783 ebrowser_rc.left = dialog_rc.left + hspacing;
1784 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1785 ebrowser_rc.right = dialog_rc.right - hspacing;
1786 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1788 /****
1789 * Move everything to the right place.
1792 /* FIXME: The Save Dialog uses a slightly different layout. */
1793 hdwp = BeginDeferWindowPos(7);
1795 if(hdwp && This->peb)
1796 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1798 if(hdwp && This->cctrls_hwnd)
1799 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1800 customctrls_rc.left, customctrls_rc.top,
1801 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1802 SWP_NOZORDER | SWP_NOACTIVATE);
1804 /* The default controls */
1805 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1806 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1807 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1809 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1810 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1811 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1812 SWP_NOZORDER | SWP_NOACTIVATE);
1814 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1815 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1816 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1818 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1819 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1820 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1822 if(hdwp && This->hmenu_opendropdown && (hwnd = GetDlgItem(This->dlg_hwnd, psh1)))
1823 DeferWindowPos(hdwp, hwnd, NULL, dropdown_rc.left, dropdown_rc.top, 0, 0,
1824 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1826 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1827 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1828 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1830 if(hdwp)
1831 EndDeferWindowPos(hdwp);
1832 else
1833 ERR("Failed to position dialog controls.\n");
1835 return;
1838 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1840 IShellItem *psi_folder;
1841 IObjectWithSite *client;
1842 FOLDERSETTINGS fos;
1843 RECT rc = {0};
1844 HRESULT hr;
1846 /* Create ExplorerBrowser instance */
1847 OleInitialize(NULL);
1849 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1850 &IID_IExplorerBrowser, (void**)&This->peb);
1851 if(FAILED(hr))
1853 ERR("Failed to instantiate ExplorerBrowser control.\n");
1854 return hr;
1857 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES | EBO_NOBORDER);
1859 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1860 if(FAILED(hr))
1862 ERR("Failed to initialize the ExplorerBrowser control.\n");
1863 IExplorerBrowser_Release(This->peb);
1864 This->peb = NULL;
1865 return hr;
1867 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1868 if(FAILED(hr))
1869 ERR("Advise (ExplorerBrowser) failed.\n");
1871 /* Get previous options? */
1872 fos.ViewMode = fos.fFlags = 0;
1873 if(!(This->options & FOS_ALLOWMULTISELECT))
1874 fos.fFlags |= FWF_SINGLESEL;
1876 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1878 hr = IExplorerBrowser_QueryInterface(This->peb, &IID_IObjectWithSite, (void**)&client);
1879 if (hr == S_OK)
1881 hr = IObjectWithSite_SetSite(client, (IUnknown*)&This->IFileDialog2_iface);
1882 IObjectWithSite_Release(client);
1883 if(FAILED(hr))
1884 ERR("SetSite failed, 0x%08lx\n", hr);
1887 /* Browse somewhere */
1888 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1889 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1891 return S_OK;
1894 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1896 HWND htoolbar;
1897 TBADDBITMAP tbab;
1898 TBBUTTON button[2];
1900 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1901 0, 0, 0, 0,
1902 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1904 tbab.hInst = HINST_COMMCTRL;
1905 tbab.nID = IDB_HIST_LARGE_COLOR;
1906 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1908 button[0].iBitmap = HIST_BACK;
1909 button[0].idCommand = IDC_NAVBACK;
1910 button[0].fsState = TBSTATE_ENABLED;
1911 button[0].fsStyle = BTNS_BUTTON;
1912 button[0].dwData = 0;
1913 button[0].iString = 0;
1915 button[1].iBitmap = HIST_FORWARD;
1916 button[1].idCommand = IDC_NAVFORWARD;
1917 button[1].fsState = TBSTATE_ENABLED;
1918 button[1].fsStyle = BTNS_BUTTON;
1919 button[1].dwData = 0;
1920 button[1].iString = 0;
1922 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1923 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1924 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1927 static void update_control_text(FileDialogImpl *This)
1929 HWND hitem;
1930 LPCWSTR custom_okbutton;
1931 cctrl_item* item;
1932 UINT min_width = MulDiv(50, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1933 UINT max_width = MulDiv(250, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1935 if(This->custom_title)
1936 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1938 if(This->hmenu_opendropdown && (item = get_first_item(&This->cctrl_opendropdown)))
1939 custom_okbutton = item->label;
1940 else
1941 custom_okbutton = This->custom_okbutton;
1943 if(custom_okbutton &&
1944 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1946 SetWindowTextW(hitem, custom_okbutton);
1947 ctrl_resize(hitem, min_width, max_width, FALSE);
1950 if(This->custom_cancelbutton &&
1951 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1953 SetWindowTextW(hitem, This->custom_cancelbutton);
1954 ctrl_resize(hitem, min_width, max_width, FALSE);
1957 if(This->custom_filenamelabel &&
1958 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1960 SetWindowTextW(hitem, This->custom_filenamelabel);
1961 ctrl_resize(hitem, min_width, max_width, FALSE);
1965 static LRESULT CALLBACK dropdown_subclass_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1967 if (umessage == WM_LBUTTONDOWN)
1969 FileDialogImpl *This = GetPropW(hwnd, L"itemdlg_This");
1971 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
1972 show_opendropdown(This);
1973 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
1975 return 0;
1978 return CallWindowProcW((WNDPROC)GetPropW(hwnd, L"itemdlg_oldwndproc"), hwnd, umessage, wparam, lparam);
1981 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1983 FileDialogImpl *This = (FileDialogImpl*)lParam;
1984 HWND hitem;
1986 TRACE("(%p, %p)\n", This, hwnd);
1988 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1989 This->dlg_hwnd = hwnd;
1991 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1992 if(hitem) ShowWindow(hitem, SW_HIDE);
1994 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1995 if(hitem) ShowWindow(hitem, SW_HIDE);
1997 /* Fill filetypes combobox, or hide it. */
1998 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1999 if(This->filterspec_count)
2001 HDC hdc;
2002 HFONT font;
2003 SIZE size;
2004 UINT i, maxwidth = 0;
2006 hdc = GetDC(hitem);
2007 font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
2008 SelectObject(hdc, font);
2010 for(i = 0; i < This->filterspec_count; i++)
2012 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
2014 if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
2015 maxwidth = max(maxwidth, size.cx);
2017 ReleaseDC(hitem, hdc);
2019 if(maxwidth > 0)
2021 maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
2022 SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
2024 else
2025 ERR("Failed to calculate width of filetype dropdown\n");
2027 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
2029 else
2030 ShowWindow(hitem, SW_HIDE);
2032 if(This->set_filename &&
2033 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
2034 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
2036 if(This->hmenu_opendropdown)
2038 HWND dropdown_hwnd;
2039 LOGFONTW lfw, lfw_marlett;
2040 HFONT dialog_font;
2042 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
2044 /* Change dropdown button font to Marlett */
2045 dialog_font = (HFONT)SendMessageW(dropdown_hwnd, WM_GETFONT, 0, 0);
2047 GetObjectW(dialog_font, sizeof(lfw), &lfw);
2049 memset(&lfw_marlett, 0, sizeof(lfw_marlett));
2050 lstrcpyW(lfw_marlett.lfFaceName, L"Marlett");
2051 lfw_marlett.lfHeight = lfw.lfHeight;
2052 lfw_marlett.lfCharSet = SYMBOL_CHARSET;
2054 This->hfont_opendropdown = CreateFontIndirectW(&lfw_marlett);
2056 SendMessageW(dropdown_hwnd, WM_SETFONT, (LPARAM)This->hfont_opendropdown, 0);
2058 /* Subclass button so we can handle LBUTTONDOWN */
2059 SetPropW(dropdown_hwnd, L"itemdlg_This", This);
2060 SetPropW(dropdown_hwnd, L"itemdlg_oldwndproc",
2061 (HANDLE)SetWindowLongPtrW(dropdown_hwnd, GWLP_WNDPROC, (LONG_PTR)dropdown_subclass_proc));
2064 ctrl_container_reparent(This, This->dlg_hwnd);
2065 init_explorerbrowser(This);
2066 init_toolbar(This, hwnd);
2067 update_control_text(This);
2068 update_layout(This);
2070 if(This->filterspec_count)
2071 events_OnTypeChange(This);
2073 if ((hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)))
2074 SetFocus(hitem);
2076 return FALSE;
2079 static LRESULT on_wm_size(FileDialogImpl *This)
2081 update_layout(This);
2082 return FALSE;
2085 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
2087 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
2088 TRACE("%p (%p)\n", This, mmi);
2090 /* FIXME */
2091 mmi->ptMinTrackSize.x = 640;
2092 mmi->ptMinTrackSize.y = 480;
2094 return FALSE;
2097 static LRESULT on_wm_destroy(FileDialogImpl *This)
2099 TRACE("%p\n", This);
2101 if(This->peb)
2103 IExplorerBrowser_Destroy(This->peb);
2104 IExplorerBrowser_Release(This->peb);
2105 This->peb = NULL;
2108 ctrl_container_reparent(This, NULL);
2109 This->dlg_hwnd = NULL;
2111 DeleteObject(This->hfont_opendropdown);
2112 This->hfont_opendropdown = NULL;
2114 return TRUE;
2117 static LRESULT on_idok(FileDialogImpl *This)
2119 TRACE("%p\n", This);
2121 if(SUCCEEDED(on_default_action(This)))
2122 EndDialog(This->dlg_hwnd, S_OK);
2124 return FALSE;
2127 static LRESULT on_idcancel(FileDialogImpl *This)
2129 TRACE("%p\n", This);
2131 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
2133 return FALSE;
2136 static LRESULT on_command_opendropdown(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2138 if(HIWORD(wparam) == BN_CLICKED)
2140 HWND hwnd = (HWND)lparam;
2141 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
2142 show_opendropdown(This);
2143 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
2146 return FALSE;
2149 static LRESULT on_browse_back(FileDialogImpl *This)
2151 TRACE("%p\n", This);
2152 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
2153 return FALSE;
2156 static LRESULT on_browse_forward(FileDialogImpl *This)
2158 TRACE("%p\n", This);
2159 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
2160 return FALSE;
2163 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2165 if(HIWORD(wparam) == CBN_SELCHANGE)
2167 IShellView *psv;
2168 HRESULT hr;
2169 LPWSTR filename;
2170 UINT prev_index = This->filetypeindex;
2172 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
2173 TRACE("File type selection changed to %d.\n", This->filetypeindex);
2175 if(prev_index == This->filetypeindex)
2176 return FALSE;
2178 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
2179 if(SUCCEEDED(hr))
2181 IShellView_Refresh(psv);
2182 IShellView_Release(psv);
2185 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
2187 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
2189 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
2190 if(ext)
2192 lstrcpyW(buf, filename);
2194 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
2195 PathRemoveExtensionW(buf);
2197 lstrcatW(buf, ext);
2198 set_file_name(This, buf);
2200 CoTaskMemFree(filename);
2203 /* The documentation claims that OnTypeChange is called only
2204 * when the dialog is opened, but this is obviously not the
2205 * case. */
2206 events_OnTypeChange(This);
2209 return FALSE;
2212 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2214 switch(LOWORD(wparam))
2216 case IDOK: return on_idok(This);
2217 case IDCANCEL: return on_idcancel(This);
2218 case psh1: return on_command_opendropdown(This, wparam, lparam);
2219 case IDC_NAVBACK: return on_browse_back(This);
2220 case IDC_NAVFORWARD: return on_browse_forward(This);
2221 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
2222 default: TRACE("Unknown command.\n");
2224 return FALSE;
2227 static INT_PTR CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
2229 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
2231 switch(umessage)
2233 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
2234 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
2235 case WM_SIZE: return on_wm_size(This);
2236 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
2237 case WM_DESTROY: return on_wm_destroy(This);
2240 return FALSE;
2243 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
2245 INT_PTR res;
2247 SetLastError(0);
2248 res = DialogBoxParamW(COMDLG32_hInstance,
2249 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
2250 parent, itemdlg_dlgproc, (LPARAM)This);
2251 This->dlg_hwnd = NULL;
2252 if(res == -1)
2254 ERR("Failed to show dialog (LastError: %ld)\n", GetLastError());
2255 return E_FAIL;
2258 TRACE("Returning 0x%08lx\n", (HRESULT)res);
2259 return (HRESULT)res;
2262 /**************************************************************************
2263 * IFileDialog implementation
2265 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
2267 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
2270 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
2271 REFIID riid,
2272 void **ppvObject)
2274 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2275 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2277 *ppvObject = NULL;
2278 if(IsEqualGUID(riid, &IID_IUnknown) ||
2279 IsEqualGUID(riid, &IID_IFileDialog) ||
2280 IsEqualGUID(riid, &IID_IFileDialog2))
2282 *ppvObject = iface;
2284 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
2286 *ppvObject = &This->u.IFileOpenDialog_iface;
2288 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
2290 *ppvObject = &This->u.IFileSaveDialog_iface;
2292 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
2294 *ppvObject = &This->IExplorerBrowserEvents_iface;
2296 else if(IsEqualGUID(riid, &IID_IServiceProvider))
2298 *ppvObject = &This->IServiceProvider_iface;
2300 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
2301 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
2302 IsEqualGUID(&IID_ICommDlgBrowser, riid))
2304 *ppvObject = &This->ICommDlgBrowser3_iface;
2306 else if(IsEqualGUID(&IID_IOleWindow, riid))
2308 *ppvObject = &This->IOleWindow_iface;
2310 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
2311 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
2313 *ppvObject = &This->IFileDialogCustomize_iface;
2315 else
2316 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
2318 if(*ppvObject)
2320 IUnknown_AddRef((IUnknown*)*ppvObject);
2321 return S_OK;
2324 return E_NOINTERFACE;
2327 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
2329 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2330 LONG ref = InterlockedIncrement(&This->ref);
2331 TRACE("%p - ref %ld\n", This, ref);
2333 return ref;
2336 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
2338 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2339 LONG ref = InterlockedDecrement(&This->ref);
2340 TRACE("%p - ref %ld\n", This, ref);
2342 if(!ref)
2344 UINT i;
2345 for(i = 0; i < This->filterspec_count; i++)
2347 LocalFree((void*)This->filterspecs[i].pszName);
2348 LocalFree((void*)This->filterspecs[i].pszSpec);
2350 HeapFree(GetProcessHeap(), 0, This->filterspecs);
2352 DestroyWindow(This->cctrls_hwnd);
2354 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
2355 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
2356 if(This->psi_folder) IShellItem_Release(This->psi_folder);
2357 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
2358 if(This->psia_results) IShellItemArray_Release(This->psia_results);
2360 LocalFree(This->set_filename);
2361 LocalFree(This->default_ext);
2362 LocalFree(This->custom_title);
2363 LocalFree(This->custom_okbutton);
2364 LocalFree(This->custom_cancelbutton);
2365 LocalFree(This->custom_filenamelabel);
2367 DestroyMenu(This->hmenu_opendropdown);
2368 DeleteObject(This->hfont_opendropdown);
2370 HeapFree(GetProcessHeap(), 0, This);
2373 return ref;
2376 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
2378 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2379 TRACE("%p (%p)\n", iface, hwndOwner);
2381 This->opendropdown_has_selection = FALSE;
2383 return create_dialog(This, hwndOwner);
2386 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
2387 const COMDLG_FILTERSPEC *rgFilterSpec)
2389 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2390 UINT i;
2391 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
2393 if(!rgFilterSpec)
2394 return E_INVALIDARG;
2396 if(This->filterspecs)
2397 return E_UNEXPECTED;
2399 if(!cFileTypes)
2400 return S_OK;
2402 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
2403 for(i = 0; i < cFileTypes; i++)
2405 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
2406 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
2408 This->filterspec_count = cFileTypes;
2410 return S_OK;
2413 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
2415 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2416 TRACE("%p (%d)\n", This, iFileType);
2418 if(!This->filterspecs)
2419 return E_FAIL;
2421 iFileType = max(iFileType, 1);
2422 iFileType = min(iFileType, This->filterspec_count);
2423 This->filetypeindex = iFileType-1;
2425 return S_OK;
2428 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
2430 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2431 TRACE("%p (%p)\n", This, piFileType);
2433 if(!piFileType)
2434 return E_INVALIDARG;
2436 if(This->filterspec_count == 0)
2437 *piFileType = 0;
2438 else
2439 *piFileType = This->filetypeindex + 1;
2441 return S_OK;
2444 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
2446 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2447 events_client *client;
2448 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
2450 if(!pfde || !pdwCookie)
2451 return E_INVALIDARG;
2453 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
2454 client->pfde = pfde;
2455 client->cookie = ++This->events_next_cookie;
2457 IFileDialogEvents_AddRef(pfde);
2458 *pdwCookie = client->cookie;
2460 list_add_tail(&This->events_clients, &client->entry);
2462 return S_OK;
2465 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
2467 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2468 events_client *client, *found = NULL;
2469 TRACE("%p (%ld)\n", This, dwCookie);
2471 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
2473 if(client->cookie == dwCookie)
2475 found = client;
2476 break;
2480 if(found)
2482 list_remove(&found->entry);
2483 IFileDialogEvents_Release(found->pfde);
2484 HeapFree(GetProcessHeap(), 0, found);
2485 return S_OK;
2488 return E_INVALIDARG;
2491 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
2493 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2494 TRACE("%p (0x%lx)\n", This, fos);
2496 if (fos & ~(FOS_OVERWRITEPROMPT | FOS_STRICTFILETYPES | FOS_NOCHANGEDIR | FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM
2497 | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_ALLOWMULTISELECT | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST
2498 | FOS_CREATEPROMPT | FOS_SHAREAWARE | FOS_NOREADONLYRETURN | FOS_NOTESTFILECREATE | FOS_HIDEMRUPLACES
2499 | FOS_HIDEPINNEDPLACES | FOS_NODEREFERENCELINKS | FOS_DONTADDTORECENT | FOS_FORCESHOWHIDDEN
2500 | FOS_DEFAULTNOMINIMODE | FOS_FORCEPREVIEWPANEON | FOS_SUPPORTSTREAMABLEITEMS))
2502 WARN("Invalid option %#lx\n", fos);
2503 return E_INVALIDARG;
2506 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
2508 WCHAR buf[30];
2509 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, ARRAY_SIZE(buf));
2510 IFileDialog2_SetTitle(iface, buf);
2513 This->options = fos;
2515 return S_OK;
2518 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
2520 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2521 TRACE("%p (%p)\n", This, pfos);
2523 if(!pfos)
2524 return E_INVALIDARG;
2526 *pfos = This->options;
2528 return S_OK;
2531 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
2533 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2534 TRACE("%p (%p)\n", This, psi);
2535 if(This->psi_defaultfolder)
2536 IShellItem_Release(This->psi_defaultfolder);
2538 This->psi_defaultfolder = psi;
2540 if(This->psi_defaultfolder)
2541 IShellItem_AddRef(This->psi_defaultfolder);
2543 return S_OK;
2546 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
2548 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2549 TRACE("%p (%p)\n", This, psi);
2550 if(This->psi_setfolder)
2551 IShellItem_Release(This->psi_setfolder);
2553 This->psi_setfolder = psi;
2555 if(This->psi_setfolder)
2556 IShellItem_AddRef(This->psi_setfolder);
2558 return S_OK;
2561 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
2563 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2564 TRACE("%p (%p)\n", This, ppsi);
2565 if(!ppsi)
2566 return E_INVALIDARG;
2568 /* FIXME:
2569 If the dialog is shown, return the current(ly selected) folder. */
2571 *ppsi = NULL;
2572 if(This->psi_folder)
2573 *ppsi = This->psi_folder;
2574 else if(This->psi_setfolder)
2575 *ppsi = This->psi_setfolder;
2576 else if(This->psi_defaultfolder)
2577 *ppsi = This->psi_defaultfolder;
2579 if(*ppsi)
2581 IShellItem_AddRef(*ppsi);
2582 return S_OK;
2585 return E_FAIL;
2588 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
2590 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2591 HRESULT hr;
2592 TRACE("%p (%p)\n", This, ppsi);
2594 if(!ppsi)
2595 return E_INVALIDARG;
2597 if(This->psia_selection)
2599 /* FIXME: Check filename edit box */
2600 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2601 return hr;
2604 return E_FAIL;
2607 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
2609 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2610 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2612 set_file_name(This, pszName);
2614 return S_OK;
2617 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
2619 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2620 TRACE("%p (%p)\n", iface, pszName);
2622 if(!pszName)
2623 return E_INVALIDARG;
2625 *pszName = NULL;
2626 get_file_name(This, pszName);
2627 return *pszName ? S_OK : E_FAIL;
2630 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
2632 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2633 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2635 LocalFree(This->custom_title);
2636 This->custom_title = StrDupW(pszTitle);
2637 update_control_text(This);
2639 return S_OK;
2642 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
2644 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2645 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2647 LocalFree(This->custom_okbutton);
2648 This->custom_okbutton = StrDupW(pszText);
2649 update_control_text(This);
2650 update_layout(This);
2652 return S_OK;
2655 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2657 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2658 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2660 LocalFree(This->custom_filenamelabel);
2661 This->custom_filenamelabel = StrDupW(pszLabel);
2662 update_control_text(This);
2663 update_layout(This);
2665 return S_OK;
2668 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
2670 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2671 HRESULT hr;
2672 TRACE("%p (%p)\n", This, ppsi);
2674 if(!ppsi)
2675 return E_INVALIDARG;
2677 if(This->psia_results)
2679 DWORD item_count;
2680 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2681 if(SUCCEEDED(hr))
2683 if(item_count != 1)
2684 return E_FAIL;
2686 /* Adds a reference. */
2687 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2690 return hr;
2693 return E_UNEXPECTED;
2696 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2698 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2699 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2700 return S_OK;
2703 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2705 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2706 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2708 LocalFree(This->default_ext);
2709 This->default_ext = StrDupW(pszDefaultExtension);
2711 return S_OK;
2714 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2716 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2717 TRACE("%p (0x%08lx)\n", This, hr);
2719 if(This->dlg_hwnd)
2720 EndDialog(This->dlg_hwnd, hr);
2722 return S_OK;
2725 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2727 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2728 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2729 This->client_guid = *guid;
2730 return S_OK;
2733 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2735 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2736 FIXME("stub - %p\n", This);
2737 return E_NOTIMPL;
2740 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2742 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2743 FIXME("stub - %p (%p)\n", This, pFilter);
2744 return E_NOTIMPL;
2747 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2749 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2750 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2752 LocalFree(This->custom_cancelbutton);
2753 This->custom_cancelbutton = StrDupW(pszLabel);
2754 update_control_text(This);
2755 update_layout(This);
2757 return S_OK;
2760 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2762 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2763 FIXME("stub - %p (%p)\n", This, psi);
2764 return E_NOTIMPL;
2767 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2768 IFileDialog2_fnQueryInterface,
2769 IFileDialog2_fnAddRef,
2770 IFileDialog2_fnRelease,
2771 IFileDialog2_fnShow,
2772 IFileDialog2_fnSetFileTypes,
2773 IFileDialog2_fnSetFileTypeIndex,
2774 IFileDialog2_fnGetFileTypeIndex,
2775 IFileDialog2_fnAdvise,
2776 IFileDialog2_fnUnadvise,
2777 IFileDialog2_fnSetOptions,
2778 IFileDialog2_fnGetOptions,
2779 IFileDialog2_fnSetDefaultFolder,
2780 IFileDialog2_fnSetFolder,
2781 IFileDialog2_fnGetFolder,
2782 IFileDialog2_fnGetCurrentSelection,
2783 IFileDialog2_fnSetFileName,
2784 IFileDialog2_fnGetFileName,
2785 IFileDialog2_fnSetTitle,
2786 IFileDialog2_fnSetOkButtonLabel,
2787 IFileDialog2_fnSetFileNameLabel,
2788 IFileDialog2_fnGetResult,
2789 IFileDialog2_fnAddPlace,
2790 IFileDialog2_fnSetDefaultExtension,
2791 IFileDialog2_fnClose,
2792 IFileDialog2_fnSetClientGuid,
2793 IFileDialog2_fnClearClientData,
2794 IFileDialog2_fnSetFilter,
2795 IFileDialog2_fnSetCancelButtonLabel,
2796 IFileDialog2_fnSetNavigationRoot
2799 /**************************************************************************
2800 * IFileOpenDialog
2802 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2804 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2807 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2808 REFIID riid, void **ppvObject)
2810 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2811 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2814 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2816 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2817 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2820 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2822 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2823 return IFileDialog2_Release(&This->IFileDialog2_iface);
2826 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2828 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2829 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2832 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2833 const COMDLG_FILTERSPEC *rgFilterSpec)
2835 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2836 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2839 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2841 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2842 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2845 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2847 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2848 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2851 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2852 DWORD *pdwCookie)
2854 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2855 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2858 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2860 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2861 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2864 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2866 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2867 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2870 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2872 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2873 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2876 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2878 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2879 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2882 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2884 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2885 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2888 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2890 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2891 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2894 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2896 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2897 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2900 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2902 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2903 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2906 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2908 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2909 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2912 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2914 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2915 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2918 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2920 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2921 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2924 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2926 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2927 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2930 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2932 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2933 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2936 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2938 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2939 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2942 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2943 LPCWSTR pszDefaultExtension)
2945 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2946 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2949 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2951 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2952 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2955 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2957 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2958 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2961 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2963 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2964 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2967 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2969 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2970 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2973 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2975 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2976 TRACE("%p (%p)\n", This, ppenum);
2978 *ppenum = This->psia_results;
2980 if(*ppenum)
2982 IShellItemArray_AddRef(*ppenum);
2983 return S_OK;
2986 return E_FAIL;
2989 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2991 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2992 TRACE("%p (%p)\n", This, ppsai);
2994 if(This->psia_selection)
2996 *ppsai = This->psia_selection;
2997 IShellItemArray_AddRef(*ppsai);
2998 return S_OK;
3001 return E_FAIL;
3004 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
3005 IFileOpenDialog_fnQueryInterface,
3006 IFileOpenDialog_fnAddRef,
3007 IFileOpenDialog_fnRelease,
3008 IFileOpenDialog_fnShow,
3009 IFileOpenDialog_fnSetFileTypes,
3010 IFileOpenDialog_fnSetFileTypeIndex,
3011 IFileOpenDialog_fnGetFileTypeIndex,
3012 IFileOpenDialog_fnAdvise,
3013 IFileOpenDialog_fnUnadvise,
3014 IFileOpenDialog_fnSetOptions,
3015 IFileOpenDialog_fnGetOptions,
3016 IFileOpenDialog_fnSetDefaultFolder,
3017 IFileOpenDialog_fnSetFolder,
3018 IFileOpenDialog_fnGetFolder,
3019 IFileOpenDialog_fnGetCurrentSelection,
3020 IFileOpenDialog_fnSetFileName,
3021 IFileOpenDialog_fnGetFileName,
3022 IFileOpenDialog_fnSetTitle,
3023 IFileOpenDialog_fnSetOkButtonLabel,
3024 IFileOpenDialog_fnSetFileNameLabel,
3025 IFileOpenDialog_fnGetResult,
3026 IFileOpenDialog_fnAddPlace,
3027 IFileOpenDialog_fnSetDefaultExtension,
3028 IFileOpenDialog_fnClose,
3029 IFileOpenDialog_fnSetClientGuid,
3030 IFileOpenDialog_fnClearClientData,
3031 IFileOpenDialog_fnSetFilter,
3032 IFileOpenDialog_fnGetResults,
3033 IFileOpenDialog_fnGetSelectedItems
3036 /**************************************************************************
3037 * IFileSaveDialog
3039 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
3041 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
3044 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
3045 REFIID riid,
3046 void **ppvObject)
3048 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3049 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3052 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
3054 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3055 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3058 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
3060 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3061 return IFileDialog2_Release(&This->IFileDialog2_iface);
3064 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
3066 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3067 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
3070 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
3071 const COMDLG_FILTERSPEC *rgFilterSpec)
3073 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3074 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
3077 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
3079 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3080 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
3083 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
3085 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3086 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
3089 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
3090 DWORD *pdwCookie)
3092 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3093 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
3096 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
3098 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3099 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
3102 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
3104 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3105 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
3108 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
3110 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3111 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
3114 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
3116 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3117 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
3120 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
3122 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3123 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
3126 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
3128 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3129 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
3132 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
3134 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3135 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
3138 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
3140 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3141 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
3144 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
3146 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3147 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
3150 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
3152 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3153 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
3156 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
3158 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3159 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
3162 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
3164 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3165 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
3168 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
3170 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3171 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
3174 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
3176 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3177 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
3180 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
3181 LPCWSTR pszDefaultExtension)
3183 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3184 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
3187 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
3189 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3190 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
3193 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
3195 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3196 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
3199 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
3201 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3202 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
3205 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
3207 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3208 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
3211 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
3213 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3214 FIXME("stub - %p (%p)\n", This, psi);
3215 return E_NOTIMPL;
3218 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
3220 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3221 FIXME("stub - %p (%p)\n", This, pStore);
3222 return E_NOTIMPL;
3225 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
3226 IPropertyDescriptionList *pList,
3227 BOOL fAppendDefault)
3229 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3230 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
3231 return E_NOTIMPL;
3234 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
3236 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3237 FIXME("stub - %p (%p)\n", This, ppStore);
3238 return E_NOTIMPL;
3241 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
3242 IShellItem *psi,
3243 IPropertyStore *pStore,
3244 HWND hwnd,
3245 IFileOperationProgressSink *pSink)
3247 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3248 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
3249 return E_NOTIMPL;
3252 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
3253 IFileSaveDialog_fnQueryInterface,
3254 IFileSaveDialog_fnAddRef,
3255 IFileSaveDialog_fnRelease,
3256 IFileSaveDialog_fnShow,
3257 IFileSaveDialog_fnSetFileTypes,
3258 IFileSaveDialog_fnSetFileTypeIndex,
3259 IFileSaveDialog_fnGetFileTypeIndex,
3260 IFileSaveDialog_fnAdvise,
3261 IFileSaveDialog_fnUnadvise,
3262 IFileSaveDialog_fnSetOptions,
3263 IFileSaveDialog_fnGetOptions,
3264 IFileSaveDialog_fnSetDefaultFolder,
3265 IFileSaveDialog_fnSetFolder,
3266 IFileSaveDialog_fnGetFolder,
3267 IFileSaveDialog_fnGetCurrentSelection,
3268 IFileSaveDialog_fnSetFileName,
3269 IFileSaveDialog_fnGetFileName,
3270 IFileSaveDialog_fnSetTitle,
3271 IFileSaveDialog_fnSetOkButtonLabel,
3272 IFileSaveDialog_fnSetFileNameLabel,
3273 IFileSaveDialog_fnGetResult,
3274 IFileSaveDialog_fnAddPlace,
3275 IFileSaveDialog_fnSetDefaultExtension,
3276 IFileSaveDialog_fnClose,
3277 IFileSaveDialog_fnSetClientGuid,
3278 IFileSaveDialog_fnClearClientData,
3279 IFileSaveDialog_fnSetFilter,
3280 IFileSaveDialog_fnSetSaveAsItem,
3281 IFileSaveDialog_fnSetProperties,
3282 IFileSaveDialog_fnSetCollectedProperties,
3283 IFileSaveDialog_fnGetProperties,
3284 IFileSaveDialog_fnApplyProperties
3287 /**************************************************************************
3288 * IExplorerBrowserEvents implementation
3290 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
3292 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
3295 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
3296 REFIID riid, void **ppvObject)
3298 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3299 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
3301 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3304 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
3306 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3307 TRACE("%p\n", This);
3308 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3311 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
3313 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3314 TRACE("%p\n", This);
3315 return IFileDialog2_Release(&This->IFileDialog2_iface);
3318 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
3319 PCIDLIST_ABSOLUTE pidlFolder)
3321 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3322 IShellItem *psi;
3323 HRESULT hr;
3324 TRACE("%p (%p)\n", This, pidlFolder);
3326 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
3327 if(SUCCEEDED(hr))
3329 hr = events_OnFolderChanging(This, psi);
3330 IShellItem_Release(psi);
3332 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
3333 if(hr == S_FALSE)
3334 hr = E_FAIL;
3336 return hr;
3338 else
3339 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
3341 return S_OK;
3344 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
3345 IShellView *psv)
3347 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3348 TRACE("%p (%p)\n", This, psv);
3349 return S_OK;
3352 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
3353 PCIDLIST_ABSOLUTE pidlFolder)
3355 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3356 HRESULT hr;
3357 TRACE("%p (%p)\n", This, pidlFolder);
3359 if(This->psi_folder)
3360 IShellItem_Release(This->psi_folder);
3362 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
3363 if(FAILED(hr))
3365 ERR("Failed to get the current folder.\n");
3366 This->psi_folder = NULL;
3369 events_OnFolderChange(This);
3371 return S_OK;
3374 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
3375 PCIDLIST_ABSOLUTE pidlFolder)
3377 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3378 TRACE("%p (%p)\n", This, pidlFolder);
3379 return S_OK;
3382 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
3383 IExplorerBrowserEvents_fnQueryInterface,
3384 IExplorerBrowserEvents_fnAddRef,
3385 IExplorerBrowserEvents_fnRelease,
3386 IExplorerBrowserEvents_fnOnNavigationPending,
3387 IExplorerBrowserEvents_fnOnViewCreated,
3388 IExplorerBrowserEvents_fnOnNavigationComplete,
3389 IExplorerBrowserEvents_fnOnNavigationFailed
3392 /**************************************************************************
3393 * IServiceProvider implementation
3395 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
3397 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
3400 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
3401 REFIID riid, void **ppvObject)
3403 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3404 TRACE("%p\n", This);
3405 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3408 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
3410 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3411 TRACE("%p\n", This);
3412 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3415 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
3417 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3418 TRACE("%p\n", This);
3419 return IFileDialog2_Release(&This->IFileDialog2_iface);
3422 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
3423 REFGUID guidService,
3424 REFIID riid, void **ppv)
3426 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3427 HRESULT hr = E_NOTIMPL;
3428 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
3430 *ppv = NULL;
3431 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
3432 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
3433 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
3434 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
3435 else
3436 FIXME("Interface %s requested from unknown service %s\n",
3437 debugstr_guid(riid), debugstr_guid(guidService));
3439 return hr;
3442 static const IServiceProviderVtbl vt_IServiceProvider = {
3443 IServiceProvider_fnQueryInterface,
3444 IServiceProvider_fnAddRef,
3445 IServiceProvider_fnRelease,
3446 IServiceProvider_fnQueryService
3449 /**************************************************************************
3450 * ICommDlgBrowser3 implementation
3452 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
3454 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
3457 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
3458 REFIID riid, void **ppvObject)
3460 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3461 TRACE("%p\n", This);
3462 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3465 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
3467 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3468 TRACE("%p\n", This);
3469 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3472 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
3474 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3475 TRACE("%p\n", This);
3476 return IFileDialog2_Release(&This->IFileDialog2_iface);
3479 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
3480 IShellView *shv)
3482 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3483 HRESULT hr;
3484 TRACE("%p (%p)\n", This, shv);
3486 hr = on_default_action(This);
3488 if(SUCCEEDED(hr))
3489 EndDialog(This->dlg_hwnd, S_OK);
3491 return S_OK;
3494 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
3495 IShellView *shv, ULONG uChange )
3497 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3498 IDataObject *new_selection;
3499 HRESULT hr;
3500 TRACE("%p (%p, %lx)\n", This, shv, uChange);
3502 switch(uChange)
3504 case CDBOSC_SELCHANGE:
3505 if(This->psia_selection)
3507 IShellItemArray_Release(This->psia_selection);
3508 This->psia_selection = NULL;
3511 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
3512 if(SUCCEEDED(hr))
3514 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
3515 (void**)&This->psia_selection);
3516 if(SUCCEEDED(hr))
3518 fill_filename_from_selection(This);
3519 events_OnSelectionChange(This);
3522 IDataObject_Release(new_selection);
3524 break;
3525 default:
3526 TRACE("Unhandled state change\n");
3528 return S_OK;
3531 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
3532 IShellView *shv, LPCITEMIDLIST pidl)
3534 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3535 IShellItem *psi;
3536 LPWSTR filename;
3537 LPITEMIDLIST parent_pidl;
3538 HRESULT hr;
3539 ULONG attr;
3540 TRACE("%p (%p, %p)\n", This, shv, pidl);
3542 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
3543 return S_OK;
3545 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3546 if(SUCCEEDED(hr))
3548 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3549 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3550 ILFree(parent_pidl);
3551 ILFree(full_pidl);
3553 if(FAILED(hr))
3555 ERR("Failed to get shellitem (%08lx).\n", hr);
3556 return S_OK;
3559 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3560 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3562 IShellItem_Release(psi);
3563 return S_OK;
3566 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
3568 IShellItem_Release(psi);
3569 return S_FALSE;
3572 hr = S_OK;
3573 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
3575 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
3576 hr = S_FALSE;
3577 CoTaskMemFree(filename);
3580 IShellItem_Release(psi);
3581 return hr;
3584 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
3585 IShellView *ppshv, DWORD dwNotifyType)
3587 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3588 FIXME("Stub: %p (%p, 0x%lx)\n", This, ppshv, dwNotifyType);
3589 return E_NOTIMPL;
3592 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
3593 IShellView *pshv,
3594 LPWSTR pszText, int cchMax)
3596 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3597 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
3598 return E_NOTIMPL;
3601 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
3603 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3604 FIXME("Stub: %p (%p)\n", This, pdwFlags);
3605 return E_NOTIMPL;
3608 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
3609 IShellView *pshv, int iColumn)
3611 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3612 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
3613 return E_NOTIMPL;
3616 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
3617 LPWSTR pszFileSpec, int cchFileSpec)
3619 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3620 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
3621 return E_NOTIMPL;
3624 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
3625 IShellView *pshv)
3627 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3628 FIXME("Stub: %p (%p)\n", This, pshv);
3629 return E_NOTIMPL;
3632 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
3633 ICommDlgBrowser3_fnQueryInterface,
3634 ICommDlgBrowser3_fnAddRef,
3635 ICommDlgBrowser3_fnRelease,
3636 ICommDlgBrowser3_fnOnDefaultCommand,
3637 ICommDlgBrowser3_fnOnStateChange,
3638 ICommDlgBrowser3_fnIncludeObject,
3639 ICommDlgBrowser3_fnNotify,
3640 ICommDlgBrowser3_fnGetDefaultMenuText,
3641 ICommDlgBrowser3_fnGetViewFlags,
3642 ICommDlgBrowser3_fnOnColumnClicked,
3643 ICommDlgBrowser3_fnGetCurrentFilter,
3644 ICommDlgBrowser3_fnOnPreviewCreated
3647 /**************************************************************************
3648 * IOleWindow implementation
3650 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
3652 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
3655 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
3657 FileDialogImpl *This = impl_from_IOleWindow(iface);
3658 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3661 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
3663 FileDialogImpl *This = impl_from_IOleWindow(iface);
3664 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3667 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
3669 FileDialogImpl *This = impl_from_IOleWindow(iface);
3670 return IFileDialog2_Release(&This->IFileDialog2_iface);
3673 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
3675 FileDialogImpl *This = impl_from_IOleWindow(iface);
3676 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
3677 return E_NOTIMPL;
3680 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
3682 FileDialogImpl *This = impl_from_IOleWindow(iface);
3683 TRACE("%p (%p)\n", This, phwnd);
3684 *phwnd = This->dlg_hwnd;
3685 return S_OK;
3688 static const IOleWindowVtbl vt_IOleWindow = {
3689 IOleWindow_fnQueryInterface,
3690 IOleWindow_fnAddRef,
3691 IOleWindow_fnRelease,
3692 IOleWindow_fnGetWindow,
3693 IOleWindow_fnContextSensitiveHelp
3696 /**************************************************************************
3697 * IFileDialogCustomize implementation
3699 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3701 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3704 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3705 REFIID riid, void **ppvObject)
3707 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3708 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3711 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3713 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3714 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3717 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3719 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3720 return IFileDialog2_Release(&This->IFileDialog2_iface);
3723 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3724 DWORD dwIDCtl)
3726 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3727 MENUINFO mi;
3728 TRACE("%p (%ld)\n", This, dwIDCtl);
3730 if (This->hmenu_opendropdown || get_cctrl(This, dwIDCtl))
3731 return E_UNEXPECTED;
3733 This->hmenu_opendropdown = CreatePopupMenu();
3735 if (!This->hmenu_opendropdown)
3736 return E_OUTOFMEMORY;
3738 mi.cbSize = sizeof(mi);
3739 mi.fMask = MIM_STYLE;
3740 mi.dwStyle = MNS_NOTIFYBYPOS;
3741 SetMenuInfo(This->hmenu_opendropdown, &mi);
3743 This->cctrl_opendropdown.hwnd = NULL;
3744 This->cctrl_opendropdown.wrapper_hwnd = NULL;
3745 This->cctrl_opendropdown.id = dwIDCtl;
3746 This->cctrl_opendropdown.dlgid = 0;
3747 This->cctrl_opendropdown.type = IDLG_CCTRL_OPENDROPDOWN;
3748 This->cctrl_opendropdown.cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
3749 list_init(&This->cctrl_opendropdown.sub_cctrls);
3750 list_init(&This->cctrl_opendropdown.sub_items);
3752 return S_OK;
3755 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3756 DWORD dwIDCtl,
3757 LPCWSTR pszLabel)
3759 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3760 customctrl *ctrl;
3761 TBBUTTON tbb;
3762 HRESULT hr;
3763 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszLabel);
3765 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3766 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3767 This->cctrl_def_height, &ctrl);
3768 if(SUCCEEDED(hr))
3770 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3771 ctrl->type = IDLG_CCTRL_MENU;
3773 /* Add the actual button with a popup menu. */
3774 tbb.iBitmap = I_IMAGENONE;
3775 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3776 tbb.iString = (DWORD_PTR)pszLabel;
3777 tbb.fsState = TBSTATE_ENABLED;
3778 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3779 tbb.idCommand = 1;
3781 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3784 return hr;
3787 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3788 DWORD dwIDCtl,
3789 LPCWSTR pszLabel)
3791 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3792 customctrl *ctrl;
3793 HRESULT hr;
3794 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszLabel);
3796 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3797 This->cctrl_def_height, &ctrl);
3798 if(SUCCEEDED(hr))
3799 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3801 return hr;
3804 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3805 DWORD dwIDCtl)
3807 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3808 customctrl *ctrl;
3809 HRESULT hr;
3810 TRACE("%p (%ld)\n", This, dwIDCtl);
3812 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3813 This->cctrl_def_height, &ctrl);
3814 if(SUCCEEDED(hr))
3815 ctrl->type = IDLG_CCTRL_COMBOBOX;
3817 return hr;
3820 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3821 DWORD dwIDCtl)
3823 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3824 customctrl *ctrl;
3825 HRESULT hr;
3826 TRACE("%p (%ld)\n", This, dwIDCtl);
3828 hr = cctrl_create_new(This, dwIDCtl, NULL, L"RadioButtonList", 0, 0, 0, &ctrl);
3829 if(SUCCEEDED(hr))
3831 ctrl->type = IDLG_CCTRL_RADIOBUTTONLIST;
3832 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)This);
3835 return hr;
3838 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3839 DWORD dwIDCtl,
3840 LPCWSTR pszLabel,
3841 BOOL bChecked)
3843 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3844 customctrl *ctrl;
3845 HRESULT hr;
3846 TRACE("%p (%ld, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3848 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0,
3849 This->cctrl_def_height, &ctrl);
3850 if(SUCCEEDED(hr))
3852 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3853 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3856 return hr;
3859 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3860 DWORD dwIDCtl,
3861 LPCWSTR pszText)
3863 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3864 customctrl *ctrl;
3865 HRESULT hr;
3866 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszText);
3868 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3869 This->cctrl_def_height, &ctrl);
3870 if(SUCCEEDED(hr))
3871 ctrl->type = IDLG_CCTRL_EDITBOX;
3873 return hr;
3876 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3877 DWORD dwIDCtl)
3879 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3880 customctrl *ctrl;
3881 HRESULT hr;
3882 TRACE("%p (%ld)\n", This, dwIDCtl);
3884 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3885 GetSystemMetrics(SM_CYEDGE), &ctrl);
3886 if(SUCCEEDED(hr))
3887 ctrl->type = IDLG_CCTRL_SEPARATOR;
3889 return hr;
3892 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3893 DWORD dwIDCtl,
3894 LPCWSTR pszText)
3896 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3897 customctrl *ctrl;
3898 HRESULT hr;
3899 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszText);
3901 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3902 This->cctrl_def_height, &ctrl);
3903 if(SUCCEEDED(hr))
3904 ctrl->type = IDLG_CCTRL_TEXT;
3906 return hr;
3909 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3910 DWORD dwIDCtl,
3911 LPCWSTR pszLabel)
3913 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3914 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3915 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszLabel);
3917 if(!ctrl) return E_INVALIDARG;
3919 switch(ctrl->type)
3921 case IDLG_CCTRL_MENU:
3922 case IDLG_CCTRL_PUSHBUTTON:
3923 case IDLG_CCTRL_CHECKBUTTON:
3924 case IDLG_CCTRL_TEXT:
3925 case IDLG_CCTRL_VISUALGROUP:
3926 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3927 break;
3928 case IDLG_CCTRL_OPENDROPDOWN:
3929 return E_NOTIMPL;
3930 default:
3931 break;
3934 return S_OK;
3937 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3938 DWORD dwIDCtl,
3939 CDCONTROLSTATEF *pdwState)
3941 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3942 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3943 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pdwState);
3945 if(!ctrl || ctrl->type == IDLG_CCTRL_OPENDROPDOWN) return E_NOTIMPL;
3947 *pdwState = ctrl->cdcstate;
3948 return S_OK;
3951 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3952 DWORD dwIDCtl,
3953 CDCONTROLSTATEF dwState)
3955 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3956 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3957 TRACE("%p (%ld, %x)\n", This, dwIDCtl, dwState);
3959 if(ctrl && ctrl->hwnd)
3961 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3963 if(dwState & CDCS_ENABLED)
3964 wndstyle &= ~(WS_DISABLED);
3965 else
3966 wndstyle |= WS_DISABLED;
3968 if(dwState & CDCS_VISIBLE)
3969 wndstyle |= WS_VISIBLE;
3970 else
3971 wndstyle &= ~(WS_VISIBLE);
3973 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3975 /* We save the state separately since at least one application
3976 * relies on being able to hide a control. */
3977 ctrl->cdcstate = dwState;
3980 return S_OK;
3983 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3984 DWORD dwIDCtl,
3985 WCHAR **ppszText)
3987 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3988 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3989 WCHAR len, *text;
3990 TRACE("%p (%ld, %p)\n", This, dwIDCtl, ppszText);
3992 if(!ctrl || !ctrl->hwnd || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3993 return E_FAIL;
3995 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3996 if(!text) return E_FAIL;
3998 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3999 *ppszText = text;
4000 return S_OK;
4003 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
4004 DWORD dwIDCtl,
4005 LPCWSTR pszText)
4007 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4008 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4009 TRACE("%p (%ld, %s)\n", This, dwIDCtl, debugstr_w(pszText));
4011 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
4012 return E_FAIL;
4014 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
4015 return S_OK;
4018 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
4019 DWORD dwIDCtl,
4020 BOOL *pbChecked)
4022 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4023 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4024 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pbChecked);
4026 if(ctrl && ctrl->hwnd)
4027 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
4029 return S_OK;
4032 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
4033 DWORD dwIDCtl,
4034 BOOL bChecked)
4036 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4037 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4038 TRACE("%p (%ld, %d)\n", This, dwIDCtl, bChecked);
4040 if(ctrl && ctrl->hwnd)
4041 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
4043 return S_OK;
4046 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
4048 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
4049 UINT i;
4050 if(!count || (count == CB_ERR))
4051 return -1;
4053 for(i = 0; i < count; i++)
4054 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
4055 return i;
4057 TRACE("Item with id %ld not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
4058 return -1;
4061 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
4062 DWORD dwIDCtl,
4063 DWORD dwIDItem,
4064 LPCWSTR pszLabel)
4066 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4067 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4068 HRESULT hr;
4069 TRACE("%p (%ld, %ld, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4071 if(!ctrl) return E_FAIL;
4073 switch(ctrl->type)
4075 case IDLG_CCTRL_COMBOBOX:
4077 UINT index;
4078 cctrl_item* item;
4080 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4082 if (FAILED(hr)) return hr;
4084 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
4085 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
4087 return S_OK;
4089 case IDLG_CCTRL_MENU:
4090 case IDLG_CCTRL_OPENDROPDOWN:
4092 cctrl_item* item;
4093 HMENU hmenu;
4095 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4097 if (FAILED(hr)) return hr;
4099 if (ctrl->type == IDLG_CCTRL_MENU)
4101 TBBUTTON tbb;
4102 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4103 hmenu = (HMENU)tbb.dwData;
4105 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4106 hmenu = This->hmenu_opendropdown;
4108 AppendMenuW(hmenu, MF_STRING, dwIDItem, pszLabel);
4109 return S_OK;
4111 case IDLG_CCTRL_RADIOBUTTONLIST:
4113 cctrl_item* item;
4115 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4117 if (SUCCEEDED(hr))
4119 item->hwnd = CreateWindowExW(0, WC_BUTTONW, pszLabel,
4120 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|BS_RADIOBUTTON|BS_MULTILINE,
4121 0, 0, 0, 0, ctrl->hwnd, ULongToHandle(dwIDItem), COMDLG32_hInstance, 0);
4123 if (!item->hwnd)
4125 ERR("Failed to create radio button\n");
4126 list_remove(&item->entry);
4127 item_free(item);
4128 return E_FAIL;
4132 return hr;
4134 default:
4135 break;
4138 return E_NOINTERFACE; /* win7 */
4141 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
4142 DWORD dwIDCtl,
4143 DWORD dwIDItem)
4145 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4146 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4147 TRACE("%p (%ld, %ld)\n", This, dwIDCtl, dwIDItem);
4149 if(!ctrl) return E_FAIL;
4151 switch(ctrl->type)
4153 case IDLG_CCTRL_COMBOBOX:
4155 cctrl_item* item;
4156 DWORD position;
4158 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4160 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
4162 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0) == CB_ERR)
4163 return E_FAIL;
4166 list_remove(&item->entry);
4167 item_free(item);
4169 return S_OK;
4171 case IDLG_CCTRL_MENU:
4172 case IDLG_CCTRL_OPENDROPDOWN:
4174 HMENU hmenu;
4175 cctrl_item* item;
4177 item = get_item(ctrl, dwIDItem, 0, NULL);
4179 if (!item)
4180 return E_UNEXPECTED;
4182 if (item->cdcstate & CDCS_VISIBLE)
4184 if (ctrl->type == IDLG_CCTRL_MENU)
4186 TBBUTTON tbb;
4187 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4188 hmenu = (HMENU)tbb.dwData;
4190 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4191 hmenu = This->hmenu_opendropdown;
4193 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
4194 return E_UNEXPECTED;
4197 list_remove(&item->entry);
4198 item_free(item);
4200 return S_OK;
4202 case IDLG_CCTRL_RADIOBUTTONLIST:
4204 cctrl_item* item;
4206 item = get_item(ctrl, dwIDItem, 0, NULL);
4208 if (!item)
4209 return E_UNEXPECTED;
4211 list_remove(&item->entry);
4212 item_free(item);
4214 return S_OK;
4216 default:
4217 break;
4220 return E_FAIL;
4223 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
4224 DWORD dwIDCtl)
4226 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4227 TRACE("%p (%ld)\n", This, dwIDCtl);
4229 /* Not implemented by native */
4230 return E_NOTIMPL;
4233 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
4234 DWORD dwIDCtl,
4235 DWORD dwIDItem,
4236 CDCONTROLSTATEF *pdwState)
4238 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4239 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4240 TRACE("%p (%ld, %ld, %p)\n", This, dwIDCtl, dwIDItem, pdwState);
4242 if(!ctrl) return E_FAIL;
4244 switch(ctrl->type)
4246 case IDLG_CCTRL_COMBOBOX:
4247 case IDLG_CCTRL_MENU:
4248 case IDLG_CCTRL_OPENDROPDOWN:
4249 case IDLG_CCTRL_RADIOBUTTONLIST:
4251 cctrl_item* item;
4253 item = get_item(ctrl, dwIDItem, 0, NULL);
4255 if (!item)
4256 return E_UNEXPECTED;
4258 *pdwState = item->cdcstate;
4260 return S_OK;
4262 default:
4263 break;
4266 return E_FAIL;
4269 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
4270 DWORD dwIDCtl,
4271 DWORD dwIDItem,
4272 CDCONTROLSTATEF dwState)
4274 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4275 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4276 TRACE("%p (%ld, %ld, %x)\n", This, dwIDCtl, dwIDItem, dwState);
4278 if(!ctrl) return E_FAIL;
4280 switch(ctrl->type)
4282 case IDLG_CCTRL_COMBOBOX:
4284 cctrl_item* item;
4285 BOOL visible, was_visible;
4286 DWORD position;
4288 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4290 if (!item)
4291 return E_UNEXPECTED;
4293 visible = ((dwState & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4294 was_visible = ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4296 if (visible && !was_visible)
4298 SendMessageW(ctrl->hwnd, CB_INSERTSTRING, position, (LPARAM)item->label);
4299 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, position, dwIDItem);
4301 else if (!visible && was_visible)
4303 SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0);
4306 item->cdcstate = dwState;
4308 return S_OK;
4310 case IDLG_CCTRL_MENU:
4311 case IDLG_CCTRL_OPENDROPDOWN:
4313 HMENU hmenu;
4314 cctrl_item* item;
4315 CDCONTROLSTATEF prev_state;
4316 DWORD position;
4318 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, &position);
4320 if (!item)
4321 return E_UNEXPECTED;
4323 prev_state = item->cdcstate;
4325 if (ctrl->type == IDLG_CCTRL_MENU)
4327 TBBUTTON tbb;
4328 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4329 hmenu = (HMENU)tbb.dwData;
4331 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4332 hmenu = This->hmenu_opendropdown;
4334 if (dwState & CDCS_VISIBLE)
4336 if (prev_state & CDCS_VISIBLE)
4338 /* change state */
4339 EnableMenuItem(hmenu, dwIDItem,
4340 MF_BYCOMMAND|((dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED));
4342 else
4344 /* show item */
4345 MENUITEMINFOW mii;
4347 mii.cbSize = sizeof(mii);
4348 mii.fMask = MIIM_ID|MIIM_STATE|MIIM_STRING;
4349 mii.fState = (dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED;
4350 mii.wID = dwIDItem;
4351 mii.dwTypeData = item->label;
4353 InsertMenuItemW(hmenu, position, TRUE, &mii);
4356 else if (prev_state & CDCS_VISIBLE)
4358 /* hide item */
4359 DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND);
4362 item->cdcstate = dwState;
4364 if (ctrl->type == IDLG_CCTRL_OPENDROPDOWN)
4366 update_control_text(This);
4367 update_layout(This);
4370 return S_OK;
4372 case IDLG_CCTRL_RADIOBUTTONLIST:
4374 cctrl_item* item;
4376 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, NULL);
4378 if (!item)
4379 return E_UNEXPECTED;
4381 /* Oddly, native allows setting this but doesn't seem to do anything with it. */
4382 item->cdcstate = dwState;
4384 return S_OK;
4386 default:
4387 break;
4390 return E_FAIL;
4393 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
4394 DWORD dwIDCtl,
4395 DWORD *pdwIDItem)
4397 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4398 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4399 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pdwIDItem);
4401 if(!ctrl) return E_FAIL;
4403 switch(ctrl->type)
4405 case IDLG_CCTRL_COMBOBOX:
4407 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
4408 if(index == CB_ERR)
4409 return E_FAIL;
4411 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
4412 return S_OK;
4414 case IDLG_CCTRL_OPENDROPDOWN:
4415 if (This->opendropdown_has_selection)
4417 *pdwIDItem = This->opendropdown_selection;
4418 return S_OK;
4420 else
4422 /* Return first enabled item. */
4423 cctrl_item* item = get_first_item(ctrl);
4425 if (item)
4427 *pdwIDItem = item->id;
4428 return S_OK;
4431 WARN("no enabled items in open dropdown\n");
4432 return E_FAIL;
4434 case IDLG_CCTRL_RADIOBUTTONLIST:
4436 cctrl_item* item;
4438 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
4440 if (SendMessageW(item->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED)
4442 *pdwIDItem = item->id;
4443 return S_OK;
4447 WARN("no checked items in radio button list\n");
4448 return E_FAIL;
4450 default:
4451 FIXME("Unsupported control type %d\n", ctrl->type);
4454 return E_NOTIMPL;
4457 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
4458 DWORD dwIDCtl,
4459 DWORD dwIDItem)
4461 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4462 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4463 TRACE("%p (%ld, %ld)\n", This, dwIDCtl, dwIDItem);
4465 if(!ctrl) return E_INVALIDARG;
4467 switch(ctrl->type)
4469 case IDLG_CCTRL_COMBOBOX:
4471 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
4473 if(index == -1)
4474 return E_INVALIDARG;
4476 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
4477 return E_FAIL;
4479 return S_OK;
4481 case IDLG_CCTRL_RADIOBUTTONLIST:
4483 cctrl_item* item;
4485 item = get_item(ctrl, dwIDItem, 0, NULL);
4487 if (item)
4489 radiobuttonlist_set_selected_item(This, ctrl, item);
4490 return S_OK;
4493 return E_INVALIDARG;
4495 default:
4496 FIXME("Unsupported control type %d\n", ctrl->type);
4499 return E_INVALIDARG;
4502 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
4503 DWORD dwIDCtl,
4504 LPCWSTR pszLabel)
4506 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4507 customctrl *vg;
4508 HRESULT hr;
4509 TRACE("%p (%ld, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
4511 if(This->cctrl_active_vg)
4512 return E_UNEXPECTED;
4514 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0,
4515 This->cctrl_def_height, &vg);
4516 if(SUCCEEDED(hr))
4518 vg->type = IDLG_CCTRL_VISUALGROUP;
4519 This->cctrl_active_vg = vg;
4522 return hr;
4525 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
4527 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4528 TRACE("%p\n", This);
4530 This->cctrl_active_vg = NULL;
4532 return S_OK;
4535 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
4536 DWORD dwIDCtl)
4538 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4539 FIXME("stub - %p (%ld)\n", This, dwIDCtl);
4540 return S_OK;
4543 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
4544 DWORD dwIDCtl,
4545 DWORD dwIDItem,
4546 LPCWSTR pszLabel)
4548 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4549 FIXME("stub - %p (%ld, %ld, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4550 return E_NOTIMPL;
4553 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
4554 IFileDialogCustomize_fnQueryInterface,
4555 IFileDialogCustomize_fnAddRef,
4556 IFileDialogCustomize_fnRelease,
4557 IFileDialogCustomize_fnEnableOpenDropDown,
4558 IFileDialogCustomize_fnAddMenu,
4559 IFileDialogCustomize_fnAddPushButton,
4560 IFileDialogCustomize_fnAddComboBox,
4561 IFileDialogCustomize_fnAddRadioButtonList,
4562 IFileDialogCustomize_fnAddCheckButton,
4563 IFileDialogCustomize_fnAddEditBox,
4564 IFileDialogCustomize_fnAddSeparator,
4565 IFileDialogCustomize_fnAddText,
4566 IFileDialogCustomize_fnSetControlLabel,
4567 IFileDialogCustomize_fnGetControlState,
4568 IFileDialogCustomize_fnSetControlState,
4569 IFileDialogCustomize_fnGetEditBoxText,
4570 IFileDialogCustomize_fnSetEditBoxText,
4571 IFileDialogCustomize_fnGetCheckButtonState,
4572 IFileDialogCustomize_fnSetCheckButtonState,
4573 IFileDialogCustomize_fnAddControlItem,
4574 IFileDialogCustomize_fnRemoveControlItem,
4575 IFileDialogCustomize_fnRemoveAllControlItems,
4576 IFileDialogCustomize_fnGetControlItemState,
4577 IFileDialogCustomize_fnSetControlItemState,
4578 IFileDialogCustomize_fnGetSelectedControlItem,
4579 IFileDialogCustomize_fnSetSelectedControlItem,
4580 IFileDialogCustomize_fnStartVisualGroup,
4581 IFileDialogCustomize_fnEndVisualGroup,
4582 IFileDialogCustomize_fnMakeProminent,
4583 IFileDialogCustomize_fnSetControlItemText
4586 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
4588 FileDialogImpl *fdimpl;
4589 HRESULT hr;
4590 IShellFolder *psf;
4591 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
4593 if(!ppv)
4594 return E_POINTER;
4595 if(pUnkOuter)
4596 return CLASS_E_NOAGGREGATION;
4598 fdimpl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FileDialogImpl));
4599 if(!fdimpl)
4600 return E_OUTOFMEMORY;
4602 fdimpl->ref = 1;
4603 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
4604 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
4605 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
4606 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
4607 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
4608 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
4610 if(type == ITEMDLG_TYPE_OPEN)
4612 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
4613 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
4614 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
4615 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
4617 else
4619 WCHAR buf[16];
4620 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
4621 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
4622 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
4624 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, ARRAY_SIZE(buf));
4625 fdimpl->custom_title = StrDupW(buf);
4626 fdimpl->custom_okbutton = StrDupW(buf);
4629 list_init(&fdimpl->events_clients);
4631 /* FIXME: The default folder setting should be restored for the
4632 * application if it was previously set. */
4633 SHGetDesktopFolder(&psf);
4634 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
4635 IShellFolder_Release(psf);
4637 hr = init_custom_controls(fdimpl);
4638 if(FAILED(hr))
4640 ERR("Failed to initialize custom controls (0x%08lx).\n", hr);
4641 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4642 return E_FAIL;
4645 hr = IFileDialog2_QueryInterface(&fdimpl->IFileDialog2_iface, riid, ppv);
4646 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4647 return hr;
4650 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4652 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
4655 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4657 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);