comdlg32: Implement SetControlItemState for menu controls.
[wine/multimedia.git] / dlls / comdlg32 / itemdlg.c
blob72f32e1726f7d5a0ce516e3aba9ffd70b195cb29
1 /*
2 * Common Item Dialog
4 * Copyright 2010,2011 David Hedberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "wingdi.h"
30 #include "winreg.h"
31 #include "shlwapi.h"
33 #include "commdlg.h"
34 #include "cdlg.h"
35 #include "filedlgbrowser.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
40 #define IDC_NAV_TOOLBAR 200
41 #define IDC_NAVBACK 201
42 #define IDC_NAVFORWARD 202
44 #include <initguid.h>
45 /* This seems to be another version of IID_IFileDialogCustomize. If
46 * there is any difference I have yet to find it. */
47 DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F);
49 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
51 static const WCHAR notifysink_childW[] = {'n','f','s','_','c','h','i','l','d',0};
52 static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0};
54 enum ITEMDLG_TYPE {
55 ITEMDLG_TYPE_OPEN,
56 ITEMDLG_TYPE_SAVE
59 enum ITEMDLG_CCTRL_TYPE {
60 IDLG_CCTRL_MENU,
61 IDLG_CCTRL_PUSHBUTTON,
62 IDLG_CCTRL_COMBOBOX,
63 IDLG_CCTRL_RADIOBUTTONLIST,
64 IDLG_CCTRL_CHECKBUTTON,
65 IDLG_CCTRL_EDITBOX,
66 IDLG_CCTRL_SEPARATOR,
67 IDLG_CCTRL_TEXT,
68 IDLG_CCTRL_VISUALGROUP
71 typedef struct cctrl_item {
72 DWORD id, parent_id;
73 LPWSTR label;
74 CDCONTROLSTATEF cdcstate;
75 struct list entry;
76 } cctrl_item;
78 typedef struct {
79 HWND hwnd, wrapper_hwnd;
80 UINT id, dlgid;
81 enum ITEMDLG_CCTRL_TYPE type;
82 CDCONTROLSTATEF cdcstate;
83 struct list entry;
85 struct list sub_cctrls;
86 struct list sub_cctrls_entry;
87 struct list sub_items;
88 } customctrl;
90 typedef struct {
91 struct list entry;
92 IFileDialogEvents *pfde;
93 DWORD cookie;
94 } events_client;
96 typedef struct FileDialogImpl {
97 IFileDialog2 IFileDialog2_iface;
98 union {
99 IFileOpenDialog IFileOpenDialog_iface;
100 IFileSaveDialog IFileSaveDialog_iface;
101 } u;
102 enum ITEMDLG_TYPE dlg_type;
103 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
104 IServiceProvider IServiceProvider_iface;
105 ICommDlgBrowser3 ICommDlgBrowser3_iface;
106 IOleWindow IOleWindow_iface;
107 IFileDialogCustomize IFileDialogCustomize_iface;
108 LONG ref;
110 FILEOPENDIALOGOPTIONS options;
111 COMDLG_FILTERSPEC *filterspecs;
112 UINT filterspec_count;
113 UINT filetypeindex;
115 struct list events_clients;
116 DWORD events_next_cookie;
118 IShellItemArray *psia_selection;
119 IShellItemArray *psia_results;
120 IShellItem *psi_defaultfolder;
121 IShellItem *psi_setfolder;
122 IShellItem *psi_folder;
124 HWND dlg_hwnd;
125 IExplorerBrowser *peb;
126 DWORD ebevents_cookie;
128 LPWSTR set_filename;
129 LPWSTR default_ext;
130 LPWSTR custom_title;
131 LPWSTR custom_okbutton;
132 LPWSTR custom_cancelbutton;
133 LPWSTR custom_filenamelabel;
135 UINT cctrl_width, cctrl_def_height, cctrls_cols;
136 UINT cctrl_indent;
137 HWND cctrls_hwnd;
138 struct list cctrls;
139 UINT_PTR cctrl_next_dlgid;
140 customctrl *cctrl_active_vg;
142 GUID client_guid;
143 } FileDialogImpl;
145 /**************************************************************************
146 * Event wrappers.
148 static HRESULT events_OnFileOk(FileDialogImpl *This)
150 events_client *cursor;
151 HRESULT hr = S_OK;
152 TRACE("%p\n", This);
154 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
156 TRACE("Notifying %p\n", cursor);
157 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
158 if(FAILED(hr) && hr != E_NOTIMPL)
159 break;
162 if(hr == E_NOTIMPL)
163 hr = S_OK;
165 return hr;
168 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
170 events_client *cursor;
171 HRESULT hr = S_OK;
172 TRACE("%p (%p)\n", This, folder);
174 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
176 TRACE("Notifying %p\n", cursor);
177 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
178 if(FAILED(hr) && hr != E_NOTIMPL)
179 break;
182 if(hr == E_NOTIMPL)
183 hr = S_OK;
185 return hr;
188 static void events_OnFolderChange(FileDialogImpl *This)
190 events_client *cursor;
191 TRACE("%p\n", This);
193 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
195 TRACE("Notifying %p\n", cursor);
196 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
200 static void events_OnSelectionChange(FileDialogImpl *This)
202 events_client *cursor;
203 TRACE("%p\n", This);
205 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
207 TRACE("Notifying %p\n", cursor);
208 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
212 static void events_OnTypeChange(FileDialogImpl *This)
214 events_client *cursor;
215 TRACE("%p\n", This);
217 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
219 TRACE("Notifying %p\n", cursor);
220 IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
224 static HRESULT events_OnOverwrite(FileDialogImpl *This, IShellItem *shellitem)
226 events_client *cursor;
227 HRESULT hr = S_OK;
228 FDE_OVERWRITE_RESPONSE response = FDEOR_DEFAULT;
229 TRACE("%p %p\n", This, shellitem);
231 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
233 TRACE("Notifying %p\n", cursor);
234 hr = IFileDialogEvents_OnOverwrite(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, shellitem, &response);
235 TRACE("<-- hr=%x response=%u\n", hr, response);
236 if(FAILED(hr) && hr != E_NOTIMPL)
237 break;
240 if(hr == E_NOTIMPL)
241 hr = S_OK;
243 if(SUCCEEDED(hr))
245 if (response == FDEOR_DEFAULT)
247 WCHAR buf[100];
248 int answer;
250 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, buf, 100);
251 answer = MessageBoxW(This->dlg_hwnd, buf, This->custom_title,
252 MB_YESNO | MB_ICONEXCLAMATION);
253 if (answer == IDNO || answer == IDCANCEL)
255 hr = E_FAIL;
258 else if (response == FDEOR_REFUSE)
259 hr = E_FAIL;
262 return hr;
265 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
267 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
270 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
272 events_client *cursor;
273 TRACE("%p\n", This);
275 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
277 IFileDialogControlEvents *pfdce;
278 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
280 TRACE("Notifying %p\n", cursor);
281 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
282 IFileDialogControlEvents_Release(pfdce);
286 return S_OK;
289 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
291 events_client *cursor;
292 TRACE("%p\n", This);
294 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
296 IFileDialogControlEvents *pfdce;
297 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
299 TRACE("Notifying %p\n", cursor);
300 IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
301 IFileDialogControlEvents_Release(pfdce);
305 return S_OK;
308 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
310 events_client *cursor;
311 TRACE("%p\n", This);
313 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
315 IFileDialogControlEvents *pfdce;
316 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
318 TRACE("Notifying %p\n", cursor);
319 IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
320 IFileDialogControlEvents_Release(pfdce);
324 return S_OK;
327 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
328 DWORD ctl_id)
330 events_client *cursor;
331 TRACE("%p\n", This);
333 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
335 IFileDialogControlEvents *pfdce;
336 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
338 TRACE("Notifying %p\n", cursor);
339 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
340 IFileDialogControlEvents_Release(pfdce);
344 return S_OK;
347 /**************************************************************************
348 * Helper functions.
350 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
352 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
353 UINT len;
355 if(!hwnd_edit)
357 if(This->set_filename)
359 len = lstrlenW(This->set_filename);
360 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
361 lstrcpyW(*str, This->set_filename);
362 return len;
364 return FALSE;
367 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
368 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
369 if(!*str)
370 return FALSE;
372 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
373 return len;
376 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
378 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
380 if(This->set_filename)
381 LocalFree(This->set_filename);
383 This->set_filename = StrDupW(str);
385 return SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str);
388 static void fill_filename_from_selection(FileDialogImpl *This)
390 IShellItem *psi;
391 LPWSTR *names;
392 HRESULT hr;
393 UINT item_count, valid_count;
394 UINT len_total, i;
396 if(!This->psia_selection)
397 return;
399 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
400 if(FAILED(hr) || !item_count)
401 return;
403 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
405 /* Get names of the selected items */
406 valid_count = 0; len_total = 0;
407 for(i = 0; i < item_count; i++)
409 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
410 if(SUCCEEDED(hr))
412 UINT attr;
414 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
415 if(SUCCEEDED(hr) &&
416 (( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
417 (!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
418 continue;
420 hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
421 if(SUCCEEDED(hr))
423 len_total += lstrlenW(names[valid_count]) + 3;
424 valid_count++;
426 IShellItem_Release(psi);
430 if(valid_count == 1)
432 set_file_name(This, names[0]);
433 CoTaskMemFree(names[0]);
435 else if(valid_count > 1)
437 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
438 LPWSTR cur_point = string;
440 for(i = 0; i < valid_count; i++)
442 LPWSTR file = names[i];
443 *cur_point++ = '\"';
444 lstrcpyW(cur_point, file);
445 cur_point += lstrlenW(file);
446 *cur_point++ = '\"';
447 *cur_point++ = ' ';
448 CoTaskMemFree(file);
450 *(cur_point-1) = '\0';
452 set_file_name(This, string);
453 HeapFree(GetProcessHeap(), 0, string);
456 HeapFree(GetProcessHeap(), 0, names);
457 return;
460 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
462 WCHAR *endpos, *ext;
464 lstrcpyW(buf, spec);
465 if( (endpos = StrChrW(buf, ';')) )
466 *endpos = '\0';
468 ext = PathFindExtensionW(buf);
469 if(StrChrW(ext, '*'))
470 return NULL;
472 return ext;
475 static BOOL shell_item_exists(IShellItem* shellitem)
477 LPWSTR filename;
478 HRESULT hr;
479 BOOL result;
481 hr = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &filename);
482 if (SUCCEEDED(hr))
484 /* FIXME: Implement SFGAO_VALIDATE in Wine and use it instead. */
485 result = (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES);
486 CoTaskMemFree(filename);
488 else
490 SFGAOF attributes;
491 result = SUCCEEDED(IShellItem_GetAttributes(shellitem, SFGAO_VALIDATE, &attributes));
494 return result;
497 static HRESULT on_default_action(FileDialogImpl *This)
499 IShellFolder *psf_parent, *psf_desktop;
500 LPITEMIDLIST *pidla;
501 LPITEMIDLIST current_folder;
502 LPWSTR fn_iter, files = NULL, tmp_files;
503 UINT file_count = 0, len, i;
504 int open_action;
505 HRESULT hr, ret = E_FAIL;
507 len = get_file_name(This, &tmp_files);
508 if(len)
510 UINT size_used;
511 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
512 CoTaskMemFree(tmp_files);
514 if(!file_count) return E_FAIL;
516 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
517 if(FAILED(hr))
519 ERR("Failed to get pidl for current directory.\n");
520 HeapFree(GetProcessHeap(), 0, files);
521 return hr;
524 TRACE("Acting on %d file(s).\n", file_count);
526 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
527 open_action = ONOPEN_OPEN;
528 fn_iter = files;
530 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
532 WCHAR canon_filename[MAX_PATH];
533 psf_parent = NULL;
535 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
537 if( (This->options & FOS_NOVALIDATE) &&
538 !(This->options & FOS_FILEMUSTEXIST) )
539 open_action = ONOPEN_OPEN;
540 else
541 open_action = ONOPEN_BROWSE;
543 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
544 This->options & ~FOS_FILEMUSTEXIST,
545 (This->dlg_type == ITEMDLG_TYPE_SAVE),
546 open_action);
548 /* Add the proper extension */
549 if(open_action == ONOPEN_OPEN)
551 static const WCHAR dotW[] = {'.',0};
553 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
555 WCHAR extbuf[MAX_PATH], *newext = NULL;
557 if(This->filterspec_count)
559 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
561 else if(This->default_ext)
563 lstrcpyW(extbuf, dotW);
564 lstrcatW(extbuf, This->default_ext);
565 newext = extbuf;
568 if(newext)
570 WCHAR *ext = PathFindExtensionW(canon_filename);
571 if(lstrcmpW(ext, newext))
572 lstrcatW(canon_filename, newext);
575 else
577 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
578 !PathFileExistsW(canon_filename))
580 if(This->default_ext)
582 lstrcatW(canon_filename, dotW);
583 lstrcatW(canon_filename, This->default_ext);
585 if(!PathFileExistsW(canon_filename))
587 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
588 open_action = ONOPEN_BROWSE;
591 else
593 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
594 open_action = ONOPEN_BROWSE;
600 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
602 if(psf_parent && !(open_action == ONOPEN_BROWSE))
603 IShellFolder_Release(psf_parent);
605 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
608 HeapFree(GetProcessHeap(), 0, files);
609 ILFree(current_folder);
611 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
612 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
614 switch(open_action)
616 case ONOPEN_SEARCH:
617 FIXME("Filtering not implemented.\n");
618 break;
620 case ONOPEN_BROWSE:
621 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
622 if(FAILED(hr))
623 ERR("Failed to browse to directory: %08x\n", hr);
625 IShellFolder_Release(psf_parent);
626 break;
628 case ONOPEN_OPEN:
629 hr = SHGetDesktopFolder(&psf_desktop);
630 if(SUCCEEDED(hr))
632 if(This->psia_results)
634 IShellItemArray_Release(This->psia_results);
635 This->psia_results = NULL;
638 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
639 &This->psia_results);
641 IShellFolder_Release(psf_desktop);
643 if(FAILED(hr))
644 break;
646 if(This->options & FOS_PICKFOLDERS)
648 SFGAOF attributes;
649 hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
650 if(hr != S_OK)
652 WCHAR buf[64];
653 LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, sizeof(buf)/sizeof(WCHAR));
655 MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
657 IShellItemArray_Release(This->psia_results);
658 This->psia_results = NULL;
659 break;
663 if((This->options & FOS_OVERWRITEPROMPT) && This->dlg_type == ITEMDLG_TYPE_SAVE)
665 IShellItem *shellitem;
667 for (i=0; SUCCEEDED(hr) && i<file_count; i++)
669 hr = IShellItemArray_GetItemAt(This->psia_results, i, &shellitem);
670 if (SUCCEEDED(hr))
672 if (shell_item_exists(shellitem))
673 hr = events_OnOverwrite(This, shellitem);
675 IShellItem_Release(shellitem);
679 if (FAILED(hr))
680 break;
683 if(events_OnFileOk(This) == S_OK)
684 ret = S_OK;
686 break;
688 default:
689 ERR("Failed.\n");
690 break;
693 /* Clean up */
694 for(i = 0; i < file_count; i++)
695 ILFree(pidla[i]);
696 HeapFree(GetProcessHeap(), 0, pidla);
698 /* Success closes the dialog */
699 return ret;
702 /**************************************************************************
703 * Control item functions.
706 static void item_free(cctrl_item *item)
708 HeapFree(GetProcessHeap(), 0, item->label);
709 HeapFree(GetProcessHeap(), 0, item);
712 static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF visible_flags, DWORD* position)
714 DWORD dummy;
715 cctrl_item* item;
717 if (!position) position = &dummy;
719 *position = 0;
721 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
723 if (item->id == itemid)
724 return item;
726 if ((item->cdcstate & visible_flags) == visible_flags)
727 (*position)++;
730 return NULL;
733 static HRESULT add_item(customctrl* parent, DWORD itemid, LPCWSTR label, cctrl_item** result)
735 cctrl_item* item;
736 LPWSTR label_copy;
738 if (get_item(parent, itemid, 0, NULL))
739 return E_INVALIDARG;
741 item = HeapAlloc(GetProcessHeap(), 0, sizeof(*item));
742 label_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(label)+1)*sizeof(WCHAR));
744 if (!item || !label_copy)
746 HeapFree(GetProcessHeap(), 0, item);
747 HeapFree(GetProcessHeap(), 0, label_copy);
748 return E_OUTOFMEMORY;
751 item->id = itemid;
752 item->parent_id = parent->id;
753 lstrcpyW(label_copy, label);
754 item->label = label_copy;
755 item->cdcstate = CDCS_VISIBLE|CDCS_ENABLED;
756 list_add_tail(&parent->sub_items, &item->entry);
758 return S_OK;
761 /**************************************************************************
762 * Control functions.
764 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
766 customctrl *ctrl, *sub_ctrl;
768 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
770 if(ctrl->dlgid == dlgid)
771 return ctrl;
773 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
774 if(sub_ctrl->dlgid == dlgid)
775 return sub_ctrl;
778 ERR("Failed to find control with dialog id %d\n", dlgid);
779 return NULL;
782 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
784 customctrl *ctrl, *sub_ctrl;
786 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
788 if(ctrl->id == ctlid)
789 return ctrl;
791 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
792 if(sub_ctrl->id == ctlid)
793 return sub_ctrl;
797 TRACE("No existing control with control id %d\n", ctlid);
798 return NULL;
801 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
803 LPWSTR text;
804 UINT len, final_width;
805 UINT lines, final_height;
806 SIZE size;
807 RECT rc;
808 HDC hdc;
809 WCHAR *c;
811 TRACE("\n");
813 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
814 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
815 if(!text) return;
816 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
818 hdc = GetDC(hctrl);
819 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
820 ReleaseDC(hctrl, hdc);
822 if(len && multiline)
824 /* FIXME: line-wrap */
825 for(lines = 1, c = text; *c != '\0'; c++)
826 if(*c == '\n') lines++;
828 final_height = size.cy*lines + 2*4;
830 else
832 GetWindowRect(hctrl, &rc);
833 final_height = rc.bottom - rc.top;
836 final_width = min(max(size.cx, min_width) + 4, max_width);
837 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
838 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
840 HeapFree(GetProcessHeap(), 0, text);
843 static UINT ctrl_get_height(customctrl *ctrl) {
844 RECT rc;
845 GetWindowRect(ctrl->wrapper_hwnd, &rc);
846 return rc.bottom - rc.top;
849 static void ctrl_free(customctrl *ctrl)
851 customctrl *sub_cur1, *sub_cur2;
852 cctrl_item *item_cur1, *item_cur2;
854 TRACE("Freeing control %p\n", ctrl);
855 if(ctrl->type == IDLG_CCTRL_MENU)
857 TBBUTTON tbb;
858 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
859 DestroyMenu((HMENU)tbb.dwData);
862 LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
864 list_remove(&sub_cur1->sub_cctrls_entry);
865 ctrl_free(sub_cur1);
868 LIST_FOR_EACH_ENTRY_SAFE(item_cur1, item_cur2, &ctrl->sub_items, cctrl_item, entry)
870 list_remove(&item_cur1->entry);
871 item_free(item_cur1);
874 DestroyWindow(ctrl->hwnd);
875 HeapFree(GetProcessHeap(), 0, ctrl);
878 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
880 RECT rc;
881 UINT total_height;
882 customctrl *sub_ctrl;
884 switch(ctrl->type)
886 case IDLG_CCTRL_PUSHBUTTON:
887 case IDLG_CCTRL_COMBOBOX:
888 case IDLG_CCTRL_CHECKBUTTON:
889 case IDLG_CCTRL_TEXT:
890 ctrl_resize(ctrl->hwnd, 160, 160, TRUE);
891 GetWindowRect(ctrl->hwnd, &rc);
892 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
893 SWP_NOZORDER|SWP_NOMOVE);
894 break;
895 case IDLG_CCTRL_VISUALGROUP:
896 total_height = 0;
897 ctrl_resize(ctrl->hwnd, 0, This->cctrl_indent, TRUE);
899 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
901 customctrl_resize(This, sub_ctrl);
902 SetWindowPos(sub_ctrl->wrapper_hwnd, NULL, This->cctrl_indent, total_height, 0, 0,
903 SWP_NOZORDER|SWP_NOSIZE);
905 total_height += ctrl_get_height(sub_ctrl);
908 /* The label should be right adjusted */
910 UINT width, height;
912 GetWindowRect(ctrl->hwnd, &rc);
913 width = rc.right - rc.left;
914 height = rc.bottom - rc.top;
916 SetWindowPos(ctrl->hwnd, NULL, This->cctrl_indent - width, 0, width, height, SWP_NOZORDER);
919 /* Resize the wrapper window to fit all the sub controls */
920 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, This->cctrl_width + This->cctrl_indent, total_height,
921 SWP_NOZORDER|SWP_NOMOVE);
922 break;
923 case IDLG_CCTRL_RADIOBUTTONLIST:
924 case IDLG_CCTRL_EDITBOX:
925 case IDLG_CCTRL_SEPARATOR:
926 case IDLG_CCTRL_MENU:
927 /* Nothing */
928 break;
932 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
934 FileDialogImpl *This = crs->lpCreateParams;
935 TRACE("%p\n", This);
937 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
938 return TRUE;
941 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
943 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
945 TRACE("%p, %lx\n", This, wparam);
947 if(ctrl)
949 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
951 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
952 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
954 else
955 cctrl_event_OnButtonClicked(This, ctrl->id);
958 return TRUE;
961 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
963 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
964 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
966 if(ctrl)
968 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
969 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
971 cctrl_event_OnItemSelected(This, ctrl->id, selid);
973 return TRUE;
976 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
978 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
979 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
980 POINT pt = { 0, nmtb->rcButton.bottom };
981 TBBUTTON tbb;
982 UINT idcmd;
984 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
986 if(ctrl)
988 cctrl_event_OnControlActivating(This,ctrl->id);
990 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
991 ClientToScreen(ctrl->hwnd, &pt);
992 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
993 if(idcmd)
994 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
997 return TBDDRET_DEFAULT;
1000 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1002 switch(HIWORD(wparam))
1004 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
1005 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
1008 return FALSE;
1011 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1013 NMHDR *nmhdr = (NMHDR*)lparam;
1015 switch(nmhdr->code)
1017 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
1020 return FALSE;
1023 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1025 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1026 customctrl *ctrl;
1027 HWND hwnd_child;
1028 RECT rc;
1030 switch(message)
1032 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
1033 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
1034 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
1035 case WM_SIZE:
1036 hwnd_child = GetPropW(hwnd, notifysink_childW);
1037 ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA);
1038 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
1040 GetClientRect(hwnd, &rc);
1041 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1043 return TRUE;
1046 return DefWindowProcW(hwnd, message, wparam, lparam);
1049 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
1050 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
1051 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
1053 HWND ns_hwnd, control_hwnd, parent_hwnd;
1054 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
1055 customctrl *ctrl;
1057 if(get_cctrl(This, id))
1058 return E_UNEXPECTED; /* Duplicate id */
1060 if(This->cctrl_active_vg)
1061 parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
1062 else
1063 parent_hwnd = This->cctrls_hwnd;
1065 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
1066 0, 0, This->cctrl_width, height, parent_hwnd,
1067 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
1068 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
1069 0, 0, This->cctrl_width, height, ns_hwnd,
1070 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
1072 if(!ns_hwnd || !control_hwnd)
1074 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
1075 DestroyWindow(ns_hwnd);
1076 DestroyWindow(control_hwnd);
1078 return E_FAIL;
1081 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
1083 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
1084 if(!ctrl)
1085 return E_OUTOFMEMORY;
1087 ctrl->hwnd = control_hwnd;
1088 ctrl->wrapper_hwnd = ns_hwnd;
1089 ctrl->id = id;
1090 ctrl->dlgid = This->cctrl_next_dlgid;
1091 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
1092 list_init(&ctrl->sub_cctrls);
1093 list_init(&ctrl->sub_items);
1095 if(This->cctrl_active_vg)
1096 list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
1097 else
1098 list_add_tail(&This->cctrls, &ctrl->entry);
1100 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl);
1102 if(ppctrl) *ppctrl = ctrl;
1104 This->cctrl_next_dlgid++;
1105 return S_OK;
1108 /**************************************************************************
1109 * Container functions.
1111 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
1113 UINT container_height;
1114 UINT column_width;
1115 UINT nr_of_cols;
1116 UINT max_control_height, total_height = 0;
1117 UINT cur_col_pos, cur_row_pos;
1118 customctrl *ctrl;
1119 BOOL fits_height;
1120 static const UINT cspacing = 90; /* Columns are spaced with 90px */
1121 static const UINT rspacing = 4; /* Rows are spaced with 4 px. */
1123 /* Given the new width of the container, this function determines the
1124 * needed height of the container and places the controls according to
1125 * the new layout. Returns the new height.
1128 TRACE("%p\n", This);
1130 column_width = This->cctrl_width + cspacing;
1131 nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
1133 /* We don't need to do anything unless the number of visible columns has changed. */
1134 if(nr_of_cols == This->cctrls_cols)
1136 RECT rc;
1137 GetWindowRect(This->cctrls_hwnd, &rc);
1138 return rc.bottom - rc.top;
1141 This->cctrls_cols = nr_of_cols;
1143 /* Get the size of the tallest control, and the total size of
1144 * all the controls to figure out the number of slots we need.
1146 max_control_height = 0;
1147 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1149 if(ctrl->cdcstate & CDCS_VISIBLE)
1151 UINT control_height = ctrl_get_height(ctrl);
1152 max_control_height = max(max_control_height, control_height);
1154 total_height += control_height + rspacing;
1158 if(!total_height)
1159 return 0;
1161 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
1162 TRACE("Guess: container_height: %d\n",container_height);
1164 /* Incrementally increase container_height until all the controls
1165 * fit.
1167 do {
1168 UINT columns_needed = 1;
1169 cur_row_pos = 0;
1171 fits_height = TRUE;
1172 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1174 if(ctrl->cdcstate & CDCS_VISIBLE)
1176 UINT control_height = ctrl_get_height(ctrl);
1178 if(cur_row_pos + control_height > container_height)
1180 if(++columns_needed > nr_of_cols)
1182 container_height += 1;
1183 fits_height = FALSE;
1184 break;
1186 cur_row_pos = 0;
1189 cur_row_pos += control_height + rspacing;
1192 } while(!fits_height);
1194 TRACE("Final container height: %d\n", container_height);
1196 /* Move the controls to their final destination
1198 cur_col_pos = 0, cur_row_pos = 0;
1199 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1201 if(ctrl->cdcstate & CDCS_VISIBLE)
1203 RECT rc;
1204 UINT control_height, control_indent;
1205 GetWindowRect(ctrl->wrapper_hwnd, &rc);
1206 control_height = rc.bottom - rc.top;
1208 if(cur_row_pos + control_height > container_height)
1210 cur_row_pos = 0;
1211 cur_col_pos += This->cctrl_width + cspacing;
1215 if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
1216 control_indent = 0;
1217 else
1218 control_indent = This->cctrl_indent;
1220 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
1221 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1223 cur_row_pos += control_height + rspacing;
1227 /* Sanity check */
1228 if(cur_row_pos + This->cctrl_width > container_width)
1229 ERR("-- Failed to place controls properly.\n");
1231 return container_height;
1234 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
1236 LONG wndstyle;
1238 if(parent)
1240 customctrl *ctrl, *sub_ctrl;
1241 HFONT font;
1243 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1244 wndstyle &= ~(WS_POPUP);
1245 wndstyle |= WS_CHILD;
1246 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1248 SetParent(This->cctrls_hwnd, parent);
1249 ShowWindow(This->cctrls_hwnd, TRUE);
1251 /* Set the fonts to match the dialog font. */
1252 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
1253 if(!font)
1254 ERR("Failed to get font handle from dialog.\n");
1256 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1258 if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1260 /* If this is a VisualGroup */
1261 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1263 if(font) SendMessageW(sub_ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1266 customctrl_resize(This, ctrl);
1269 else
1271 ShowWindow(This->cctrls_hwnd, FALSE);
1273 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1274 wndstyle &= ~(WS_CHILD);
1275 wndstyle |= WS_POPUP;
1276 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1278 SetParent(This->cctrls_hwnd, NULL);
1282 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
1284 FileDialogImpl *This = crs->lpCreateParams;
1285 TRACE("%p\n", This);
1287 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1288 return TRUE;
1291 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
1293 customctrl *cur1, *cur2;
1294 TRACE("%p\n", This);
1296 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1298 list_remove(&cur1->entry);
1299 ctrl_free(cur1);
1302 return TRUE;
1305 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1307 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1309 switch(umessage)
1311 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1312 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1313 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1316 return FALSE;
1319 static HRESULT init_custom_controls(FileDialogImpl *This)
1321 WNDCLASSW wc;
1322 static const WCHAR ctrl_container_classname[] =
1323 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1325 InitCommonControlsEx(NULL);
1327 This->cctrl_width = 160; /* Controls have a fixed width */
1328 This->cctrl_indent = 100;
1329 This->cctrl_def_height = 23;
1330 This->cctrls_cols = 0;
1332 This->cctrl_next_dlgid = 0x2000;
1333 list_init(&This->cctrls);
1334 This->cctrl_active_vg = NULL;
1336 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1338 wc.style = CS_HREDRAW | CS_VREDRAW;
1339 wc.lpfnWndProc = ctrl_container_wndproc;
1340 wc.cbClsExtra = 0;
1341 wc.cbWndExtra = 0;
1342 wc.hInstance = COMDLG32_hInstance;
1343 wc.hIcon = 0;
1344 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1345 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1346 wc.lpszMenuName = NULL;
1347 wc.lpszClassName = ctrl_container_classname;
1349 if(!RegisterClassW(&wc)) return E_FAIL;
1352 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1353 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1354 0, 0, 0, 0, NULL, 0,
1355 COMDLG32_hInstance, This);
1356 if(!This->cctrls_hwnd)
1357 return E_FAIL;
1359 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1361 /* Register class for */
1362 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1363 wc.hInstance != COMDLG32_hInstance)
1365 wc.style = CS_HREDRAW | CS_VREDRAW;
1366 wc.lpfnWndProc = notifysink_proc;
1367 wc.cbClsExtra = 0;
1368 wc.cbWndExtra = 0;
1369 wc.hInstance = COMDLG32_hInstance;
1370 wc.hIcon = 0;
1371 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1372 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1373 wc.lpszMenuName = NULL;
1374 wc.lpszClassName = floatnotifysinkW;
1376 if (!RegisterClassW(&wc))
1377 ERR("Failed to register FloatNotifySink window class.\n");
1380 return S_OK;
1383 /**************************************************************************
1384 * Window related functions.
1386 static void update_layout(FileDialogImpl *This)
1388 HDWP hdwp;
1389 HWND hwnd;
1390 RECT dialog_rc;
1391 RECT cancel_rc, open_rc;
1392 RECT filetype_rc, filename_rc, filenamelabel_rc;
1393 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1394 static const UINT vspacing = 4, hspacing = 4;
1395 static const UINT min_width = 320, min_height = 200;
1397 if (!GetClientRect(This->dlg_hwnd, &dialog_rc))
1399 TRACE("Invalid dialog window, not updating layout\n");
1400 return;
1403 if(dialog_rc.right < min_width || dialog_rc.bottom < min_height)
1405 TRACE("Dialog size (%d, %d) too small, not updating layout\n", dialog_rc.right, dialog_rc.bottom);
1406 return;
1409 /****
1410 * Calculate the size of the dialog and all the parts.
1413 /* Cancel button */
1414 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1415 if(hwnd)
1417 int cancel_width, cancel_height;
1418 GetWindowRect(hwnd, &cancel_rc);
1419 cancel_width = cancel_rc.right - cancel_rc.left;
1420 cancel_height = cancel_rc.bottom - cancel_rc.top;
1422 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1423 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1424 cancel_rc.right = cancel_rc.left + cancel_width;
1425 cancel_rc.bottom = cancel_rc.top + cancel_height;
1428 /* Open/Save button */
1429 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1430 if(hwnd)
1432 int open_width, open_height;
1433 GetWindowRect(hwnd, &open_rc);
1434 open_width = open_rc.right - open_rc.left;
1435 open_height = open_rc.bottom - open_rc.top;
1437 open_rc.left = cancel_rc.left - open_width - hspacing;
1438 open_rc.top = cancel_rc.top;
1439 open_rc.right = open_rc.left + open_width;
1440 open_rc.bottom = open_rc.top + open_height;
1443 /* The filetype combobox. */
1444 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1445 if(hwnd)
1447 int filetype_width, filetype_height;
1448 GetWindowRect(hwnd, &filetype_rc);
1450 filetype_width = filetype_rc.right - filetype_rc.left;
1451 filetype_height = filetype_rc.bottom - filetype_rc.top;
1453 filetype_rc.right = cancel_rc.right;
1455 filetype_rc.left = filetype_rc.right - filetype_width;
1456 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1457 filetype_rc.bottom = filetype_rc.top + filetype_height;
1459 if(!This->filterspec_count)
1460 filetype_rc.left = filetype_rc.right;
1463 /* Filename label. */
1464 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1465 if(hwnd)
1467 int filetypelabel_width, filetypelabel_height;
1468 GetWindowRect(hwnd, &filenamelabel_rc);
1470 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1471 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1473 filenamelabel_rc.left = 160; /* FIXME */
1474 filenamelabel_rc.top = filetype_rc.top;
1475 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1476 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1479 /* Filename edit box. */
1480 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1481 if(hwnd)
1483 int filename_width, filename_height;
1484 GetWindowRect(hwnd, &filename_rc);
1486 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1487 filename_height = filename_rc.bottom - filename_rc.top;
1489 filename_rc.left = filenamelabel_rc.right + hspacing;
1490 filename_rc.top = filetype_rc.top;
1491 filename_rc.right = filename_rc.left + filename_width;
1492 filename_rc.bottom = filename_rc.top + filename_height;
1495 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1496 if(hwnd)
1498 GetWindowRect(hwnd, &toolbar_rc);
1499 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1502 /* The custom controls */
1503 customctrls_rc.left = dialog_rc.left + hspacing;
1504 customctrls_rc.right = dialog_rc.right - hspacing;
1505 customctrls_rc.bottom = filename_rc.top - vspacing;
1506 customctrls_rc.top = customctrls_rc.bottom -
1507 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1509 /* The ExplorerBrowser control. */
1510 ebrowser_rc.left = dialog_rc.left + hspacing;
1511 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1512 ebrowser_rc.right = dialog_rc.right - hspacing;
1513 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1515 /****
1516 * Move everything to the right place.
1519 /* FIXME: The Save Dialog uses a slightly different layout. */
1520 hdwp = BeginDeferWindowPos(7);
1522 if(hdwp && This->peb)
1523 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1525 if(hdwp && This->cctrls_hwnd)
1526 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1527 customctrls_rc.left, customctrls_rc.top,
1528 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1529 SWP_NOZORDER | SWP_NOACTIVATE);
1531 /* The default controls */
1532 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1533 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1534 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1536 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1537 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1538 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1539 SWP_NOZORDER | SWP_NOACTIVATE);
1541 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1542 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1543 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1545 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1546 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1547 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1549 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1550 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1551 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1553 if(hdwp)
1554 EndDeferWindowPos(hdwp);
1555 else
1556 ERR("Failed to position dialog controls.\n");
1558 return;
1561 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1563 IShellItem *psi_folder;
1564 IObjectWithSite *client;
1565 FOLDERSETTINGS fos;
1566 RECT rc = {0};
1567 HRESULT hr;
1569 /* Create ExplorerBrowser instance */
1570 OleInitialize(NULL);
1572 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1573 &IID_IExplorerBrowser, (void**)&This->peb);
1574 if(FAILED(hr))
1576 ERR("Failed to instantiate ExplorerBrowser control.\n");
1577 return hr;
1580 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES | EBO_NOBORDER);
1582 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1583 if(FAILED(hr))
1585 ERR("Failed to initialize the ExplorerBrowser control.\n");
1586 IExplorerBrowser_Release(This->peb);
1587 This->peb = NULL;
1588 return hr;
1590 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1591 if(FAILED(hr))
1592 ERR("Advise (ExplorerBrowser) failed.\n");
1594 /* Get previous options? */
1595 fos.ViewMode = fos.fFlags = 0;
1596 if(!(This->options & FOS_ALLOWMULTISELECT))
1597 fos.fFlags |= FWF_SINGLESEL;
1599 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1601 hr = IExplorerBrowser_QueryInterface(This->peb, &IID_IObjectWithSite, (void**)&client);
1602 if (hr == S_OK)
1604 hr = IObjectWithSite_SetSite(client, (IUnknown*)&This->IFileDialog2_iface);
1605 IObjectWithSite_Release(client);
1606 if(FAILED(hr))
1607 ERR("SetSite failed, 0x%08x\n", hr);
1610 /* Browse somewhere */
1611 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1612 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1614 return S_OK;
1617 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1619 HWND htoolbar;
1620 TBADDBITMAP tbab;
1621 TBBUTTON button[2];
1623 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1624 0, 0, 0, 0,
1625 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1627 tbab.hInst = HINST_COMMCTRL;
1628 tbab.nID = IDB_HIST_LARGE_COLOR;
1629 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1631 button[0].iBitmap = HIST_BACK;
1632 button[0].idCommand = IDC_NAVBACK;
1633 button[0].fsState = TBSTATE_ENABLED;
1634 button[0].fsStyle = BTNS_BUTTON;
1635 button[0].dwData = 0;
1636 button[0].iString = 0;
1638 button[1].iBitmap = HIST_FORWARD;
1639 button[1].idCommand = IDC_NAVFORWARD;
1640 button[1].fsState = TBSTATE_ENABLED;
1641 button[1].fsStyle = BTNS_BUTTON;
1642 button[1].dwData = 0;
1643 button[1].iString = 0;
1645 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1646 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1647 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1650 static void update_control_text(FileDialogImpl *This)
1652 HWND hitem;
1653 if(This->custom_title)
1654 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1656 if(This->custom_okbutton &&
1657 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1659 SetWindowTextW(hitem, This->custom_okbutton);
1660 ctrl_resize(hitem, 50, 250, FALSE);
1663 if(This->custom_cancelbutton &&
1664 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1666 SetWindowTextW(hitem, This->custom_cancelbutton);
1667 ctrl_resize(hitem, 50, 250, FALSE);
1670 if(This->custom_filenamelabel &&
1671 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1673 SetWindowTextW(hitem, This->custom_filenamelabel);
1674 ctrl_resize(hitem, 50, 250, FALSE);
1678 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1680 FileDialogImpl *This = (FileDialogImpl*)lParam;
1681 HWND hitem;
1683 TRACE("(%p, %p)\n", This, hwnd);
1685 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1686 This->dlg_hwnd = hwnd;
1688 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1689 if(hitem) ShowWindow(hitem, SW_HIDE);
1691 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1692 if(hitem) ShowWindow(hitem, SW_HIDE);
1694 /* Fill filetypes combobox, or hide it. */
1695 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1696 if(This->filterspec_count)
1698 HDC hdc;
1699 HFONT font;
1700 SIZE size;
1701 UINT i, maxwidth = 0;
1703 hdc = GetDC(hitem);
1704 font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
1705 SelectObject(hdc, font);
1707 for(i = 0; i < This->filterspec_count; i++)
1709 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
1711 if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
1712 maxwidth = max(maxwidth, size.cx);
1714 ReleaseDC(hitem, hdc);
1716 if(maxwidth > 0)
1718 maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
1719 SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
1721 else
1722 ERR("Failed to calculate width of filetype dropdown\n");
1724 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
1726 else
1727 ShowWindow(hitem, SW_HIDE);
1729 if(This->set_filename &&
1730 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1731 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
1733 ctrl_container_reparent(This, This->dlg_hwnd);
1734 init_explorerbrowser(This);
1735 init_toolbar(This, hwnd);
1736 update_control_text(This);
1737 update_layout(This);
1739 if(This->filterspec_count)
1740 events_OnTypeChange(This);
1742 return TRUE;
1745 static LRESULT on_wm_size(FileDialogImpl *This)
1747 update_layout(This);
1748 return FALSE;
1751 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
1753 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
1754 TRACE("%p (%p)\n", This, mmi);
1756 /* FIXME */
1757 mmi->ptMinTrackSize.x = 640;
1758 mmi->ptMinTrackSize.y = 480;
1760 return FALSE;
1763 static LRESULT on_wm_destroy(FileDialogImpl *This)
1765 TRACE("%p\n", This);
1767 if(This->peb)
1769 IExplorerBrowser_Destroy(This->peb);
1770 IExplorerBrowser_Release(This->peb);
1771 This->peb = NULL;
1774 ctrl_container_reparent(This, NULL);
1775 This->dlg_hwnd = NULL;
1777 return TRUE;
1780 static LRESULT on_idok(FileDialogImpl *This)
1782 TRACE("%p\n", This);
1784 if(SUCCEEDED(on_default_action(This)))
1785 EndDialog(This->dlg_hwnd, S_OK);
1787 return FALSE;
1790 static LRESULT on_idcancel(FileDialogImpl *This)
1792 TRACE("%p\n", This);
1794 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
1796 return FALSE;
1799 static LRESULT on_browse_back(FileDialogImpl *This)
1801 TRACE("%p\n", This);
1802 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
1803 return FALSE;
1806 static LRESULT on_browse_forward(FileDialogImpl *This)
1808 TRACE("%p\n", This);
1809 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
1810 return FALSE;
1813 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1815 if(HIWORD(wparam) == CBN_SELCHANGE)
1817 IShellView *psv;
1818 HRESULT hr;
1819 LPWSTR filename;
1820 UINT prev_index = This->filetypeindex;
1822 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
1823 TRACE("File type selection changed to %d.\n", This->filetypeindex);
1825 if(prev_index == This->filetypeindex)
1826 return FALSE;
1828 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
1829 if(SUCCEEDED(hr))
1831 IShellView_Refresh(psv);
1832 IShellView_Release(psv);
1835 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
1837 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
1839 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
1840 if(ext)
1842 lstrcpyW(buf, filename);
1844 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
1845 PathRemoveExtensionW(buf);
1847 lstrcatW(buf, ext);
1848 set_file_name(This, buf);
1850 CoTaskMemFree(filename);
1853 /* The documentation claims that OnTypeChange is called only
1854 * when the dialog is opened, but this is obviously not the
1855 * case. */
1856 events_OnTypeChange(This);
1859 return FALSE;
1862 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1864 switch(LOWORD(wparam))
1866 case IDOK: return on_idok(This);
1867 case IDCANCEL: return on_idcancel(This);
1868 case IDC_NAVBACK: return on_browse_back(This);
1869 case IDC_NAVFORWARD: return on_browse_forward(This);
1870 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
1871 default: TRACE("Unknown command.\n");
1873 return FALSE;
1876 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1878 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1880 switch(umessage)
1882 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
1883 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
1884 case WM_SIZE: return on_wm_size(This);
1885 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
1886 case WM_DESTROY: return on_wm_destroy(This);
1889 return FALSE;
1892 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
1894 INT_PTR res;
1896 SetLastError(0);
1897 res = DialogBoxParamW(COMDLG32_hInstance,
1898 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
1899 parent, itemdlg_dlgproc, (LPARAM)This);
1900 This->dlg_hwnd = NULL;
1901 if(res == -1)
1903 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
1904 return E_FAIL;
1907 TRACE("Returning 0x%08x\n", (HRESULT)res);
1908 return (HRESULT)res;
1911 /**************************************************************************
1912 * IFileDialog implementation
1914 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
1916 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
1919 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
1920 REFIID riid,
1921 void **ppvObject)
1923 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1924 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1926 *ppvObject = NULL;
1927 if(IsEqualGUID(riid, &IID_IUnknown) ||
1928 IsEqualGUID(riid, &IID_IFileDialog) ||
1929 IsEqualGUID(riid, &IID_IFileDialog2))
1931 *ppvObject = iface;
1933 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
1935 *ppvObject = &This->u.IFileOpenDialog_iface;
1937 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
1939 *ppvObject = &This->u.IFileSaveDialog_iface;
1941 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
1943 *ppvObject = &This->IExplorerBrowserEvents_iface;
1945 else if(IsEqualGUID(riid, &IID_IServiceProvider))
1947 *ppvObject = &This->IServiceProvider_iface;
1949 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
1950 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
1951 IsEqualGUID(&IID_ICommDlgBrowser, riid))
1953 *ppvObject = &This->ICommDlgBrowser3_iface;
1955 else if(IsEqualGUID(&IID_IOleWindow, riid))
1957 *ppvObject = &This->IOleWindow_iface;
1959 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
1960 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
1962 *ppvObject = &This->IFileDialogCustomize_iface;
1964 else
1965 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
1967 if(*ppvObject)
1969 IUnknown_AddRef((IUnknown*)*ppvObject);
1970 return S_OK;
1973 return E_NOINTERFACE;
1976 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
1978 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1979 LONG ref = InterlockedIncrement(&This->ref);
1980 TRACE("%p - ref %d\n", This, ref);
1982 return ref;
1985 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
1987 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1988 LONG ref = InterlockedDecrement(&This->ref);
1989 TRACE("%p - ref %d\n", This, ref);
1991 if(!ref)
1993 UINT i;
1994 for(i = 0; i < This->filterspec_count; i++)
1996 LocalFree((void*)This->filterspecs[i].pszName);
1997 LocalFree((void*)This->filterspecs[i].pszSpec);
1999 HeapFree(GetProcessHeap(), 0, This->filterspecs);
2001 DestroyWindow(This->cctrls_hwnd);
2003 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
2004 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
2005 if(This->psi_folder) IShellItem_Release(This->psi_folder);
2006 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
2007 if(This->psia_results) IShellItemArray_Release(This->psia_results);
2009 LocalFree(This->set_filename);
2010 LocalFree(This->default_ext);
2011 LocalFree(This->custom_title);
2012 LocalFree(This->custom_okbutton);
2013 LocalFree(This->custom_cancelbutton);
2014 LocalFree(This->custom_filenamelabel);
2016 HeapFree(GetProcessHeap(), 0, This);
2019 return ref;
2022 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
2024 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2025 TRACE("%p (%p)\n", iface, hwndOwner);
2027 return create_dialog(This, hwndOwner);
2030 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
2031 const COMDLG_FILTERSPEC *rgFilterSpec)
2033 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2034 UINT i;
2035 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
2037 if(This->filterspecs)
2038 return E_UNEXPECTED;
2040 if(!rgFilterSpec)
2041 return E_INVALIDARG;
2043 if(!cFileTypes)
2044 return S_OK;
2046 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
2047 for(i = 0; i < cFileTypes; i++)
2049 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
2050 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
2052 This->filterspec_count = cFileTypes;
2054 return S_OK;
2057 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
2059 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2060 TRACE("%p (%d)\n", This, iFileType);
2062 if(!This->filterspecs)
2063 return E_FAIL;
2065 iFileType = max(iFileType, 1);
2066 iFileType = min(iFileType, This->filterspec_count);
2067 This->filetypeindex = iFileType-1;
2069 return S_OK;
2072 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
2074 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2075 TRACE("%p (%p)\n", This, piFileType);
2077 if(!piFileType)
2078 return E_INVALIDARG;
2080 if(This->filterspec_count == 0)
2081 *piFileType = 0;
2082 else
2083 *piFileType = This->filetypeindex + 1;
2085 return S_OK;
2088 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
2090 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2091 events_client *client;
2092 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
2094 if(!pfde || !pdwCookie)
2095 return E_INVALIDARG;
2097 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
2098 client->pfde = pfde;
2099 client->cookie = ++This->events_next_cookie;
2101 IFileDialogEvents_AddRef(pfde);
2102 *pdwCookie = client->cookie;
2104 list_add_tail(&This->events_clients, &client->entry);
2106 return S_OK;
2109 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
2111 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2112 events_client *client, *found = NULL;
2113 TRACE("%p (%d)\n", This, dwCookie);
2115 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
2117 if(client->cookie == dwCookie)
2119 found = client;
2120 break;
2124 if(found)
2126 list_remove(&found->entry);
2127 IFileDialogEvents_Release(found->pfde);
2128 HeapFree(GetProcessHeap(), 0, found);
2129 return S_OK;
2132 return E_INVALIDARG;
2135 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
2137 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2138 TRACE("%p (0x%x)\n", This, fos);
2140 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
2142 WCHAR buf[30];
2143 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, sizeof(buf)/sizeof(WCHAR));
2144 IFileDialog2_SetTitle(iface, buf);
2147 This->options = fos;
2149 return S_OK;
2152 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
2154 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2155 TRACE("%p (%p)\n", This, pfos);
2157 if(!pfos)
2158 return E_INVALIDARG;
2160 *pfos = This->options;
2162 return S_OK;
2165 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
2167 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2168 TRACE("%p (%p)\n", This, psi);
2169 if(This->psi_defaultfolder)
2170 IShellItem_Release(This->psi_defaultfolder);
2172 This->psi_defaultfolder = psi;
2174 if(This->psi_defaultfolder)
2175 IShellItem_AddRef(This->psi_defaultfolder);
2177 return S_OK;
2180 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
2182 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2183 TRACE("%p (%p)\n", This, psi);
2184 if(This->psi_setfolder)
2185 IShellItem_Release(This->psi_setfolder);
2187 This->psi_setfolder = psi;
2189 if(This->psi_setfolder)
2190 IShellItem_AddRef(This->psi_setfolder);
2192 return S_OK;
2195 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
2197 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2198 TRACE("%p (%p)\n", This, ppsi);
2199 if(!ppsi)
2200 return E_INVALIDARG;
2202 /* FIXME:
2203 If the dialog is shown, return the current(ly selected) folder. */
2205 *ppsi = NULL;
2206 if(This->psi_folder)
2207 *ppsi = This->psi_folder;
2208 else if(This->psi_setfolder)
2209 *ppsi = This->psi_setfolder;
2210 else if(This->psi_defaultfolder)
2211 *ppsi = This->psi_defaultfolder;
2213 if(*ppsi)
2215 IShellItem_AddRef(*ppsi);
2216 return S_OK;
2219 return E_FAIL;
2222 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
2224 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2225 HRESULT hr;
2226 TRACE("%p (%p)\n", This, ppsi);
2228 if(!ppsi)
2229 return E_INVALIDARG;
2231 if(This->psia_selection)
2233 /* FIXME: Check filename edit box */
2234 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2235 return hr;
2238 return E_FAIL;
2241 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
2243 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2244 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2246 set_file_name(This, pszName);
2248 return S_OK;
2251 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
2253 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2254 TRACE("%p (%p)\n", iface, pszName);
2256 if(!pszName)
2257 return E_INVALIDARG;
2259 *pszName = NULL;
2260 if(get_file_name(This, pszName))
2261 return S_OK;
2262 else
2263 return E_FAIL;
2266 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
2268 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2269 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2271 LocalFree(This->custom_title);
2272 This->custom_title = StrDupW(pszTitle);
2273 update_control_text(This);
2275 return S_OK;
2278 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
2280 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2281 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2283 LocalFree(This->custom_okbutton);
2284 This->custom_okbutton = StrDupW(pszText);
2285 update_control_text(This);
2286 update_layout(This);
2288 return S_OK;
2291 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2293 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2294 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2296 LocalFree(This->custom_filenamelabel);
2297 This->custom_filenamelabel = StrDupW(pszLabel);
2298 update_control_text(This);
2299 update_layout(This);
2301 return S_OK;
2304 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
2306 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2307 HRESULT hr;
2308 TRACE("%p (%p)\n", This, ppsi);
2310 if(!ppsi)
2311 return E_INVALIDARG;
2313 if(This->psia_results)
2315 UINT item_count;
2316 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2317 if(SUCCEEDED(hr))
2319 if(item_count != 1)
2320 return E_FAIL;
2322 /* Adds a reference. */
2323 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2326 return hr;
2329 return E_UNEXPECTED;
2332 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2334 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2335 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2336 return E_NOTIMPL;
2339 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2341 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2342 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2344 LocalFree(This->default_ext);
2345 This->default_ext = StrDupW(pszDefaultExtension);
2347 return S_OK;
2350 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2352 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2353 TRACE("%p (0x%08x)\n", This, hr);
2355 if(This->dlg_hwnd)
2356 EndDialog(This->dlg_hwnd, hr);
2358 return S_OK;
2361 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2363 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2364 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2365 This->client_guid = *guid;
2366 return S_OK;
2369 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2371 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2372 FIXME("stub - %p\n", This);
2373 return E_NOTIMPL;
2376 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2378 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2379 FIXME("stub - %p (%p)\n", This, pFilter);
2380 return E_NOTIMPL;
2383 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2385 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2386 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2388 LocalFree(This->custom_cancelbutton);
2389 This->custom_cancelbutton = StrDupW(pszLabel);
2390 update_control_text(This);
2391 update_layout(This);
2393 return S_OK;
2396 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2398 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2399 FIXME("stub - %p (%p)\n", This, psi);
2400 return E_NOTIMPL;
2403 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2404 IFileDialog2_fnQueryInterface,
2405 IFileDialog2_fnAddRef,
2406 IFileDialog2_fnRelease,
2407 IFileDialog2_fnShow,
2408 IFileDialog2_fnSetFileTypes,
2409 IFileDialog2_fnSetFileTypeIndex,
2410 IFileDialog2_fnGetFileTypeIndex,
2411 IFileDialog2_fnAdvise,
2412 IFileDialog2_fnUnadvise,
2413 IFileDialog2_fnSetOptions,
2414 IFileDialog2_fnGetOptions,
2415 IFileDialog2_fnSetDefaultFolder,
2416 IFileDialog2_fnSetFolder,
2417 IFileDialog2_fnGetFolder,
2418 IFileDialog2_fnGetCurrentSelection,
2419 IFileDialog2_fnSetFileName,
2420 IFileDialog2_fnGetFileName,
2421 IFileDialog2_fnSetTitle,
2422 IFileDialog2_fnSetOkButtonLabel,
2423 IFileDialog2_fnSetFileNameLabel,
2424 IFileDialog2_fnGetResult,
2425 IFileDialog2_fnAddPlace,
2426 IFileDialog2_fnSetDefaultExtension,
2427 IFileDialog2_fnClose,
2428 IFileDialog2_fnSetClientGuid,
2429 IFileDialog2_fnClearClientData,
2430 IFileDialog2_fnSetFilter,
2431 IFileDialog2_fnSetCancelButtonLabel,
2432 IFileDialog2_fnSetNavigationRoot
2435 /**************************************************************************
2436 * IFileOpenDialog
2438 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2440 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2443 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2444 REFIID riid, void **ppvObject)
2446 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2447 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2450 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2452 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2453 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2456 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2458 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2459 return IFileDialog2_Release(&This->IFileDialog2_iface);
2462 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2464 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2465 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2468 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2469 const COMDLG_FILTERSPEC *rgFilterSpec)
2471 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2472 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2475 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2477 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2478 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2481 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2483 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2484 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2487 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2488 DWORD *pdwCookie)
2490 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2491 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2494 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2496 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2497 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2500 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2502 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2503 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2506 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2508 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2509 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2512 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2514 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2515 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2518 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2520 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2521 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2524 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2526 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2527 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2530 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2532 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2533 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2536 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2538 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2539 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2542 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2544 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2545 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2548 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2550 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2551 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2554 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2556 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2557 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2560 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2562 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2563 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2566 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2568 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2569 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2572 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2574 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2575 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2578 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2579 LPCWSTR pszDefaultExtension)
2581 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2582 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2585 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2587 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2588 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2591 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2593 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2594 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2597 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2599 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2600 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2603 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2605 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2606 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2609 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2611 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2612 TRACE("%p (%p)\n", This, ppenum);
2614 *ppenum = This->psia_results;
2616 if(*ppenum)
2618 IShellItemArray_AddRef(*ppenum);
2619 return S_OK;
2622 return E_FAIL;
2625 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2627 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2628 TRACE("%p (%p)\n", This, ppsai);
2630 if(This->psia_selection)
2632 *ppsai = This->psia_selection;
2633 IShellItemArray_AddRef(*ppsai);
2634 return S_OK;
2637 return E_FAIL;
2640 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2641 IFileOpenDialog_fnQueryInterface,
2642 IFileOpenDialog_fnAddRef,
2643 IFileOpenDialog_fnRelease,
2644 IFileOpenDialog_fnShow,
2645 IFileOpenDialog_fnSetFileTypes,
2646 IFileOpenDialog_fnSetFileTypeIndex,
2647 IFileOpenDialog_fnGetFileTypeIndex,
2648 IFileOpenDialog_fnAdvise,
2649 IFileOpenDialog_fnUnadvise,
2650 IFileOpenDialog_fnSetOptions,
2651 IFileOpenDialog_fnGetOptions,
2652 IFileOpenDialog_fnSetDefaultFolder,
2653 IFileOpenDialog_fnSetFolder,
2654 IFileOpenDialog_fnGetFolder,
2655 IFileOpenDialog_fnGetCurrentSelection,
2656 IFileOpenDialog_fnSetFileName,
2657 IFileOpenDialog_fnGetFileName,
2658 IFileOpenDialog_fnSetTitle,
2659 IFileOpenDialog_fnSetOkButtonLabel,
2660 IFileOpenDialog_fnSetFileNameLabel,
2661 IFileOpenDialog_fnGetResult,
2662 IFileOpenDialog_fnAddPlace,
2663 IFileOpenDialog_fnSetDefaultExtension,
2664 IFileOpenDialog_fnClose,
2665 IFileOpenDialog_fnSetClientGuid,
2666 IFileOpenDialog_fnClearClientData,
2667 IFileOpenDialog_fnSetFilter,
2668 IFileOpenDialog_fnGetResults,
2669 IFileOpenDialog_fnGetSelectedItems
2672 /**************************************************************************
2673 * IFileSaveDialog
2675 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
2677 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
2680 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
2681 REFIID riid,
2682 void **ppvObject)
2684 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2685 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2688 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
2690 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2691 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2694 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
2696 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2697 return IFileDialog2_Release(&This->IFileDialog2_iface);
2700 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
2702 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2703 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2706 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
2707 const COMDLG_FILTERSPEC *rgFilterSpec)
2709 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2710 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2713 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
2715 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2716 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2719 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
2721 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2722 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2725 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
2726 DWORD *pdwCookie)
2728 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2729 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2732 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
2734 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2735 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2738 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
2740 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2741 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2744 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2746 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2747 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2750 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
2752 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2753 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2756 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
2758 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2759 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2762 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
2764 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2765 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2768 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
2770 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2771 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2774 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
2776 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2777 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2780 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
2782 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2783 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2786 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
2788 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2789 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2792 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
2794 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2795 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2798 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
2800 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2801 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2804 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
2806 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2807 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2810 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
2812 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2813 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2816 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
2817 LPCWSTR pszDefaultExtension)
2819 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2820 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2823 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
2825 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2826 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2829 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
2831 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2832 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2835 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
2837 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2838 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2841 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
2843 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2844 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2847 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
2849 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2850 FIXME("stub - %p (%p)\n", This, psi);
2851 return E_NOTIMPL;
2854 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
2856 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2857 FIXME("stub - %p (%p)\n", This, pStore);
2858 return E_NOTIMPL;
2861 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
2862 IPropertyDescriptionList *pList,
2863 BOOL fAppendDefault)
2865 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2866 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
2867 return E_NOTIMPL;
2870 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
2872 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2873 FIXME("stub - %p (%p)\n", This, ppStore);
2874 return E_NOTIMPL;
2877 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
2878 IShellItem *psi,
2879 IPropertyStore *pStore,
2880 HWND hwnd,
2881 IFileOperationProgressSink *pSink)
2883 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2884 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
2885 return E_NOTIMPL;
2888 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
2889 IFileSaveDialog_fnQueryInterface,
2890 IFileSaveDialog_fnAddRef,
2891 IFileSaveDialog_fnRelease,
2892 IFileSaveDialog_fnShow,
2893 IFileSaveDialog_fnSetFileTypes,
2894 IFileSaveDialog_fnSetFileTypeIndex,
2895 IFileSaveDialog_fnGetFileTypeIndex,
2896 IFileSaveDialog_fnAdvise,
2897 IFileSaveDialog_fnUnadvise,
2898 IFileSaveDialog_fnSetOptions,
2899 IFileSaveDialog_fnGetOptions,
2900 IFileSaveDialog_fnSetDefaultFolder,
2901 IFileSaveDialog_fnSetFolder,
2902 IFileSaveDialog_fnGetFolder,
2903 IFileSaveDialog_fnGetCurrentSelection,
2904 IFileSaveDialog_fnSetFileName,
2905 IFileSaveDialog_fnGetFileName,
2906 IFileSaveDialog_fnSetTitle,
2907 IFileSaveDialog_fnSetOkButtonLabel,
2908 IFileSaveDialog_fnSetFileNameLabel,
2909 IFileSaveDialog_fnGetResult,
2910 IFileSaveDialog_fnAddPlace,
2911 IFileSaveDialog_fnSetDefaultExtension,
2912 IFileSaveDialog_fnClose,
2913 IFileSaveDialog_fnSetClientGuid,
2914 IFileSaveDialog_fnClearClientData,
2915 IFileSaveDialog_fnSetFilter,
2916 IFileSaveDialog_fnSetSaveAsItem,
2917 IFileSaveDialog_fnSetProperties,
2918 IFileSaveDialog_fnSetCollectedProperties,
2919 IFileSaveDialog_fnGetProperties,
2920 IFileSaveDialog_fnApplyProperties
2923 /**************************************************************************
2924 * IExplorerBrowserEvents implementation
2926 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
2928 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
2931 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
2932 REFIID riid, void **ppvObject)
2934 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2935 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2937 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2940 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
2942 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2943 TRACE("%p\n", This);
2944 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2947 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
2949 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2950 TRACE("%p\n", This);
2951 return IFileDialog2_Release(&This->IFileDialog2_iface);
2954 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
2955 PCIDLIST_ABSOLUTE pidlFolder)
2957 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2958 IShellItem *psi;
2959 HRESULT hr;
2960 TRACE("%p (%p)\n", This, pidlFolder);
2962 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
2963 if(SUCCEEDED(hr))
2965 hr = events_OnFolderChanging(This, psi);
2966 IShellItem_Release(psi);
2968 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
2969 if(hr == S_FALSE)
2970 hr = E_FAIL;
2972 return hr;
2974 else
2975 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
2977 return S_OK;
2980 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
2981 IShellView *psv)
2983 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2984 TRACE("%p (%p)\n", This, psv);
2985 return S_OK;
2988 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
2989 PCIDLIST_ABSOLUTE pidlFolder)
2991 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2992 HRESULT hr;
2993 TRACE("%p (%p)\n", This, pidlFolder);
2995 if(This->psi_folder)
2996 IShellItem_Release(This->psi_folder);
2998 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
2999 if(FAILED(hr))
3001 ERR("Failed to get the current folder.\n");
3002 This->psi_folder = NULL;
3005 events_OnFolderChange(This);
3007 return S_OK;
3010 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
3011 PCIDLIST_ABSOLUTE pidlFolder)
3013 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3014 TRACE("%p (%p)\n", This, pidlFolder);
3015 return S_OK;
3018 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
3019 IExplorerBrowserEvents_fnQueryInterface,
3020 IExplorerBrowserEvents_fnAddRef,
3021 IExplorerBrowserEvents_fnRelease,
3022 IExplorerBrowserEvents_fnOnNavigationPending,
3023 IExplorerBrowserEvents_fnOnViewCreated,
3024 IExplorerBrowserEvents_fnOnNavigationComplete,
3025 IExplorerBrowserEvents_fnOnNavigationFailed
3028 /**************************************************************************
3029 * IServiceProvider implementation
3031 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
3033 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
3036 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
3037 REFIID riid, void **ppvObject)
3039 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3040 TRACE("%p\n", This);
3041 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3044 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
3046 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3047 TRACE("%p\n", This);
3048 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3051 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
3053 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3054 TRACE("%p\n", This);
3055 return IFileDialog2_Release(&This->IFileDialog2_iface);
3058 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
3059 REFGUID guidService,
3060 REFIID riid, void **ppv)
3062 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3063 HRESULT hr = E_NOTIMPL;
3064 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
3066 *ppv = NULL;
3067 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
3068 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
3069 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
3070 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
3071 else
3072 FIXME("Interface %s requested from unknown service %s\n",
3073 debugstr_guid(riid), debugstr_guid(guidService));
3075 return hr;
3078 static const IServiceProviderVtbl vt_IServiceProvider = {
3079 IServiceProvider_fnQueryInterface,
3080 IServiceProvider_fnAddRef,
3081 IServiceProvider_fnRelease,
3082 IServiceProvider_fnQueryService
3085 /**************************************************************************
3086 * ICommDlgBrowser3 implementation
3088 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
3090 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
3093 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
3094 REFIID riid, void **ppvObject)
3096 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3097 TRACE("%p\n", This);
3098 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3101 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
3103 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3104 TRACE("%p\n", This);
3105 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3108 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
3110 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3111 TRACE("%p\n", This);
3112 return IFileDialog2_Release(&This->IFileDialog2_iface);
3115 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
3116 IShellView *shv)
3118 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3119 HRESULT hr;
3120 TRACE("%p (%p)\n", This, shv);
3122 hr = on_default_action(This);
3124 if(SUCCEEDED(hr))
3125 EndDialog(This->dlg_hwnd, S_OK);
3127 return S_OK;
3130 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
3131 IShellView *shv, ULONG uChange )
3133 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3134 IDataObject *new_selection;
3135 HRESULT hr;
3136 TRACE("%p (%p, %x)\n", This, shv, uChange);
3138 switch(uChange)
3140 case CDBOSC_SELCHANGE:
3141 if(This->psia_selection)
3143 IShellItemArray_Release(This->psia_selection);
3144 This->psia_selection = NULL;
3147 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
3148 if(SUCCEEDED(hr))
3150 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
3151 (void**)&This->psia_selection);
3152 if(SUCCEEDED(hr))
3154 fill_filename_from_selection(This);
3155 events_OnSelectionChange(This);
3158 IDataObject_Release(new_selection);
3160 break;
3161 default:
3162 TRACE("Unhandled state change\n");
3164 return S_OK;
3167 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
3168 IShellView *shv, LPCITEMIDLIST pidl)
3170 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3171 IShellItem *psi;
3172 LPWSTR filename;
3173 LPITEMIDLIST parent_pidl;
3174 HRESULT hr;
3175 ULONG attr;
3176 TRACE("%p (%p, %p)\n", This, shv, pidl);
3178 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
3179 return S_OK;
3181 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3182 if(SUCCEEDED(hr))
3184 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3185 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3186 ILFree(parent_pidl);
3187 ILFree(full_pidl);
3189 if(FAILED(hr))
3191 ERR("Failed to get shellitem (%08x).\n", hr);
3192 return S_OK;
3195 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3196 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3198 IShellItem_Release(psi);
3199 return S_OK;
3202 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
3204 IShellItem_Release(psi);
3205 return S_FALSE;
3208 hr = S_OK;
3209 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
3211 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
3212 hr = S_FALSE;
3213 CoTaskMemFree(filename);
3216 IShellItem_Release(psi);
3217 return hr;
3220 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
3221 IShellView *ppshv, DWORD dwNotifyType)
3223 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3224 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
3225 return E_NOTIMPL;
3228 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
3229 IShellView *pshv,
3230 LPWSTR pszText, int cchMax)
3232 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3233 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
3234 return E_NOTIMPL;
3237 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
3239 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3240 FIXME("Stub: %p (%p)\n", This, pdwFlags);
3241 return E_NOTIMPL;
3244 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
3245 IShellView *pshv, int iColumn)
3247 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3248 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
3249 return E_NOTIMPL;
3252 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
3253 LPWSTR pszFileSpec, int cchFileSpec)
3255 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3256 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
3257 return E_NOTIMPL;
3260 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
3261 IShellView *pshv)
3263 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3264 FIXME("Stub: %p (%p)\n", This, pshv);
3265 return E_NOTIMPL;
3268 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
3269 ICommDlgBrowser3_fnQueryInterface,
3270 ICommDlgBrowser3_fnAddRef,
3271 ICommDlgBrowser3_fnRelease,
3272 ICommDlgBrowser3_fnOnDefaultCommand,
3273 ICommDlgBrowser3_fnOnStateChange,
3274 ICommDlgBrowser3_fnIncludeObject,
3275 ICommDlgBrowser3_fnNotify,
3276 ICommDlgBrowser3_fnGetDefaultMenuText,
3277 ICommDlgBrowser3_fnGetViewFlags,
3278 ICommDlgBrowser3_fnOnColumnClicked,
3279 ICommDlgBrowser3_fnGetCurrentFilter,
3280 ICommDlgBrowser3_fnOnPreviewCreated
3283 /**************************************************************************
3284 * IOleWindow implementation
3286 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
3288 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
3291 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
3293 FileDialogImpl *This = impl_from_IOleWindow(iface);
3294 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3297 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
3299 FileDialogImpl *This = impl_from_IOleWindow(iface);
3300 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3303 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
3305 FileDialogImpl *This = impl_from_IOleWindow(iface);
3306 return IFileDialog2_Release(&This->IFileDialog2_iface);
3309 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
3311 FileDialogImpl *This = impl_from_IOleWindow(iface);
3312 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
3313 return E_NOTIMPL;
3316 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
3318 FileDialogImpl *This = impl_from_IOleWindow(iface);
3319 TRACE("%p (%p)\n", This, phwnd);
3320 *phwnd = This->dlg_hwnd;
3321 return S_OK;
3324 static const IOleWindowVtbl vt_IOleWindow = {
3325 IOleWindow_fnQueryInterface,
3326 IOleWindow_fnAddRef,
3327 IOleWindow_fnRelease,
3328 IOleWindow_fnGetWindow,
3329 IOleWindow_fnContextSensitiveHelp
3332 /**************************************************************************
3333 * IFileDialogCustomize implementation
3335 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3337 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3340 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3341 REFIID riid, void **ppvObject)
3343 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3344 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3347 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3349 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3350 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3353 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3355 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3356 return IFileDialog2_Release(&This->IFileDialog2_iface);
3359 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3360 DWORD dwIDCtl)
3362 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3363 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3364 return E_NOTIMPL;
3367 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3368 DWORD dwIDCtl,
3369 LPCWSTR pszLabel)
3371 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3372 customctrl *ctrl;
3373 TBBUTTON tbb;
3374 HRESULT hr;
3375 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3377 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3378 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3379 This->cctrl_def_height, &ctrl);
3380 if(SUCCEEDED(hr))
3382 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3383 ctrl->type = IDLG_CCTRL_MENU;
3385 /* Add the actual button with a popup menu. */
3386 tbb.iBitmap = I_IMAGENONE;
3387 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3388 tbb.iString = (DWORD_PTR)pszLabel;
3389 tbb.fsState = TBSTATE_ENABLED;
3390 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3391 tbb.idCommand = 1;
3393 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3396 return hr;
3399 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3400 DWORD dwIDCtl,
3401 LPCWSTR pszLabel)
3403 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3404 customctrl *ctrl;
3405 HRESULT hr;
3406 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3408 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3409 This->cctrl_def_height, &ctrl);
3410 if(SUCCEEDED(hr))
3411 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3413 return hr;
3416 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3417 DWORD dwIDCtl)
3419 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3420 customctrl *ctrl;
3421 HRESULT hr;
3422 TRACE("%p (%d)\n", This, dwIDCtl);
3424 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3425 This->cctrl_def_height, &ctrl);
3426 if(SUCCEEDED(hr))
3427 ctrl->type = IDLG_CCTRL_COMBOBOX;
3429 return hr;
3432 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3433 DWORD dwIDCtl)
3435 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3436 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3437 return E_NOTIMPL;
3440 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3441 DWORD dwIDCtl,
3442 LPCWSTR pszLabel,
3443 BOOL bChecked)
3445 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3446 customctrl *ctrl;
3447 HRESULT hr;
3448 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3450 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0,
3451 This->cctrl_def_height, &ctrl);
3452 if(SUCCEEDED(hr))
3454 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3455 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3458 return hr;
3461 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3462 DWORD dwIDCtl,
3463 LPCWSTR pszText)
3465 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3466 customctrl *ctrl;
3467 HRESULT hr;
3468 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3470 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3471 This->cctrl_def_height, &ctrl);
3472 if(SUCCEEDED(hr))
3473 ctrl->type = IDLG_CCTRL_EDITBOX;
3475 return hr;
3478 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3479 DWORD dwIDCtl)
3481 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3482 customctrl *ctrl;
3483 HRESULT hr;
3484 TRACE("%p (%d)\n", This, dwIDCtl);
3486 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3487 GetSystemMetrics(SM_CYEDGE), &ctrl);
3488 if(SUCCEEDED(hr))
3489 ctrl->type = IDLG_CCTRL_SEPARATOR;
3491 return hr;
3494 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3495 DWORD dwIDCtl,
3496 LPCWSTR pszText)
3498 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3499 customctrl *ctrl;
3500 HRESULT hr;
3501 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3503 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3504 This->cctrl_def_height, &ctrl);
3505 if(SUCCEEDED(hr))
3506 ctrl->type = IDLG_CCTRL_TEXT;
3508 return hr;
3511 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3512 DWORD dwIDCtl,
3513 LPCWSTR pszLabel)
3515 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3516 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3517 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3519 if(!ctrl) return E_INVALIDARG;
3521 switch(ctrl->type)
3523 case IDLG_CCTRL_MENU:
3524 case IDLG_CCTRL_PUSHBUTTON:
3525 case IDLG_CCTRL_CHECKBUTTON:
3526 case IDLG_CCTRL_TEXT:
3527 case IDLG_CCTRL_VISUALGROUP:
3528 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3529 break;
3530 default:
3531 break;
3534 return S_OK;
3537 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3538 DWORD dwIDCtl,
3539 CDCONTROLSTATEF *pdwState)
3541 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3542 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3543 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3545 if(!ctrl) return E_NOTIMPL;
3547 *pdwState = ctrl->cdcstate;
3548 return S_OK;
3551 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3552 DWORD dwIDCtl,
3553 CDCONTROLSTATEF dwState)
3555 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3556 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3557 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3559 if(ctrl)
3561 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3563 if(dwState & CDCS_ENABLED)
3564 wndstyle &= ~(WS_DISABLED);
3565 else
3566 wndstyle |= WS_DISABLED;
3568 if(dwState & CDCS_VISIBLE)
3569 wndstyle |= WS_VISIBLE;
3570 else
3571 wndstyle &= ~(WS_VISIBLE);
3573 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3575 /* We save the state separately since at least one application
3576 * relies on being able to hide a control. */
3577 ctrl->cdcstate = dwState;
3580 return S_OK;
3583 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3584 DWORD dwIDCtl,
3585 WCHAR **ppszText)
3587 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3588 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3589 WCHAR len, *text;
3590 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
3592 if(!ctrl || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3593 return E_FAIL;
3595 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3596 if(!text) return E_FAIL;
3598 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3599 *ppszText = text;
3600 return S_OK;
3603 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
3604 DWORD dwIDCtl,
3605 LPCWSTR pszText)
3607 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3608 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3609 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
3611 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
3612 return E_FAIL;
3614 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
3615 return S_OK;
3618 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
3619 DWORD dwIDCtl,
3620 BOOL *pbChecked)
3622 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3623 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3624 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
3626 if(ctrl)
3627 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
3629 return S_OK;
3632 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
3633 DWORD dwIDCtl,
3634 BOOL bChecked)
3636 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3637 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3638 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
3640 if(ctrl)
3641 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
3643 return S_OK;
3646 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
3648 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
3649 UINT i;
3650 if(!count || (count == CB_ERR))
3651 return -1;
3653 for(i = 0; i < count; i++)
3654 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3655 return i;
3657 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
3658 return -1;
3661 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
3662 DWORD dwIDCtl,
3663 DWORD dwIDItem,
3664 LPCWSTR pszLabel)
3666 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3667 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3668 HRESULT hr;
3669 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3671 if(!ctrl) return E_FAIL;
3673 switch(ctrl->type)
3675 case IDLG_CCTRL_COMBOBOX:
3677 UINT index;
3679 if(get_combobox_index_from_id(ctrl->hwnd, dwIDItem) != -1)
3680 return E_INVALIDARG;
3682 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
3683 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
3685 return S_OK;
3687 case IDLG_CCTRL_MENU:
3689 TBBUTTON tbb;
3690 cctrl_item* item;
3692 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
3694 if (FAILED(hr)) return hr;
3696 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3698 AppendMenuW((HMENU)tbb.dwData, MF_STRING, dwIDItem, pszLabel);
3699 return S_OK;
3701 default:
3702 break;
3705 return E_NOINTERFACE; /* win7 */
3708 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
3709 DWORD dwIDCtl,
3710 DWORD dwIDItem)
3712 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3713 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3714 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3716 if(!ctrl) return E_FAIL;
3718 switch(ctrl->type)
3720 case IDLG_CCTRL_COMBOBOX:
3722 UINT i, count = SendMessageW(ctrl->hwnd, CB_GETCOUNT, 0, 0);
3723 if(!count || (count == CB_ERR))
3724 return E_FAIL;
3726 for(i = 0; i < count; i++)
3727 if(SendMessageW(ctrl->hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3729 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, i, 0) == CB_ERR)
3730 return E_FAIL;
3731 return S_OK;
3734 return E_UNEXPECTED;
3736 case IDLG_CCTRL_MENU:
3738 TBBUTTON tbb;
3739 HMENU hmenu;
3740 cctrl_item* item;
3742 item = get_item(ctrl, dwIDItem, 0, NULL);
3744 if (!item)
3745 return E_UNEXPECTED;
3747 if (item->cdcstate & CDCS_VISIBLE)
3749 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3750 hmenu = (HMENU)tbb.dwData;
3752 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
3753 return E_UNEXPECTED;
3756 list_remove(&item->entry);
3757 item_free(item);
3759 return S_OK;
3761 default:
3762 break;
3765 return E_FAIL;
3768 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
3769 DWORD dwIDCtl)
3771 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3772 TRACE("%p (%d)\n", This, dwIDCtl);
3774 /* Not implemented by native */
3775 return E_NOTIMPL;
3778 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
3779 DWORD dwIDCtl,
3780 DWORD dwIDItem,
3781 CDCONTROLSTATEF *pdwState)
3783 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3784 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3785 TRACE("%p (%d, %d, %p)\n", This, dwIDCtl, dwIDItem, pdwState);
3787 if(!ctrl) return E_FAIL;
3789 switch(ctrl->type)
3791 case IDLG_CCTRL_MENU:
3793 cctrl_item* item;
3795 item = get_item(ctrl, dwIDItem, 0, NULL);
3797 if (!item)
3798 return E_UNEXPECTED;
3800 *pdwState = item->cdcstate;
3802 return S_OK;
3804 default:
3805 break;
3808 return E_FAIL;
3811 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
3812 DWORD dwIDCtl,
3813 DWORD dwIDItem,
3814 CDCONTROLSTATEF dwState)
3816 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3817 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3818 TRACE("%p (%d, %d, %x)\n", This, dwIDCtl, dwIDItem, dwState);
3820 if(!ctrl) return E_FAIL;
3822 switch(ctrl->type)
3824 case IDLG_CCTRL_MENU:
3826 TBBUTTON tbb;
3827 HMENU hmenu;
3828 cctrl_item* item;
3829 CDCONTROLSTATEF prev_state;
3830 DWORD position;
3832 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, &position);
3834 if (!item)
3835 return E_UNEXPECTED;
3837 prev_state = item->cdcstate;
3839 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3840 hmenu = (HMENU)tbb.dwData;
3842 if (dwState & CDCS_VISIBLE)
3844 if (prev_state & CDCS_VISIBLE)
3846 /* change state */
3847 EnableMenuItem(hmenu, dwIDItem,
3848 MF_BYCOMMAND|((dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED));
3850 else
3852 /* show item */
3853 MENUITEMINFOW mii;
3855 mii.cbSize = sizeof(mii);
3856 mii.fMask = MIIM_ID|MIIM_STATE|MIIM_STRING;
3857 mii.fState = (dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED;
3858 mii.wID = dwIDItem;
3859 mii.dwTypeData = item->label;
3861 InsertMenuItemW(hmenu, position, TRUE, &mii);
3864 else if (prev_state & CDCS_VISIBLE)
3866 /* hide item */
3867 DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND);
3870 item->cdcstate = dwState;
3872 return S_OK;
3874 default:
3875 break;
3878 return E_FAIL;
3881 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
3882 DWORD dwIDCtl,
3883 DWORD *pdwIDItem)
3885 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3886 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3887 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
3889 if(!ctrl) return E_FAIL;
3891 switch(ctrl->type)
3893 case IDLG_CCTRL_COMBOBOX:
3895 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
3896 if(index == CB_ERR)
3897 return E_FAIL;
3899 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
3900 return S_OK;
3902 default:
3903 FIXME("Unsupported control type %d\n", ctrl->type);
3906 return E_NOTIMPL;
3909 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
3910 DWORD dwIDCtl,
3911 DWORD dwIDItem)
3913 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3914 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3915 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3917 if(!ctrl) return E_INVALIDARG;
3919 switch(ctrl->type)
3921 case IDLG_CCTRL_COMBOBOX:
3923 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
3925 if(index == -1)
3926 return E_INVALIDARG;
3928 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
3929 return E_FAIL;
3931 return S_OK;
3933 default:
3934 FIXME("Unsupported control type %d\n", ctrl->type);
3937 return E_INVALIDARG;
3940 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
3941 DWORD dwIDCtl,
3942 LPCWSTR pszLabel)
3944 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3945 customctrl *vg;
3946 HRESULT hr;
3947 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
3949 if(This->cctrl_active_vg)
3950 return E_UNEXPECTED;
3952 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0,
3953 This->cctrl_def_height, &vg);
3954 if(SUCCEEDED(hr))
3956 vg->type = IDLG_CCTRL_VISUALGROUP;
3957 This->cctrl_active_vg = vg;
3960 return hr;
3963 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
3965 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3966 TRACE("%p\n", This);
3968 This->cctrl_active_vg = NULL;
3970 return S_OK;
3973 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
3974 DWORD dwIDCtl)
3976 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3977 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3978 return E_NOTIMPL;
3981 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
3982 DWORD dwIDCtl,
3983 DWORD dwIDItem,
3984 LPCWSTR pszLabel)
3986 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3987 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3988 return E_NOTIMPL;
3991 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
3992 IFileDialogCustomize_fnQueryInterface,
3993 IFileDialogCustomize_fnAddRef,
3994 IFileDialogCustomize_fnRelease,
3995 IFileDialogCustomize_fnEnableOpenDropDown,
3996 IFileDialogCustomize_fnAddMenu,
3997 IFileDialogCustomize_fnAddPushButton,
3998 IFileDialogCustomize_fnAddComboBox,
3999 IFileDialogCustomize_fnAddRadioButtonList,
4000 IFileDialogCustomize_fnAddCheckButton,
4001 IFileDialogCustomize_fnAddEditBox,
4002 IFileDialogCustomize_fnAddSeparator,
4003 IFileDialogCustomize_fnAddText,
4004 IFileDialogCustomize_fnSetControlLabel,
4005 IFileDialogCustomize_fnGetControlState,
4006 IFileDialogCustomize_fnSetControlState,
4007 IFileDialogCustomize_fnGetEditBoxText,
4008 IFileDialogCustomize_fnSetEditBoxText,
4009 IFileDialogCustomize_fnGetCheckButtonState,
4010 IFileDialogCustomize_fnSetCheckButtonState,
4011 IFileDialogCustomize_fnAddControlItem,
4012 IFileDialogCustomize_fnRemoveControlItem,
4013 IFileDialogCustomize_fnRemoveAllControlItems,
4014 IFileDialogCustomize_fnGetControlItemState,
4015 IFileDialogCustomize_fnSetControlItemState,
4016 IFileDialogCustomize_fnGetSelectedControlItem,
4017 IFileDialogCustomize_fnSetSelectedControlItem,
4018 IFileDialogCustomize_fnStartVisualGroup,
4019 IFileDialogCustomize_fnEndVisualGroup,
4020 IFileDialogCustomize_fnMakeProminent,
4021 IFileDialogCustomize_fnSetControlItemText
4024 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
4026 FileDialogImpl *fdimpl;
4027 HRESULT hr;
4028 IShellFolder *psf;
4029 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
4031 if(!ppv)
4032 return E_POINTER;
4033 if(pUnkOuter)
4034 return CLASS_E_NOAGGREGATION;
4036 fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
4037 if(!fdimpl)
4038 return E_OUTOFMEMORY;
4040 fdimpl->ref = 1;
4041 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
4042 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
4043 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
4044 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
4045 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
4046 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
4048 if(type == ITEMDLG_TYPE_OPEN)
4050 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
4051 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
4052 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
4053 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
4055 else
4057 WCHAR buf[16];
4058 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
4059 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
4060 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
4062 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
4063 fdimpl->custom_title = StrDupW(buf);
4064 fdimpl->custom_okbutton = StrDupW(buf);
4067 fdimpl->filterspecs = NULL;
4068 fdimpl->filterspec_count = 0;
4069 fdimpl->filetypeindex = 0;
4071 fdimpl->psia_selection = fdimpl->psia_results = NULL;
4072 fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
4074 list_init(&fdimpl->events_clients);
4075 fdimpl->events_next_cookie = 0;
4077 fdimpl->dlg_hwnd = NULL;
4078 fdimpl->peb = NULL;
4080 fdimpl->set_filename = NULL;
4081 fdimpl->default_ext = NULL;
4082 fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL;
4084 fdimpl->client_guid = GUID_NULL;
4086 /* FIXME: The default folder setting should be restored for the
4087 * application if it was previously set. */
4088 SHGetDesktopFolder(&psf);
4089 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
4090 IShellFolder_Release(psf);
4092 hr = init_custom_controls(fdimpl);
4093 if(FAILED(hr))
4095 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
4096 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4097 return E_FAIL;
4100 hr = IFileDialog2_QueryInterface(&fdimpl->IFileDialog2_iface, riid, ppv);
4101 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4102 return hr;
4105 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4107 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
4110 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4112 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);