comdlg32: Expand the filetype combobox dropdown to fit the contents.
[wine/multimedia.git] / dlls / comdlg32 / itemdlg.c
blob3b9711153b4ac1d8bf4f2e62d626059b0bc41fe2
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
25 #define NONAMELESSSTRUCT
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "wingdi.h"
31 #include "winreg.h"
32 #include "shlwapi.h"
34 #include "commdlg.h"
35 #include "cdlg.h"
36 #include "filedlgbrowser.h"
38 #include "wine/debug.h"
39 #include "wine/list.h"
41 #define IDC_NAV_TOOLBAR 200
42 #define IDC_NAVBACK 201
43 #define IDC_NAVFORWARD 202
45 #include <initguid.h>
46 /* This seems to be another version of IID_IFileDialogCustomize. If
47 * there is any difference I have yet to find it. */
48 DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F);
50 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
52 static const WCHAR notifysink_childW[] = {'n','f','s','_','c','h','i','l','d',0};
53 static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0};
55 enum ITEMDLG_TYPE {
56 ITEMDLG_TYPE_OPEN,
57 ITEMDLG_TYPE_SAVE
60 enum ITEMDLG_CCTRL_TYPE {
61 IDLG_CCTRL_MENU,
62 IDLG_CCTRL_PUSHBUTTON,
63 IDLG_CCTRL_COMBOBOX,
64 IDLG_CCTRL_RADIOBUTTONLIST,
65 IDLG_CCTRL_CHECKBUTTON,
66 IDLG_CCTRL_EDITBOX,
67 IDLG_CCTRL_SEPARATOR,
68 IDLG_CCTRL_TEXT,
69 IDLG_CCTRL_VISUALGROUP
72 typedef struct {
73 HWND hwnd, wrapper_hwnd;
74 UINT id, dlgid;
75 enum ITEMDLG_CCTRL_TYPE type;
76 CDCONTROLSTATEF cdcstate;
77 struct list entry;
79 struct list sub_cctrls;
80 struct list sub_cctrls_entry;
81 } customctrl;
83 typedef struct {
84 struct list entry;
85 IFileDialogEvents *pfde;
86 DWORD cookie;
87 } events_client;
89 typedef struct FileDialogImpl {
90 IFileDialog2 IFileDialog2_iface;
91 union {
92 IFileOpenDialog IFileOpenDialog_iface;
93 IFileSaveDialog IFileSaveDialog_iface;
94 } u;
95 enum ITEMDLG_TYPE dlg_type;
96 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
97 IServiceProvider IServiceProvider_iface;
98 ICommDlgBrowser3 ICommDlgBrowser3_iface;
99 IOleWindow IOleWindow_iface;
100 IFileDialogCustomize IFileDialogCustomize_iface;
101 LONG ref;
103 FILEOPENDIALOGOPTIONS options;
104 COMDLG_FILTERSPEC *filterspecs;
105 UINT filterspec_count;
106 UINT filetypeindex;
108 struct list events_clients;
109 DWORD events_next_cookie;
111 IShellItemArray *psia_selection;
112 IShellItemArray *psia_results;
113 IShellItem *psi_defaultfolder;
114 IShellItem *psi_setfolder;
115 IShellItem *psi_folder;
117 HWND dlg_hwnd;
118 IExplorerBrowser *peb;
119 DWORD ebevents_cookie;
121 LPWSTR set_filename;
122 LPWSTR default_ext;
123 LPWSTR custom_title;
124 LPWSTR custom_okbutton;
125 LPWSTR custom_cancelbutton;
126 LPWSTR custom_filenamelabel;
128 UINT cctrl_width, cctrl_def_height, cctrls_cols;
129 UINT cctrl_indent;
130 HWND cctrls_hwnd;
131 struct list cctrls;
132 UINT_PTR cctrl_next_dlgid;
133 customctrl *cctrl_active_vg;
135 GUID client_guid;
136 } FileDialogImpl;
138 /**************************************************************************
139 * Event wrappers.
141 static HRESULT events_OnFileOk(FileDialogImpl *This)
143 events_client *cursor;
144 HRESULT hr = S_OK;
145 TRACE("%p\n", This);
147 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
149 TRACE("Notifying %p\n", cursor);
150 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
151 if(FAILED(hr) && hr != E_NOTIMPL)
152 break;
155 if(hr == E_NOTIMPL)
156 hr = S_OK;
158 return hr;
161 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
163 events_client *cursor;
164 HRESULT hr = S_OK;
165 TRACE("%p (%p)\n", This, folder);
167 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
169 TRACE("Notifying %p\n", cursor);
170 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
171 if(FAILED(hr) && hr != E_NOTIMPL)
172 break;
175 if(hr == E_NOTIMPL)
176 hr = S_OK;
178 return hr;
181 static void events_OnFolderChange(FileDialogImpl *This)
183 events_client *cursor;
184 TRACE("%p\n", This);
186 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
188 TRACE("Notifying %p\n", cursor);
189 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
193 static void events_OnSelectionChange(FileDialogImpl *This)
195 events_client *cursor;
196 TRACE("%p\n", This);
198 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
200 TRACE("Notifying %p\n", cursor);
201 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
205 static void events_OnTypeChange(FileDialogImpl *This)
207 events_client *cursor;
208 TRACE("%p\n", This);
210 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
212 TRACE("Notifying %p\n", cursor);
213 IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
217 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
219 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
222 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
224 events_client *cursor;
225 TRACE("%p\n", This);
227 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
229 IFileDialogControlEvents *pfdce;
230 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
232 TRACE("Notifying %p\n", cursor);
233 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
234 IFileDialogControlEvents_Release(pfdce);
238 return S_OK;
241 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
243 events_client *cursor;
244 TRACE("%p\n", This);
246 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
248 IFileDialogControlEvents *pfdce;
249 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
251 TRACE("Notifying %p\n", cursor);
252 IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
253 IFileDialogControlEvents_Release(pfdce);
257 return S_OK;
260 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
262 events_client *cursor;
263 TRACE("%p\n", This);
265 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
267 IFileDialogControlEvents *pfdce;
268 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
270 TRACE("Notifying %p\n", cursor);
271 IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
272 IFileDialogControlEvents_Release(pfdce);
276 return S_OK;
279 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
280 DWORD ctl_id)
282 events_client *cursor;
283 TRACE("%p\n", This);
285 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
287 IFileDialogControlEvents *pfdce;
288 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
290 TRACE("Notifying %p\n", cursor);
291 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
292 IFileDialogControlEvents_Release(pfdce);
296 return S_OK;
299 /**************************************************************************
300 * Helper functions.
302 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
304 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
305 UINT len;
307 if(!hwnd_edit)
309 if(This->set_filename)
311 len = lstrlenW(This->set_filename);
312 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
313 lstrcpyW(*str, This->set_filename);
314 return len;
316 return FALSE;
319 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
320 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
321 if(!*str)
322 return FALSE;
324 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
325 return len;
328 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
330 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
332 if(This->set_filename)
333 LocalFree(This->set_filename);
335 This->set_filename = StrDupW(str);
337 return SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str);
340 static void fill_filename_from_selection(FileDialogImpl *This)
342 IShellItem *psi;
343 LPWSTR *names;
344 HRESULT hr;
345 UINT item_count, valid_count;
346 UINT len_total, i;
348 if(!This->psia_selection)
349 return;
351 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
352 if(FAILED(hr) || !item_count)
353 return;
355 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
357 /* Get names of the selected items */
358 valid_count = 0; len_total = 0;
359 for(i = 0; i < item_count; i++)
361 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
362 if(SUCCEEDED(hr))
364 UINT attr;
366 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
367 if(SUCCEEDED(hr) &&
368 (( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
369 (!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
370 continue;
372 hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
373 if(SUCCEEDED(hr))
375 len_total += lstrlenW(names[valid_count]) + 3;
376 valid_count++;
378 IShellItem_Release(psi);
382 if(valid_count == 1)
384 set_file_name(This, names[0]);
385 CoTaskMemFree(names[0]);
387 else if(valid_count > 1)
389 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
390 LPWSTR cur_point = string;
392 for(i = 0; i < valid_count; i++)
394 LPWSTR file = names[i];
395 *cur_point++ = '\"';
396 lstrcpyW(cur_point, file);
397 cur_point += lstrlenW(file);
398 *cur_point++ = '\"';
399 *cur_point++ = ' ';
400 CoTaskMemFree(file);
402 *(cur_point-1) = '\0';
404 set_file_name(This, string);
405 HeapFree(GetProcessHeap(), 0, string);
408 HeapFree(GetProcessHeap(), 0, names);
409 return;
412 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
414 WCHAR *endpos, *ext;
416 lstrcpyW(buf, spec);
417 if( (endpos = StrChrW(buf, ';')) )
418 *endpos = '\0';
420 ext = PathFindExtensionW(buf);
421 if(StrChrW(ext, '*'))
422 return NULL;
424 return ext;
427 static HRESULT on_default_action(FileDialogImpl *This)
429 IShellFolder *psf_parent, *psf_desktop;
430 LPITEMIDLIST *pidla;
431 LPITEMIDLIST current_folder;
432 LPWSTR fn_iter, files = NULL, tmp_files;
433 UINT file_count = 0, len, i;
434 int open_action;
435 HRESULT hr, ret = E_FAIL;
437 len = get_file_name(This, &tmp_files);
438 if(len)
440 UINT size_used;
441 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
442 CoTaskMemFree(tmp_files);
444 if(!file_count) return E_FAIL;
446 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
447 if(FAILED(hr))
449 ERR("Failed to get pidl for current directory.\n");
450 HeapFree(GetProcessHeap(), 0, files);
451 return hr;
454 TRACE("Acting on %d file(s).\n", file_count);
456 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
457 open_action = ONOPEN_OPEN;
458 fn_iter = files;
460 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
462 WCHAR canon_filename[MAX_PATH];
463 psf_parent = NULL;
465 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
467 if( (This->options & FOS_NOVALIDATE) &&
468 !(This->options & FOS_FILEMUSTEXIST) )
469 open_action = ONOPEN_OPEN;
470 else
471 open_action = ONOPEN_BROWSE;
473 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
474 This->options & ~FOS_FILEMUSTEXIST,
475 (This->dlg_type == ITEMDLG_TYPE_SAVE),
476 open_action);
478 /* Add the proper extension */
479 if(open_action == ONOPEN_OPEN)
481 static const WCHAR dotW[] = {'.',0};
483 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
485 WCHAR extbuf[MAX_PATH], *newext = NULL;
487 if(This->filterspec_count)
489 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
491 else if(This->default_ext)
493 lstrcpyW(extbuf, dotW);
494 lstrcatW(extbuf, This->default_ext);
495 newext = extbuf;
498 if(newext)
500 WCHAR *ext = PathFindExtensionW(canon_filename);
501 if(lstrcmpW(ext, newext))
502 lstrcatW(canon_filename, newext);
505 else
507 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
508 !PathFileExistsW(canon_filename))
510 if(This->default_ext)
512 lstrcatW(canon_filename, dotW);
513 lstrcatW(canon_filename, This->default_ext);
515 if(!PathFileExistsW(canon_filename))
517 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
518 open_action = ONOPEN_BROWSE;
521 else
523 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
524 open_action = ONOPEN_BROWSE;
530 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
532 if(psf_parent && !(open_action == ONOPEN_BROWSE))
533 IShellFolder_Release(psf_parent);
535 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
538 HeapFree(GetProcessHeap(), 0, files);
539 ILFree(current_folder);
541 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
542 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
544 switch(open_action)
546 case ONOPEN_SEARCH:
547 FIXME("Filtering not implemented.\n");
548 break;
550 case ONOPEN_BROWSE:
551 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
552 if(FAILED(hr))
553 ERR("Failed to browse to directory: %08x\n", hr);
555 IShellFolder_Release(psf_parent);
556 break;
558 case ONOPEN_OPEN:
559 hr = SHGetDesktopFolder(&psf_desktop);
560 if(SUCCEEDED(hr))
562 if(This->psia_results)
564 IShellItemArray_Release(This->psia_results);
565 This->psia_results = NULL;
568 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
569 &This->psia_results);
571 IShellFolder_Release(psf_desktop);
573 if(FAILED(hr))
574 break;
576 if(This->options & FOS_PICKFOLDERS)
578 SFGAOF attributes;
579 hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
580 if(hr != S_OK)
582 WCHAR buf[64];
583 LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, sizeof(buf)/sizeof(WCHAR));
585 MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
587 IShellItemArray_Release(This->psia_results);
588 This->psia_results = NULL;
589 break;
593 if(events_OnFileOk(This) == S_OK)
594 ret = S_OK;
596 break;
598 default:
599 ERR("Failed.\n");
600 break;
603 /* Clean up */
604 for(i = 0; i < file_count; i++)
605 ILFree(pidla[i]);
606 HeapFree(GetProcessHeap(), 0, pidla);
608 /* Success closes the dialog */
609 return ret;
612 /**************************************************************************
613 * Control functions.
615 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
617 customctrl *ctrl, *sub_ctrl;
619 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
621 if(ctrl->dlgid == dlgid)
622 return ctrl;
624 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
625 if(sub_ctrl->dlgid == dlgid)
626 return sub_ctrl;
629 ERR("Failed to find control with dialog id %d\n", dlgid);
630 return NULL;
633 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
635 customctrl *ctrl, *sub_ctrl;
637 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
639 if(ctrl->id == ctlid)
640 return ctrl;
642 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
643 if(sub_ctrl->id == ctlid)
644 return sub_ctrl;
648 TRACE("No existing control with control id %d\n", ctlid);
649 return NULL;
652 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
654 LPWSTR text;
655 UINT len, final_width;
656 UINT lines, final_height;
657 SIZE size;
658 RECT rc;
659 HDC hdc;
660 WCHAR *c;
662 TRACE("\n");
664 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
665 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
666 if(!text) return;
667 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
669 hdc = GetDC(hctrl);
670 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
671 ReleaseDC(hctrl, hdc);
673 if(len && multiline)
675 /* FIXME: line-wrap */
676 for(lines = 1, c = text; *c != '\0'; c++)
677 if(*c == '\n') lines++;
679 final_height = size.cy*lines + 2*4;
681 else
683 GetWindowRect(hctrl, &rc);
684 final_height = rc.bottom - rc.top;
687 final_width = min(max(size.cx, min_width) + 4, max_width);
688 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
689 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
691 HeapFree(GetProcessHeap(), 0, text);
694 static UINT ctrl_get_height(customctrl *ctrl) {
695 RECT rc;
696 GetWindowRect(ctrl->wrapper_hwnd, &rc);
697 return rc.bottom - rc.top;
700 static void ctrl_free(customctrl *ctrl)
702 customctrl *sub_cur1, *sub_cur2;
704 TRACE("Freeing control %p\n", ctrl);
705 if(ctrl->type == IDLG_CCTRL_MENU)
707 TBBUTTON tbb;
708 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
709 DestroyMenu((HMENU)tbb.dwData);
712 LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
714 list_remove(&sub_cur1->sub_cctrls_entry);
715 ctrl_free(sub_cur1);
718 DestroyWindow(ctrl->hwnd);
719 HeapFree(GetProcessHeap(), 0, ctrl);
722 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
724 RECT rc;
725 UINT total_height;
726 customctrl *sub_ctrl;
728 switch(ctrl->type)
730 case IDLG_CCTRL_PUSHBUTTON:
731 case IDLG_CCTRL_COMBOBOX:
732 case IDLG_CCTRL_CHECKBUTTON:
733 case IDLG_CCTRL_TEXT:
734 ctrl_resize(ctrl->hwnd, 160, 160, TRUE);
735 GetWindowRect(ctrl->hwnd, &rc);
736 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
737 SWP_NOZORDER|SWP_NOMOVE);
738 break;
739 case IDLG_CCTRL_VISUALGROUP:
740 total_height = 0;
741 ctrl_resize(ctrl->hwnd, 0, This->cctrl_indent, TRUE);
743 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
745 customctrl_resize(This, sub_ctrl);
746 SetWindowPos(sub_ctrl->wrapper_hwnd, NULL, This->cctrl_indent, total_height, 0, 0,
747 SWP_NOZORDER|SWP_NOSIZE);
749 total_height += ctrl_get_height(sub_ctrl);
752 /* The label should be right adjusted */
754 UINT width, height;
756 GetWindowRect(ctrl->hwnd, &rc);
757 width = rc.right - rc.left;
758 height = rc.bottom - rc.top;
760 SetWindowPos(ctrl->hwnd, NULL, This->cctrl_indent - width, 0, width, height, SWP_NOZORDER);
763 /* Resize the wrapper window to fit all the sub controls */
764 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, This->cctrl_width + This->cctrl_indent, total_height,
765 SWP_NOZORDER|SWP_NOMOVE);
766 break;
767 case IDLG_CCTRL_RADIOBUTTONLIST:
768 case IDLG_CCTRL_EDITBOX:
769 case IDLG_CCTRL_SEPARATOR:
770 case IDLG_CCTRL_MENU:
771 /* Nothing */
772 break;
776 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
778 FileDialogImpl *This = crs->lpCreateParams;
779 TRACE("%p\n", This);
781 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
782 return TRUE;
785 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
787 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
789 TRACE("%p, %lx\n", This, wparam);
791 if(ctrl)
793 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
795 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
796 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
798 else
799 cctrl_event_OnButtonClicked(This, ctrl->id);
802 return TRUE;
805 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
807 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
808 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
810 if(ctrl)
812 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
813 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
815 cctrl_event_OnItemSelected(This, ctrl->id, selid);
817 return TRUE;
820 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
822 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
823 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
824 POINT pt = { 0, nmtb->rcButton.bottom };
825 TBBUTTON tbb;
826 UINT idcmd;
828 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
830 if(ctrl)
832 cctrl_event_OnControlActivating(This,ctrl->id);
834 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
835 ClientToScreen(ctrl->hwnd, &pt);
836 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
837 if(idcmd)
838 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
841 return TBDDRET_DEFAULT;
844 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
846 switch(HIWORD(wparam))
848 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
849 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
852 return FALSE;
855 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
857 NMHDR *nmhdr = (NMHDR*)lparam;
859 switch(nmhdr->code)
861 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
864 return FALSE;
867 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
869 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
870 customctrl *ctrl;
871 HWND hwnd_child;
872 RECT rc;
874 switch(message)
876 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
877 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
878 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
879 case WM_SIZE:
880 hwnd_child = GetPropW(hwnd, notifysink_childW);
881 ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA);
882 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
884 GetClientRect(hwnd, &rc);
885 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
887 return TRUE;
890 return DefWindowProcW(hwnd, message, wparam, lparam);
893 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
894 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
895 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
897 HWND ns_hwnd, control_hwnd, parent_hwnd;
898 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
899 customctrl *ctrl;
901 if(get_cctrl(This, id))
902 return E_UNEXPECTED; /* Duplicate id */
904 if(This->cctrl_active_vg)
905 parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
906 else
907 parent_hwnd = This->cctrls_hwnd;
909 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
910 0, 0, This->cctrl_width, height, parent_hwnd,
911 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
912 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
913 0, 0, This->cctrl_width, height, ns_hwnd,
914 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
916 if(!ns_hwnd || !control_hwnd)
918 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
919 DestroyWindow(ns_hwnd);
920 DestroyWindow(control_hwnd);
922 return E_FAIL;
925 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
927 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
928 if(!ctrl)
929 return E_OUTOFMEMORY;
931 ctrl->hwnd = control_hwnd;
932 ctrl->wrapper_hwnd = ns_hwnd;
933 ctrl->id = id;
934 ctrl->dlgid = This->cctrl_next_dlgid;
935 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
936 list_init(&ctrl->sub_cctrls);
938 if(This->cctrl_active_vg)
939 list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
940 else
941 list_add_tail(&This->cctrls, &ctrl->entry);
943 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl);
945 if(ppctrl) *ppctrl = ctrl;
947 This->cctrl_next_dlgid++;
948 return S_OK;
951 /**************************************************************************
952 * Container functions.
954 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
956 UINT container_height;
957 UINT column_width;
958 UINT nr_of_cols;
959 UINT max_control_height, total_height = 0;
960 UINT cur_col_pos, cur_row_pos;
961 customctrl *ctrl;
962 BOOL fits_height;
963 static const UINT cspacing = 90; /* Columns are spaced with 90px */
964 static const UINT rspacing = 4; /* Rows are spaced with 4 px. */
966 /* Given the new width of the container, this function determines the
967 * needed height of the container and places the controls according to
968 * the new layout. Returns the new height.
971 TRACE("%p\n", This);
973 column_width = This->cctrl_width + cspacing;
974 nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
976 /* We don't need to do anything unless the number of visible columns has changed. */
977 if(nr_of_cols == This->cctrls_cols)
979 RECT rc;
980 GetWindowRect(This->cctrls_hwnd, &rc);
981 return rc.bottom - rc.top;
984 This->cctrls_cols = nr_of_cols;
986 /* Get the size of the tallest control, and the total size of
987 * all the controls to figure out the number of slots we need.
989 max_control_height = 0;
990 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
992 if(ctrl->cdcstate & CDCS_VISIBLE)
994 UINT control_height = ctrl_get_height(ctrl);
995 max_control_height = max(max_control_height, control_height);
997 total_height += control_height + rspacing;
1001 if(!total_height)
1002 return 0;
1004 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
1005 TRACE("Guess: container_height: %d\n",container_height);
1007 /* Incrementally increase container_height until all the controls
1008 * fit.
1010 do {
1011 UINT columns_needed = 1;
1012 cur_row_pos = 0;
1014 fits_height = TRUE;
1015 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1017 if(ctrl->cdcstate & CDCS_VISIBLE)
1019 UINT control_height = ctrl_get_height(ctrl);
1021 if(cur_row_pos + control_height > container_height)
1023 if(++columns_needed > nr_of_cols)
1025 container_height += 1;
1026 fits_height = FALSE;
1027 break;
1029 cur_row_pos = 0;
1032 cur_row_pos += control_height + rspacing;
1035 } while(!fits_height);
1037 TRACE("Final container height: %d\n", container_height);
1039 /* Move the controls to their final destination
1041 cur_col_pos = 0, cur_row_pos = 0;
1042 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1044 if(ctrl->cdcstate & CDCS_VISIBLE)
1046 RECT rc;
1047 UINT control_height, control_indent;
1048 GetWindowRect(ctrl->wrapper_hwnd, &rc);
1049 control_height = rc.bottom - rc.top;
1051 if(cur_row_pos + control_height > container_height)
1053 cur_row_pos = 0;
1054 cur_col_pos += This->cctrl_width + cspacing;
1058 if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
1059 control_indent = 0;
1060 else
1061 control_indent = This->cctrl_indent;
1063 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
1064 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1066 cur_row_pos += control_height + rspacing;
1070 /* Sanity check */
1071 if(cur_row_pos + This->cctrl_width > container_width)
1072 ERR("-- Failed to place controls properly.\n");
1074 return container_height;
1077 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
1079 LONG wndstyle;
1081 if(parent)
1083 customctrl *ctrl, *sub_ctrl;
1084 HFONT font;
1086 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1087 wndstyle &= ~(WS_POPUP);
1088 wndstyle |= WS_CHILD;
1089 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1091 SetParent(This->cctrls_hwnd, parent);
1092 ShowWindow(This->cctrls_hwnd, TRUE);
1094 /* Set the fonts to match the dialog font. */
1095 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
1096 if(!font)
1097 ERR("Failed to get font handle from dialog.\n");
1099 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1101 if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1103 /* If this is a VisualGroup */
1104 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1106 if(font) SendMessageW(sub_ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1109 customctrl_resize(This, ctrl);
1112 else
1114 ShowWindow(This->cctrls_hwnd, FALSE);
1116 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1117 wndstyle &= ~(WS_CHILD);
1118 wndstyle |= WS_POPUP;
1119 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1121 SetParent(This->cctrls_hwnd, NULL);
1125 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
1127 FileDialogImpl *This = crs->lpCreateParams;
1128 TRACE("%p\n", This);
1130 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1131 return TRUE;
1134 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
1136 customctrl *cur1, *cur2;
1137 TRACE("%p\n", This);
1139 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1141 list_remove(&cur1->entry);
1142 ctrl_free(cur1);
1145 return TRUE;
1148 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1150 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1152 switch(umessage)
1154 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1155 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1156 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1159 return FALSE;
1162 static HRESULT init_custom_controls(FileDialogImpl *This)
1164 WNDCLASSW wc;
1165 static const WCHAR ctrl_container_classname[] =
1166 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1168 InitCommonControlsEx(NULL);
1170 This->cctrl_width = 160; /* Controls have a fixed width */
1171 This->cctrl_indent = 100;
1172 This->cctrl_def_height = 23;
1173 This->cctrls_cols = 0;
1175 This->cctrl_next_dlgid = 0x2000;
1176 list_init(&This->cctrls);
1177 This->cctrl_active_vg = NULL;
1179 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1181 wc.style = CS_HREDRAW | CS_VREDRAW;
1182 wc.lpfnWndProc = ctrl_container_wndproc;
1183 wc.cbClsExtra = 0;
1184 wc.cbWndExtra = 0;
1185 wc.hInstance = COMDLG32_hInstance;
1186 wc.hIcon = 0;
1187 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1188 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1189 wc.lpszMenuName = NULL;
1190 wc.lpszClassName = ctrl_container_classname;
1192 if(!RegisterClassW(&wc)) return E_FAIL;
1195 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1196 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1197 0, 0, 0, 0, NULL, 0,
1198 COMDLG32_hInstance, (void*)This);
1199 if(!This->cctrls_hwnd)
1200 return E_FAIL;
1202 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1204 /* Register class for */
1205 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1206 wc.hInstance != COMDLG32_hInstance)
1208 wc.style = CS_HREDRAW | CS_VREDRAW;
1209 wc.lpfnWndProc = notifysink_proc;
1210 wc.cbClsExtra = 0;
1211 wc.cbWndExtra = 0;
1212 wc.hInstance = COMDLG32_hInstance;
1213 wc.hIcon = 0;
1214 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1215 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1216 wc.lpszMenuName = NULL;
1217 wc.lpszClassName = floatnotifysinkW;
1219 if (!RegisterClassW(&wc))
1220 ERR("Failed to register FloatNotifySink window class.\n");
1223 return S_OK;
1226 /**************************************************************************
1227 * Window related functions.
1229 static SIZE update_layout(FileDialogImpl *This)
1231 HDWP hdwp;
1232 HWND hwnd;
1233 RECT dialog_rc;
1234 RECT cancel_rc, open_rc;
1235 RECT filetype_rc, filename_rc, filenamelabel_rc;
1236 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1237 int missing_width, missing_height;
1238 static const UINT vspacing = 4, hspacing = 4;
1239 SIZE ret;
1241 GetClientRect(This->dlg_hwnd, &dialog_rc);
1243 missing_width = max(0, 320 - dialog_rc.right);
1244 missing_height = max(0, 200 - dialog_rc.bottom);
1246 if(missing_width || missing_height)
1248 TRACE("Missing (%d, %d)\n", missing_width, missing_height);
1249 ret.cx = missing_width;
1250 ret.cy = missing_height;
1251 return ret;
1254 /****
1255 * Calculate the size of the dialog and all the parts.
1258 /* Cancel button */
1259 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1260 if(hwnd)
1262 int cancel_width, cancel_height;
1263 GetWindowRect(hwnd, &cancel_rc);
1264 cancel_width = cancel_rc.right - cancel_rc.left;
1265 cancel_height = cancel_rc.bottom - cancel_rc.top;
1267 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1268 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1269 cancel_rc.right = cancel_rc.left + cancel_width;
1270 cancel_rc.bottom = cancel_rc.top + cancel_height;
1273 /* Open/Save button */
1274 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1275 if(hwnd)
1277 int open_width, open_height;
1278 GetWindowRect(hwnd, &open_rc);
1279 open_width = open_rc.right - open_rc.left;
1280 open_height = open_rc.bottom - open_rc.top;
1282 open_rc.left = cancel_rc.left - open_width - hspacing;
1283 open_rc.top = cancel_rc.top;
1284 open_rc.right = open_rc.left + open_width;
1285 open_rc.bottom = open_rc.top + open_height;
1288 /* The filetype combobox. */
1289 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1290 if(hwnd)
1292 int filetype_width, filetype_height;
1293 GetWindowRect(hwnd, &filetype_rc);
1295 filetype_width = filetype_rc.right - filetype_rc.left;
1296 filetype_height = filetype_rc.bottom - filetype_rc.top;
1298 filetype_rc.right = cancel_rc.right;
1300 filetype_rc.left = filetype_rc.right - filetype_width;
1301 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1302 filetype_rc.bottom = filetype_rc.top + filetype_height;
1304 if(!This->filterspec_count)
1305 filetype_rc.left = filetype_rc.right;
1308 /* Filename label. */
1309 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1310 if(hwnd)
1312 int filetypelabel_width, filetypelabel_height;
1313 GetWindowRect(hwnd, &filenamelabel_rc);
1315 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1316 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1318 filenamelabel_rc.left = 160; /* FIXME */
1319 filenamelabel_rc.top = filetype_rc.top;
1320 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1321 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1324 /* Filename edit box. */
1325 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1326 if(hwnd)
1328 int filename_width, filename_height;
1329 GetWindowRect(hwnd, &filename_rc);
1331 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1332 filename_height = filename_rc.bottom - filename_rc.top;
1334 filename_rc.left = filenamelabel_rc.right + hspacing;
1335 filename_rc.top = filetype_rc.top;
1336 filename_rc.right = filename_rc.left + filename_width;
1337 filename_rc.bottom = filename_rc.top + filename_height;
1340 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1341 if(hwnd)
1343 GetWindowRect(hwnd, &toolbar_rc);
1344 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1347 /* The custom controls */
1348 customctrls_rc.left = dialog_rc.left + hspacing;
1349 customctrls_rc.right = dialog_rc.right - hspacing;
1350 customctrls_rc.bottom = filename_rc.top - vspacing;
1351 customctrls_rc.top = customctrls_rc.bottom -
1352 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1354 /* The ExplorerBrowser control. */
1355 ebrowser_rc.left = dialog_rc.left + hspacing;
1356 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1357 ebrowser_rc.right = dialog_rc.right - hspacing;
1358 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1360 /****
1361 * Move everything to the right place.
1364 /* FIXME: The Save Dialog uses a slightly different layout. */
1365 hdwp = BeginDeferWindowPos(7);
1367 if(hdwp && This->peb)
1368 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1370 if(hdwp && This->cctrls_hwnd)
1371 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1372 customctrls_rc.left, customctrls_rc.top,
1373 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1374 SWP_NOZORDER | SWP_NOACTIVATE);
1376 /* The default controls */
1377 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1378 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1379 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1381 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1382 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1383 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1384 SWP_NOZORDER | SWP_NOACTIVATE);
1386 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1387 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1388 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1390 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1391 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1392 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1394 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1395 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1396 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1398 if(hdwp)
1399 EndDeferWindowPos(hdwp);
1400 else
1401 ERR("Failed to position dialog controls.\n");
1403 ret.cx = 0; ret.cy = 0;
1404 return ret;
1407 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1409 IShellItem *psi_folder;
1410 FOLDERSETTINGS fos;
1411 RECT rc = {0};
1412 HRESULT hr;
1414 /* Create ExplorerBrowser instance */
1415 OleInitialize(NULL);
1417 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1418 &IID_IExplorerBrowser, (void**)&This->peb);
1419 if(FAILED(hr))
1421 ERR("Failed to instantiate ExplorerBrowser control.\n");
1422 return hr;
1425 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES);
1427 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1428 if(FAILED(hr))
1430 ERR("Failed to initialize the ExplorerBrowser control.\n");
1431 IExplorerBrowser_Release(This->peb);
1432 This->peb = NULL;
1433 return hr;
1435 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1436 if(FAILED(hr))
1437 ERR("Advise (ExplorerBrowser) failed.\n");
1439 /* Get previous options? */
1440 fos.ViewMode = fos.fFlags = 0;
1441 if(!(This->options & FOS_ALLOWMULTISELECT))
1442 fos.fFlags |= FWF_SINGLESEL;
1444 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1446 hr = IUnknown_SetSite((IUnknown*)This->peb, (IUnknown*)This);
1447 if(FAILED(hr))
1448 ERR("SetSite (ExplorerBrowser) failed.\n");
1450 /* Browse somewhere */
1451 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1452 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1454 return S_OK;
1457 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1459 HWND htoolbar;
1460 TBADDBITMAP tbab;
1461 TBBUTTON button[2];
1463 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1464 0, 0, 0, 0,
1465 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1467 tbab.hInst = HINST_COMMCTRL;
1468 tbab.nID = IDB_HIST_LARGE_COLOR;
1469 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1471 button[0].iBitmap = HIST_BACK;
1472 button[0].idCommand = IDC_NAVBACK;
1473 button[0].fsState = TBSTATE_ENABLED;
1474 button[0].fsStyle = BTNS_BUTTON;
1475 button[0].dwData = 0;
1476 button[0].iString = 0;
1478 button[1].iBitmap = HIST_FORWARD;
1479 button[1].idCommand = IDC_NAVFORWARD;
1480 button[1].fsState = TBSTATE_ENABLED;
1481 button[1].fsStyle = BTNS_BUTTON;
1482 button[1].dwData = 0;
1483 button[1].iString = 0;
1485 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1486 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1487 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1490 static void update_control_text(FileDialogImpl *This)
1492 HWND hitem;
1493 if(This->custom_title)
1494 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1496 if(This->custom_okbutton &&
1497 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1499 SetWindowTextW(hitem, This->custom_okbutton);
1500 ctrl_resize(hitem, 50, 250, FALSE);
1503 if(This->custom_cancelbutton &&
1504 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1506 SetWindowTextW(hitem, This->custom_cancelbutton);
1507 ctrl_resize(hitem, 50, 250, FALSE);
1510 if(This->custom_filenamelabel &&
1511 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1513 SetWindowTextW(hitem, This->custom_filenamelabel);
1514 ctrl_resize(hitem, 50, 250, FALSE);
1518 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1520 FileDialogImpl *This = (FileDialogImpl*)lParam;
1521 HWND hitem;
1523 TRACE("(%p, %p)\n", This, hwnd);
1525 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1526 This->dlg_hwnd = hwnd;
1528 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1529 if(hitem) ShowWindow(hitem, SW_HIDE);
1531 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1532 if(hitem) ShowWindow(hitem, SW_HIDE);
1534 /* Fill filetypes combobox, or hide it. */
1535 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1536 if(This->filterspec_count)
1538 HDC hdc;
1539 HFONT font;
1540 SIZE size;
1541 UINT i, maxwidth = 0;
1543 hdc = GetDC(hitem);
1544 font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
1545 SelectObject(hdc, font);
1547 for(i = 0; i < This->filterspec_count; i++)
1549 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
1551 if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
1552 maxwidth = max(maxwidth, size.cx);
1554 ReleaseDC(hitem, hdc);
1556 if(maxwidth > 0)
1558 maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
1559 SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
1561 else
1562 ERR("Failed to calculate width of filetype dropdown\n");
1564 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
1566 else
1567 ShowWindow(hitem, SW_HIDE);
1569 if(This->set_filename &&
1570 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1571 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
1573 ctrl_container_reparent(This, This->dlg_hwnd);
1574 init_explorerbrowser(This);
1575 init_toolbar(This, hwnd);
1576 update_control_text(This);
1577 update_layout(This);
1579 if(This->filterspec_count)
1580 events_OnTypeChange(This);
1582 return TRUE;
1585 static LRESULT on_wm_size(FileDialogImpl *This)
1587 update_layout(This);
1588 return FALSE;
1591 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
1593 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
1594 TRACE("%p (%p)\n", This, mmi);
1596 /* FIXME */
1597 mmi->ptMinTrackSize.x = 640;
1598 mmi->ptMinTrackSize.y = 480;
1600 return FALSE;
1603 static LRESULT on_wm_destroy(FileDialogImpl *This)
1605 TRACE("%p\n", This);
1607 if(This->peb)
1609 IExplorerBrowser_Destroy(This->peb);
1610 IExplorerBrowser_Release(This->peb);
1611 This->peb = NULL;
1614 ctrl_container_reparent(This, NULL);
1615 This->dlg_hwnd = NULL;
1617 return TRUE;
1620 static LRESULT on_idok(FileDialogImpl *This)
1622 TRACE("%p\n", This);
1624 if(SUCCEEDED(on_default_action(This)))
1625 EndDialog(This->dlg_hwnd, S_OK);
1627 return FALSE;
1630 static LRESULT on_idcancel(FileDialogImpl *This)
1632 TRACE("%p\n", This);
1634 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
1636 return FALSE;
1639 static LRESULT on_browse_back(FileDialogImpl *This)
1641 TRACE("%p\n", This);
1642 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
1643 return FALSE;
1646 static LRESULT on_browse_forward(FileDialogImpl *This)
1648 TRACE("%p\n", This);
1649 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
1650 return FALSE;
1653 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1655 if(HIWORD(wparam) == CBN_SELCHANGE)
1657 IShellView *psv;
1658 HRESULT hr;
1659 LPWSTR filename;
1660 UINT prev_index = This->filetypeindex;
1662 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
1663 TRACE("File type selection changed to %d.\n", This->filetypeindex);
1665 if(prev_index == This->filetypeindex)
1666 return FALSE;
1668 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
1669 if(SUCCEEDED(hr))
1671 IShellView_Refresh(psv);
1672 IShellView_Release(psv);
1675 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
1677 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
1679 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
1680 if(ext)
1682 lstrcpyW(buf, filename);
1684 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
1685 PathRemoveExtensionW(buf);
1687 lstrcatW(buf, ext);
1688 set_file_name(This, buf);
1690 CoTaskMemFree(filename);
1693 /* The documentation claims that OnTypeChange is called only
1694 * when the dialog is opened, but this is obviously not the
1695 * case. */
1696 events_OnTypeChange(This);
1699 return FALSE;
1702 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1704 switch(LOWORD(wparam))
1706 case IDOK: return on_idok(This);
1707 case IDCANCEL: return on_idcancel(This);
1708 case IDC_NAVBACK: return on_browse_back(This);
1709 case IDC_NAVFORWARD: return on_browse_forward(This);
1710 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
1711 default: TRACE("Unknown command.\n");
1713 return FALSE;
1716 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1718 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1720 switch(umessage)
1722 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
1723 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
1724 case WM_SIZE: return on_wm_size(This);
1725 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
1726 case WM_DESTROY: return on_wm_destroy(This);
1729 return FALSE;
1732 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
1734 INT_PTR res;
1736 SetLastError(0);
1737 res = DialogBoxParamW(COMDLG32_hInstance,
1738 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
1739 parent, itemdlg_dlgproc, (LPARAM)This);
1740 This->dlg_hwnd = NULL;
1741 if(res == -1)
1743 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
1744 return E_FAIL;
1747 TRACE("Returning 0x%08x\n", (HRESULT)res);
1748 return (HRESULT)res;
1751 /**************************************************************************
1752 * IFileDialog implementation
1754 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
1756 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
1759 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
1760 REFIID riid,
1761 void **ppvObject)
1763 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1764 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1766 *ppvObject = NULL;
1767 if(IsEqualGUID(riid, &IID_IUnknown) ||
1768 IsEqualGUID(riid, &IID_IFileDialog) ||
1769 IsEqualGUID(riid, &IID_IFileDialog2))
1771 *ppvObject = iface;
1773 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
1775 *ppvObject = &This->u.IFileOpenDialog_iface;
1777 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
1779 *ppvObject = &This->u.IFileSaveDialog_iface;
1781 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
1783 *ppvObject = &This->IExplorerBrowserEvents_iface;
1785 else if(IsEqualGUID(riid, &IID_IServiceProvider))
1787 *ppvObject = &This->IServiceProvider_iface;
1789 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
1790 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
1791 IsEqualGUID(&IID_ICommDlgBrowser, riid))
1793 *ppvObject = &This->ICommDlgBrowser3_iface;
1795 else if(IsEqualGUID(&IID_IOleWindow, riid))
1797 *ppvObject = &This->IOleWindow_iface;
1799 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
1800 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
1802 *ppvObject = &This->IFileDialogCustomize_iface;
1804 else
1805 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
1807 if(*ppvObject)
1809 IUnknown_AddRef((IUnknown*)*ppvObject);
1810 return S_OK;
1813 return E_NOINTERFACE;
1816 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
1818 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1819 LONG ref = InterlockedIncrement(&This->ref);
1820 TRACE("%p - ref %d\n", This, ref);
1822 return ref;
1825 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
1827 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1828 LONG ref = InterlockedDecrement(&This->ref);
1829 TRACE("%p - ref %d\n", This, ref);
1831 if(!ref)
1833 UINT i;
1834 for(i = 0; i < This->filterspec_count; i++)
1836 LocalFree((void*)This->filterspecs[i].pszName);
1837 LocalFree((void*)This->filterspecs[i].pszSpec);
1839 HeapFree(GetProcessHeap(), 0, This->filterspecs);
1841 DestroyWindow(This->cctrls_hwnd);
1843 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
1844 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
1845 if(This->psi_folder) IShellItem_Release(This->psi_folder);
1846 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
1847 if(This->psia_results) IShellItemArray_Release(This->psia_results);
1849 LocalFree(This->set_filename);
1850 LocalFree(This->default_ext);
1851 LocalFree(This->custom_title);
1852 LocalFree(This->custom_okbutton);
1853 LocalFree(This->custom_cancelbutton);
1854 LocalFree(This->custom_filenamelabel);
1856 HeapFree(GetProcessHeap(), 0, This);
1859 return ref;
1862 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
1864 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1865 TRACE("%p (%p)\n", iface, hwndOwner);
1867 return create_dialog(This, hwndOwner);
1870 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
1871 const COMDLG_FILTERSPEC *rgFilterSpec)
1873 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1874 UINT i;
1875 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
1877 if(This->filterspecs)
1878 return E_UNEXPECTED;
1880 if(!rgFilterSpec)
1881 return E_INVALIDARG;
1883 if(!cFileTypes)
1884 return S_OK;
1886 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
1887 for(i = 0; i < cFileTypes; i++)
1889 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
1890 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
1892 This->filterspec_count = cFileTypes;
1894 return S_OK;
1897 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
1899 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1900 TRACE("%p (%d)\n", This, iFileType);
1902 if(!This->filterspecs)
1903 return E_FAIL;
1905 iFileType = max(iFileType, 1);
1906 iFileType = min(iFileType, This->filterspec_count);
1907 This->filetypeindex = iFileType-1;
1909 return S_OK;
1912 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
1914 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1915 TRACE("%p (%p)\n", This, piFileType);
1917 if(!piFileType)
1918 return E_INVALIDARG;
1920 if(This->filterspec_count == 0)
1921 *piFileType = 0;
1922 else
1923 *piFileType = This->filetypeindex + 1;
1925 return S_OK;
1928 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
1930 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1931 events_client *client;
1932 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
1934 if(!pfde || !pdwCookie)
1935 return E_INVALIDARG;
1937 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
1938 client->pfde = pfde;
1939 client->cookie = ++This->events_next_cookie;
1941 IFileDialogEvents_AddRef(pfde);
1942 *pdwCookie = client->cookie;
1944 list_add_tail(&This->events_clients, &client->entry);
1946 return S_OK;
1949 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
1951 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1952 events_client *client, *found = NULL;
1953 TRACE("%p (%d)\n", This, dwCookie);
1955 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
1957 if(client->cookie == dwCookie)
1959 found = client;
1960 break;
1964 if(found)
1966 list_remove(&found->entry);
1967 IFileDialogEvents_Release(found->pfde);
1968 HeapFree(GetProcessHeap(), 0, found);
1969 return S_OK;
1972 return E_INVALIDARG;
1975 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
1977 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1978 TRACE("%p (0x%x)\n", This, fos);
1980 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
1982 WCHAR buf[30];
1983 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, sizeof(buf)/sizeof(WCHAR));
1984 IFileDialog2_SetTitle(iface, buf);
1987 This->options = fos;
1989 return S_OK;
1992 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
1994 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1995 TRACE("%p (%p)\n", This, pfos);
1997 if(!pfos)
1998 return E_INVALIDARG;
2000 *pfos = This->options;
2002 return S_OK;
2005 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
2007 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2008 TRACE("%p (%p)\n", This, psi);
2009 if(This->psi_defaultfolder)
2010 IShellItem_Release(This->psi_defaultfolder);
2012 This->psi_defaultfolder = psi;
2014 if(This->psi_defaultfolder)
2015 IShellItem_AddRef(This->psi_defaultfolder);
2017 return S_OK;
2020 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
2022 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2023 TRACE("%p (%p)\n", This, psi);
2024 if(This->psi_setfolder)
2025 IShellItem_Release(This->psi_setfolder);
2027 This->psi_setfolder = psi;
2029 if(This->psi_setfolder)
2030 IShellItem_AddRef(This->psi_setfolder);
2032 return S_OK;
2035 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
2037 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2038 TRACE("%p (%p)\n", This, ppsi);
2039 if(!ppsi)
2040 return E_INVALIDARG;
2042 /* FIXME:
2043 If the dialog is shown, return the current(ly selected) folder. */
2045 *ppsi = NULL;
2046 if(This->psi_folder)
2047 *ppsi = This->psi_folder;
2048 else if(This->psi_setfolder)
2049 *ppsi = This->psi_setfolder;
2050 else if(This->psi_defaultfolder)
2051 *ppsi = This->psi_defaultfolder;
2053 if(*ppsi)
2055 IShellItem_AddRef(*ppsi);
2056 return S_OK;
2059 return E_FAIL;
2062 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
2064 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2065 HRESULT hr;
2066 TRACE("%p (%p)\n", This, ppsi);
2068 if(!ppsi)
2069 return E_INVALIDARG;
2071 if(This->psia_selection)
2073 /* FIXME: Check filename edit box */
2074 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2075 return hr;
2078 return E_FAIL;
2081 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
2083 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2084 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2086 set_file_name(This, pszName);
2088 return S_OK;
2091 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
2093 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2094 TRACE("%p (%p)\n", iface, pszName);
2096 if(!pszName)
2097 return E_INVALIDARG;
2099 *pszName = NULL;
2100 if(get_file_name(This, pszName))
2101 return S_OK;
2102 else
2103 return E_FAIL;
2106 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
2108 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2109 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2111 LocalFree(This->custom_title);
2112 This->custom_title = StrDupW(pszTitle);
2113 update_control_text(This);
2115 return S_OK;
2118 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
2120 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2121 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2123 LocalFree(This->custom_okbutton);
2124 This->custom_okbutton = StrDupW(pszText);
2125 update_control_text(This);
2126 update_layout(This);
2128 return S_OK;
2131 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2133 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2134 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2136 LocalFree(This->custom_filenamelabel);
2137 This->custom_filenamelabel = StrDupW(pszLabel);
2138 update_control_text(This);
2139 update_layout(This);
2141 return S_OK;
2144 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
2146 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2147 HRESULT hr;
2148 TRACE("%p (%p)\n", This, ppsi);
2150 if(!ppsi)
2151 return E_INVALIDARG;
2153 if(This->psia_results)
2155 UINT item_count;
2156 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2157 if(SUCCEEDED(hr))
2159 if(item_count != 1)
2160 return E_FAIL;
2162 /* Adds a reference. */
2163 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2166 return hr;
2169 return E_UNEXPECTED;
2172 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2174 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2175 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2176 return E_NOTIMPL;
2179 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2181 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2182 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2184 LocalFree(This->default_ext);
2185 This->default_ext = StrDupW(pszDefaultExtension);
2187 return S_OK;
2190 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2192 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2193 TRACE("%p (0x%08x)\n", This, hr);
2195 if(This->dlg_hwnd)
2196 EndDialog(This->dlg_hwnd, hr);
2198 return S_OK;
2201 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2203 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2204 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2205 This->client_guid = *guid;
2206 return S_OK;
2209 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2211 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2212 FIXME("stub - %p\n", This);
2213 return E_NOTIMPL;
2216 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2218 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2219 FIXME("stub - %p (%p)\n", This, pFilter);
2220 return E_NOTIMPL;
2223 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2225 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2226 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2228 LocalFree(This->custom_cancelbutton);
2229 This->custom_cancelbutton = StrDupW(pszLabel);
2230 update_control_text(This);
2231 update_layout(This);
2233 return S_OK;
2236 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2238 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2239 FIXME("stub - %p (%p)\n", This, psi);
2240 return E_NOTIMPL;
2243 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2244 IFileDialog2_fnQueryInterface,
2245 IFileDialog2_fnAddRef,
2246 IFileDialog2_fnRelease,
2247 IFileDialog2_fnShow,
2248 IFileDialog2_fnSetFileTypes,
2249 IFileDialog2_fnSetFileTypeIndex,
2250 IFileDialog2_fnGetFileTypeIndex,
2251 IFileDialog2_fnAdvise,
2252 IFileDialog2_fnUnadvise,
2253 IFileDialog2_fnSetOptions,
2254 IFileDialog2_fnGetOptions,
2255 IFileDialog2_fnSetDefaultFolder,
2256 IFileDialog2_fnSetFolder,
2257 IFileDialog2_fnGetFolder,
2258 IFileDialog2_fnGetCurrentSelection,
2259 IFileDialog2_fnSetFileName,
2260 IFileDialog2_fnGetFileName,
2261 IFileDialog2_fnSetTitle,
2262 IFileDialog2_fnSetOkButtonLabel,
2263 IFileDialog2_fnSetFileNameLabel,
2264 IFileDialog2_fnGetResult,
2265 IFileDialog2_fnAddPlace,
2266 IFileDialog2_fnSetDefaultExtension,
2267 IFileDialog2_fnClose,
2268 IFileDialog2_fnSetClientGuid,
2269 IFileDialog2_fnClearClientData,
2270 IFileDialog2_fnSetFilter,
2271 IFileDialog2_fnSetCancelButtonLabel,
2272 IFileDialog2_fnSetNavigationRoot
2275 /**************************************************************************
2276 * IFileOpenDialog
2278 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2280 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2283 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2284 REFIID riid, void **ppvObject)
2286 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2287 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2290 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2292 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2293 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2296 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2298 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2299 return IFileDialog2_Release(&This->IFileDialog2_iface);
2302 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2304 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2305 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2308 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2309 const COMDLG_FILTERSPEC *rgFilterSpec)
2311 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2312 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2315 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2317 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2318 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2321 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2323 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2324 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2327 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2328 DWORD *pdwCookie)
2330 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2331 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2334 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2336 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2337 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2340 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2342 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2343 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2346 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2348 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2349 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2352 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2354 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2355 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2358 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2360 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2361 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2364 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2366 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2367 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2370 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2372 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2373 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2376 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2378 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2379 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2382 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2384 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2385 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2388 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2390 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2391 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2394 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2396 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2397 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2400 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2402 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2403 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2406 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2408 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2409 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2412 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2414 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2415 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2418 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2419 LPCWSTR pszDefaultExtension)
2421 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2422 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2425 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2427 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2428 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2431 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2433 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2434 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2437 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2439 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2440 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2443 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2445 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2446 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2449 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2451 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2452 TRACE("%p (%p)\n", This, ppenum);
2454 *ppenum = This->psia_results;
2456 if(*ppenum)
2458 IShellItemArray_AddRef(*ppenum);
2459 return S_OK;
2462 return E_FAIL;
2465 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2467 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2468 TRACE("%p (%p)\n", This, ppsai);
2470 if(This->psia_selection)
2472 *ppsai = This->psia_selection;
2473 IShellItemArray_AddRef(*ppsai);
2474 return S_OK;
2477 return E_FAIL;
2480 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2481 IFileOpenDialog_fnQueryInterface,
2482 IFileOpenDialog_fnAddRef,
2483 IFileOpenDialog_fnRelease,
2484 IFileOpenDialog_fnShow,
2485 IFileOpenDialog_fnSetFileTypes,
2486 IFileOpenDialog_fnSetFileTypeIndex,
2487 IFileOpenDialog_fnGetFileTypeIndex,
2488 IFileOpenDialog_fnAdvise,
2489 IFileOpenDialog_fnUnadvise,
2490 IFileOpenDialog_fnSetOptions,
2491 IFileOpenDialog_fnGetOptions,
2492 IFileOpenDialog_fnSetDefaultFolder,
2493 IFileOpenDialog_fnSetFolder,
2494 IFileOpenDialog_fnGetFolder,
2495 IFileOpenDialog_fnGetCurrentSelection,
2496 IFileOpenDialog_fnSetFileName,
2497 IFileOpenDialog_fnGetFileName,
2498 IFileOpenDialog_fnSetTitle,
2499 IFileOpenDialog_fnSetOkButtonLabel,
2500 IFileOpenDialog_fnSetFileNameLabel,
2501 IFileOpenDialog_fnGetResult,
2502 IFileOpenDialog_fnAddPlace,
2503 IFileOpenDialog_fnSetDefaultExtension,
2504 IFileOpenDialog_fnClose,
2505 IFileOpenDialog_fnSetClientGuid,
2506 IFileOpenDialog_fnClearClientData,
2507 IFileOpenDialog_fnSetFilter,
2508 IFileOpenDialog_fnGetResults,
2509 IFileOpenDialog_fnGetSelectedItems
2512 /**************************************************************************
2513 * IFileSaveDialog
2515 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
2517 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
2520 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
2521 REFIID riid,
2522 void **ppvObject)
2524 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2525 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2528 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
2530 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2531 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2534 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
2536 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2537 return IFileDialog2_Release(&This->IFileDialog2_iface);
2540 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
2542 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2543 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2546 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
2547 const COMDLG_FILTERSPEC *rgFilterSpec)
2549 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2550 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2553 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
2555 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2556 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2559 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
2561 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2562 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2565 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
2566 DWORD *pdwCookie)
2568 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2569 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2572 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
2574 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2575 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2578 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
2580 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2581 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2584 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2586 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2587 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2590 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
2592 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2593 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2596 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
2598 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2599 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2602 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
2604 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2605 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2608 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
2610 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2611 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2614 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
2616 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2617 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2620 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
2622 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2623 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2626 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
2628 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2629 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2632 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
2634 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2635 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2638 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
2640 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2641 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2644 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
2646 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2647 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2650 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
2652 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2653 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2656 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
2657 LPCWSTR pszDefaultExtension)
2659 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2660 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2663 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
2665 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2666 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2669 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
2671 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2672 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2675 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
2677 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2678 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2681 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
2683 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2684 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2687 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
2689 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2690 FIXME("stub - %p (%p)\n", This, psi);
2691 return E_NOTIMPL;
2694 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
2696 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2697 FIXME("stub - %p (%p)\n", This, pStore);
2698 return E_NOTIMPL;
2701 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
2702 IPropertyDescriptionList *pList,
2703 BOOL fAppendDefault)
2705 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2706 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
2707 return E_NOTIMPL;
2710 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
2712 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2713 FIXME("stub - %p (%p)\n", This, ppStore);
2714 return E_NOTIMPL;
2717 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
2718 IShellItem *psi,
2719 IPropertyStore *pStore,
2720 HWND hwnd,
2721 IFileOperationProgressSink *pSink)
2723 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2724 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
2725 return E_NOTIMPL;
2728 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
2729 IFileSaveDialog_fnQueryInterface,
2730 IFileSaveDialog_fnAddRef,
2731 IFileSaveDialog_fnRelease,
2732 IFileSaveDialog_fnShow,
2733 IFileSaveDialog_fnSetFileTypes,
2734 IFileSaveDialog_fnSetFileTypeIndex,
2735 IFileSaveDialog_fnGetFileTypeIndex,
2736 IFileSaveDialog_fnAdvise,
2737 IFileSaveDialog_fnUnadvise,
2738 IFileSaveDialog_fnSetOptions,
2739 IFileSaveDialog_fnGetOptions,
2740 IFileSaveDialog_fnSetDefaultFolder,
2741 IFileSaveDialog_fnSetFolder,
2742 IFileSaveDialog_fnGetFolder,
2743 IFileSaveDialog_fnGetCurrentSelection,
2744 IFileSaveDialog_fnSetFileName,
2745 IFileSaveDialog_fnGetFileName,
2746 IFileSaveDialog_fnSetTitle,
2747 IFileSaveDialog_fnSetOkButtonLabel,
2748 IFileSaveDialog_fnSetFileNameLabel,
2749 IFileSaveDialog_fnGetResult,
2750 IFileSaveDialog_fnAddPlace,
2751 IFileSaveDialog_fnSetDefaultExtension,
2752 IFileSaveDialog_fnClose,
2753 IFileSaveDialog_fnSetClientGuid,
2754 IFileSaveDialog_fnClearClientData,
2755 IFileSaveDialog_fnSetFilter,
2756 IFileSaveDialog_fnSetSaveAsItem,
2757 IFileSaveDialog_fnSetProperties,
2758 IFileSaveDialog_fnSetCollectedProperties,
2759 IFileSaveDialog_fnGetProperties,
2760 IFileSaveDialog_fnApplyProperties
2763 /**************************************************************************
2764 * IExplorerBrowserEvents implementation
2766 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
2768 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
2771 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
2772 REFIID riid, void **ppvObject)
2774 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2775 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2777 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2780 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
2782 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2783 TRACE("%p\n", This);
2784 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2787 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
2789 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2790 TRACE("%p\n", This);
2791 return IFileDialog2_Release(&This->IFileDialog2_iface);
2794 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
2795 PCIDLIST_ABSOLUTE pidlFolder)
2797 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2798 IShellItem *psi;
2799 HRESULT hr;
2800 TRACE("%p (%p)\n", This, pidlFolder);
2802 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
2803 if(SUCCEEDED(hr))
2805 hr = events_OnFolderChanging(This, psi);
2806 IShellItem_Release(psi);
2808 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
2809 if(hr == S_FALSE)
2810 hr = E_FAIL;
2812 return hr;
2814 else
2815 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
2817 return S_OK;
2820 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
2821 IShellView *psv)
2823 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2824 TRACE("%p (%p)\n", This, psv);
2825 return S_OK;
2828 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
2829 PCIDLIST_ABSOLUTE pidlFolder)
2831 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2832 HRESULT hr;
2833 TRACE("%p (%p)\n", This, pidlFolder);
2835 if(This->psi_folder)
2836 IShellItem_Release(This->psi_folder);
2838 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
2839 if(FAILED(hr))
2841 ERR("Failed to get the current folder.\n");
2842 This->psi_folder = NULL;
2845 events_OnFolderChange(This);
2847 return S_OK;
2850 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
2851 PCIDLIST_ABSOLUTE pidlFolder)
2853 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2854 TRACE("%p (%p)\n", This, pidlFolder);
2855 return S_OK;
2858 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
2859 IExplorerBrowserEvents_fnQueryInterface,
2860 IExplorerBrowserEvents_fnAddRef,
2861 IExplorerBrowserEvents_fnRelease,
2862 IExplorerBrowserEvents_fnOnNavigationPending,
2863 IExplorerBrowserEvents_fnOnViewCreated,
2864 IExplorerBrowserEvents_fnOnNavigationComplete,
2865 IExplorerBrowserEvents_fnOnNavigationFailed
2868 /**************************************************************************
2869 * IServiceProvider implementation
2871 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2873 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
2876 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
2877 REFIID riid, void **ppvObject)
2879 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2880 TRACE("%p\n", This);
2881 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2884 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
2886 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2887 TRACE("%p\n", This);
2888 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2891 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
2893 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2894 TRACE("%p\n", This);
2895 return IFileDialog2_Release(&This->IFileDialog2_iface);
2898 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
2899 REFGUID guidService,
2900 REFIID riid, void **ppv)
2902 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2903 HRESULT hr = E_NOTIMPL;
2904 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
2906 *ppv = NULL;
2907 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
2908 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
2909 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
2910 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
2911 else
2912 FIXME("Interface %s requested from unknown service %s\n",
2913 debugstr_guid(riid), debugstr_guid(guidService));
2915 return hr;
2918 static const IServiceProviderVtbl vt_IServiceProvider = {
2919 IServiceProvider_fnQueryInterface,
2920 IServiceProvider_fnAddRef,
2921 IServiceProvider_fnRelease,
2922 IServiceProvider_fnQueryService
2925 /**************************************************************************
2926 * ICommDlgBrowser3 implementation
2928 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
2930 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
2933 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
2934 REFIID riid, void **ppvObject)
2936 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2937 TRACE("%p\n", This);
2938 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2941 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
2943 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2944 TRACE("%p\n", This);
2945 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2948 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
2950 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2951 TRACE("%p\n", This);
2952 return IFileDialog2_Release(&This->IFileDialog2_iface);
2955 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
2956 IShellView *shv)
2958 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2959 HRESULT hr;
2960 TRACE("%p (%p)\n", This, shv);
2962 hr = on_default_action(This);
2964 if(SUCCEEDED(hr))
2965 EndDialog(This->dlg_hwnd, S_OK);
2967 return S_OK;
2970 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
2971 IShellView *shv, ULONG uChange )
2973 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2974 IDataObject *new_selection;
2975 HRESULT hr;
2976 TRACE("%p (%p, %x)\n", This, shv, uChange);
2978 switch(uChange)
2980 case CDBOSC_SELCHANGE:
2981 if(This->psia_selection)
2983 IShellItemArray_Release(This->psia_selection);
2984 This->psia_selection = NULL;
2987 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
2988 if(SUCCEEDED(hr))
2990 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
2991 (void**)&This->psia_selection);
2992 if(SUCCEEDED(hr))
2994 fill_filename_from_selection(This);
2995 events_OnSelectionChange(This);
2998 IDataObject_Release(new_selection);
3000 break;
3001 default:
3002 TRACE("Unhandled state change\n");
3004 return S_OK;
3007 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
3008 IShellView *shv, LPCITEMIDLIST pidl)
3010 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3011 IShellItem *psi;
3012 LPWSTR filename;
3013 LPITEMIDLIST parent_pidl;
3014 HRESULT hr;
3015 ULONG attr;
3016 TRACE("%p (%p, %p)\n", This, shv, pidl);
3018 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
3019 return S_OK;
3021 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3022 if(SUCCEEDED(hr))
3024 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3025 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3026 ILFree(parent_pidl);
3027 ILFree(full_pidl);
3029 if(FAILED(hr))
3031 ERR("Failed to get shellitem (%08x).\n", hr);
3032 return S_OK;
3035 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3036 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3038 IShellItem_Release(psi);
3039 return S_OK;
3042 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
3044 IShellItem_Release(psi);
3045 return S_FALSE;
3048 hr = S_OK;
3049 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
3051 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
3052 hr = S_FALSE;
3053 CoTaskMemFree(filename);
3056 IShellItem_Release(psi);
3057 return hr;
3060 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
3061 IShellView *ppshv, DWORD dwNotifyType)
3063 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3064 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
3065 return E_NOTIMPL;
3068 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
3069 IShellView *pshv,
3070 LPWSTR pszText, int cchMax)
3072 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3073 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
3074 return E_NOTIMPL;
3077 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
3079 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3080 FIXME("Stub: %p (%p)\n", This, pdwFlags);
3081 return E_NOTIMPL;
3084 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
3085 IShellView *pshv, int iColumn)
3087 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3088 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
3089 return E_NOTIMPL;
3092 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
3093 LPWSTR pszFileSpec, int cchFileSpec)
3095 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3096 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
3097 return E_NOTIMPL;
3100 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
3101 IShellView *pshv)
3103 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3104 FIXME("Stub: %p (%p)\n", This, pshv);
3105 return E_NOTIMPL;
3108 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
3109 ICommDlgBrowser3_fnQueryInterface,
3110 ICommDlgBrowser3_fnAddRef,
3111 ICommDlgBrowser3_fnRelease,
3112 ICommDlgBrowser3_fnOnDefaultCommand,
3113 ICommDlgBrowser3_fnOnStateChange,
3114 ICommDlgBrowser3_fnIncludeObject,
3115 ICommDlgBrowser3_fnNotify,
3116 ICommDlgBrowser3_fnGetDefaultMenuText,
3117 ICommDlgBrowser3_fnGetViewFlags,
3118 ICommDlgBrowser3_fnOnColumnClicked,
3119 ICommDlgBrowser3_fnGetCurrentFilter,
3120 ICommDlgBrowser3_fnOnPreviewCreated
3123 /**************************************************************************
3124 * IOleWindow implementation
3126 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
3128 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
3131 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
3133 FileDialogImpl *This = impl_from_IOleWindow(iface);
3134 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3137 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
3139 FileDialogImpl *This = impl_from_IOleWindow(iface);
3140 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3143 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
3145 FileDialogImpl *This = impl_from_IOleWindow(iface);
3146 return IFileDialog2_Release(&This->IFileDialog2_iface);
3149 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
3151 FileDialogImpl *This = impl_from_IOleWindow(iface);
3152 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
3153 return E_NOTIMPL;
3156 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
3158 FileDialogImpl *This = impl_from_IOleWindow(iface);
3159 TRACE("%p (%p)\n", This, phwnd);
3160 *phwnd = This->dlg_hwnd;
3161 return S_OK;
3164 static const IOleWindowVtbl vt_IOleWindow = {
3165 IOleWindow_fnQueryInterface,
3166 IOleWindow_fnAddRef,
3167 IOleWindow_fnRelease,
3168 IOleWindow_fnGetWindow,
3169 IOleWindow_fnContextSensitiveHelp
3172 /**************************************************************************
3173 * IFileDialogCustomize implementation
3175 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3177 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3180 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3181 REFIID riid, void **ppvObject)
3183 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3184 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3187 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3189 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3190 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3193 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3195 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3196 return IFileDialog2_Release(&This->IFileDialog2_iface);
3199 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3200 DWORD dwIDCtl)
3202 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3203 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3204 return E_NOTIMPL;
3207 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3208 DWORD dwIDCtl,
3209 LPCWSTR pszLabel)
3211 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3212 customctrl *ctrl;
3213 TBBUTTON tbb;
3214 HRESULT hr;
3215 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3217 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3218 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3219 This->cctrl_def_height, &ctrl);
3220 if(SUCCEEDED(hr))
3222 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3223 ctrl->type = IDLG_CCTRL_MENU;
3225 /* Add the actual button with a popup menu. */
3226 tbb.iBitmap = I_IMAGENONE;
3227 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3228 tbb.iString = (DWORD_PTR)pszLabel;
3229 tbb.fsState = TBSTATE_ENABLED;
3230 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3231 tbb.idCommand = 1;
3233 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3236 return hr;
3239 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3240 DWORD dwIDCtl,
3241 LPCWSTR pszLabel)
3243 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3244 customctrl *ctrl;
3245 HRESULT hr;
3246 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3248 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3249 This->cctrl_def_height, &ctrl);
3250 if(SUCCEEDED(hr))
3251 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3253 return hr;
3256 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3257 DWORD dwIDCtl)
3259 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3260 customctrl *ctrl;
3261 HRESULT hr;
3262 TRACE("%p (%d)\n", This, dwIDCtl);
3264 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3265 This->cctrl_def_height, &ctrl);
3266 if(SUCCEEDED(hr))
3267 ctrl->type = IDLG_CCTRL_COMBOBOX;
3269 return hr;
3272 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3273 DWORD dwIDCtl)
3275 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3276 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3277 return E_NOTIMPL;
3280 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3281 DWORD dwIDCtl,
3282 LPCWSTR pszLabel,
3283 BOOL bChecked)
3285 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3286 customctrl *ctrl;
3287 HRESULT hr;
3288 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3290 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0,
3291 This->cctrl_def_height, &ctrl);
3292 if(SUCCEEDED(hr))
3294 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3295 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3298 return hr;
3301 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3302 DWORD dwIDCtl,
3303 LPCWSTR pszText)
3305 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3306 customctrl *ctrl;
3307 HRESULT hr;
3308 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3310 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3311 This->cctrl_def_height, &ctrl);
3312 if(SUCCEEDED(hr))
3313 ctrl->type = IDLG_CCTRL_EDITBOX;
3315 return hr;
3318 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3319 DWORD dwIDCtl)
3321 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3322 customctrl *ctrl;
3323 HRESULT hr;
3324 TRACE("%p (%d)\n", This, dwIDCtl);
3326 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3327 GetSystemMetrics(SM_CYEDGE), &ctrl);
3328 if(SUCCEEDED(hr))
3329 ctrl->type = IDLG_CCTRL_SEPARATOR;
3331 return hr;
3334 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3335 DWORD dwIDCtl,
3336 LPCWSTR pszText)
3338 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3339 customctrl *ctrl;
3340 HRESULT hr;
3341 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3343 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3344 This->cctrl_def_height, &ctrl);
3345 if(SUCCEEDED(hr))
3346 ctrl->type = IDLG_CCTRL_TEXT;
3348 return hr;
3351 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3352 DWORD dwIDCtl,
3353 LPCWSTR pszLabel)
3355 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3356 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3357 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3359 if(!ctrl) return E_INVALIDARG;
3361 switch(ctrl->type)
3363 case IDLG_CCTRL_MENU:
3364 case IDLG_CCTRL_PUSHBUTTON:
3365 case IDLG_CCTRL_CHECKBUTTON:
3366 case IDLG_CCTRL_TEXT:
3367 case IDLG_CCTRL_VISUALGROUP:
3368 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3369 break;
3370 default:
3371 break;
3374 return S_OK;
3377 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3378 DWORD dwIDCtl,
3379 CDCONTROLSTATEF *pdwState)
3381 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3382 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3383 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3385 if(!ctrl) return E_NOTIMPL;
3387 *pdwState = ctrl->cdcstate;
3388 return S_OK;
3391 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3392 DWORD dwIDCtl,
3393 CDCONTROLSTATEF dwState)
3395 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3396 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3397 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3399 if(ctrl)
3401 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3403 if(dwState & CDCS_ENABLED)
3404 wndstyle &= ~(WS_DISABLED);
3405 else
3406 wndstyle |= WS_DISABLED;
3408 if(dwState & CDCS_VISIBLE)
3409 wndstyle |= WS_VISIBLE;
3410 else
3411 wndstyle &= ~(WS_VISIBLE);
3413 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3415 /* We save the state separately since at least one application
3416 * relies on being able to hide a control. */
3417 ctrl->cdcstate = dwState;
3420 return S_OK;
3423 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3424 DWORD dwIDCtl,
3425 WCHAR **ppszText)
3427 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3428 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3429 WCHAR len, *text;
3430 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
3432 if(!ctrl || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3433 return E_FAIL;
3435 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3436 if(!text) return E_FAIL;
3438 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3439 *ppszText = text;
3440 return S_OK;
3443 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
3444 DWORD dwIDCtl,
3445 LPCWSTR pszText)
3447 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3448 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3449 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
3451 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
3452 return E_FAIL;
3454 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
3455 return S_OK;
3458 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
3459 DWORD dwIDCtl,
3460 BOOL *pbChecked)
3462 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3463 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3464 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
3466 if(ctrl)
3467 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
3469 return S_OK;
3472 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
3473 DWORD dwIDCtl,
3474 BOOL bChecked)
3476 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3477 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3478 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
3480 if(ctrl)
3481 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
3483 return S_OK;
3486 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
3488 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
3489 UINT i;
3490 if(!count || (count == CB_ERR))
3491 return -1;
3493 for(i = 0; i < count; i++)
3494 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3495 return i;
3497 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
3498 return -1;
3501 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
3502 DWORD dwIDCtl,
3503 DWORD dwIDItem,
3504 LPCWSTR pszLabel)
3506 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3507 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3508 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3510 if(!ctrl) return E_FAIL;
3512 switch(ctrl->type)
3514 case IDLG_CCTRL_COMBOBOX:
3516 UINT index;
3518 if(get_combobox_index_from_id(ctrl->hwnd, dwIDItem) != -1)
3519 return E_INVALIDARG;
3521 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
3522 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
3524 return S_OK;
3526 case IDLG_CCTRL_MENU:
3528 TBBUTTON tbb;
3529 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3531 if(GetMenuState((HMENU)tbb.dwData, dwIDItem, MF_BYCOMMAND) != -1)
3532 return E_INVALIDARG;
3534 AppendMenuW((HMENU)tbb.dwData, MF_STRING, dwIDItem, pszLabel);
3535 return S_OK;
3537 default:
3538 break;
3541 return E_NOINTERFACE; /* win7 */
3544 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
3545 DWORD dwIDCtl,
3546 DWORD dwIDItem)
3548 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3549 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3550 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3552 if(!ctrl) return E_FAIL;
3554 switch(ctrl->type)
3556 case IDLG_CCTRL_COMBOBOX:
3558 UINT i, count = SendMessageW(ctrl->hwnd, CB_GETCOUNT, 0, 0);
3559 if(!count || (count == CB_ERR))
3560 return E_FAIL;
3562 for(i = 0; i < count; i++)
3563 if(SendMessageW(ctrl->hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3565 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, i, 0) == CB_ERR)
3566 return E_FAIL;
3567 return S_OK;
3570 return E_UNEXPECTED;
3572 case IDLG_CCTRL_MENU:
3574 TBBUTTON tbb;
3575 HMENU hmenu;
3576 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3577 hmenu = (HMENU)tbb.dwData;
3579 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
3580 return E_UNEXPECTED;
3582 return S_OK;
3584 default:
3585 break;
3588 return E_FAIL;
3591 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
3592 DWORD dwIDCtl)
3594 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3595 TRACE("%p (%d)\n", This, dwIDCtl);
3597 /* Not implemented by native */
3598 return E_NOTIMPL;
3601 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
3602 DWORD dwIDCtl,
3603 DWORD dwIDItem,
3604 CDCONTROLSTATEF *pdwState)
3606 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3607 FIXME("stub - %p\n", This);
3608 return E_NOTIMPL;
3611 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
3612 DWORD dwIDCtl,
3613 DWORD dwIDItem,
3614 CDCONTROLSTATEF dwState)
3616 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3617 FIXME("stub - %p\n", This);
3618 return E_NOTIMPL;
3621 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
3622 DWORD dwIDCtl,
3623 DWORD *pdwIDItem)
3625 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3626 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3627 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
3629 if(!ctrl) return E_FAIL;
3631 switch(ctrl->type)
3633 case IDLG_CCTRL_COMBOBOX:
3635 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
3636 if(index == CB_ERR)
3637 return E_FAIL;
3639 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
3640 return S_OK;
3642 default:
3643 FIXME("Unsupported control type %d\n", ctrl->type);
3646 return E_NOTIMPL;
3649 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
3650 DWORD dwIDCtl,
3651 DWORD dwIDItem)
3653 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3654 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3655 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3657 if(!ctrl) return E_INVALIDARG;
3659 switch(ctrl->type)
3661 case IDLG_CCTRL_COMBOBOX:
3663 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
3665 if(index == -1)
3666 return E_INVALIDARG;
3668 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
3669 return E_FAIL;
3671 return S_OK;
3673 default:
3674 FIXME("Unsupported control type %d\n", ctrl->type);
3677 return E_INVALIDARG;
3680 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
3681 DWORD dwIDCtl,
3682 LPCWSTR pszLabel)
3684 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3685 customctrl *vg;
3686 HRESULT hr;
3687 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
3689 if(This->cctrl_active_vg)
3690 return E_UNEXPECTED;
3692 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0,
3693 This->cctrl_def_height, &vg);
3694 if(SUCCEEDED(hr))
3696 vg->type = IDLG_CCTRL_VISUALGROUP;
3697 This->cctrl_active_vg = vg;
3700 return hr;
3703 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
3705 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3706 TRACE("%p\n", This);
3708 This->cctrl_active_vg = NULL;
3710 return S_OK;
3713 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
3714 DWORD dwIDCtl)
3716 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3717 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3718 return E_NOTIMPL;
3721 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
3722 DWORD dwIDCtl,
3723 DWORD dwIDItem,
3724 LPCWSTR pszLabel)
3726 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3727 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3728 return E_NOTIMPL;
3731 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
3732 IFileDialogCustomize_fnQueryInterface,
3733 IFileDialogCustomize_fnAddRef,
3734 IFileDialogCustomize_fnRelease,
3735 IFileDialogCustomize_fnEnableOpenDropDown,
3736 IFileDialogCustomize_fnAddMenu,
3737 IFileDialogCustomize_fnAddPushButton,
3738 IFileDialogCustomize_fnAddComboBox,
3739 IFileDialogCustomize_fnAddRadioButtonList,
3740 IFileDialogCustomize_fnAddCheckButton,
3741 IFileDialogCustomize_fnAddEditBox,
3742 IFileDialogCustomize_fnAddSeparator,
3743 IFileDialogCustomize_fnAddText,
3744 IFileDialogCustomize_fnSetControlLabel,
3745 IFileDialogCustomize_fnGetControlState,
3746 IFileDialogCustomize_fnSetControlState,
3747 IFileDialogCustomize_fnGetEditBoxText,
3748 IFileDialogCustomize_fnSetEditBoxText,
3749 IFileDialogCustomize_fnGetCheckButtonState,
3750 IFileDialogCustomize_fnSetCheckButtonState,
3751 IFileDialogCustomize_fnAddControlItem,
3752 IFileDialogCustomize_fnRemoveControlItem,
3753 IFileDialogCustomize_fnRemoveAllControlItems,
3754 IFileDialogCustomize_fnGetControlItemState,
3755 IFileDialogCustomize_fnSetControlItemState,
3756 IFileDialogCustomize_fnGetSelectedControlItem,
3757 IFileDialogCustomize_fnSetSelectedControlItem,
3758 IFileDialogCustomize_fnStartVisualGroup,
3759 IFileDialogCustomize_fnEndVisualGroup,
3760 IFileDialogCustomize_fnMakeProminent,
3761 IFileDialogCustomize_fnSetControlItemText
3764 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
3766 FileDialogImpl *fdimpl;
3767 HRESULT hr;
3768 IShellFolder *psf;
3769 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
3771 if(!ppv)
3772 return E_POINTER;
3773 if(pUnkOuter)
3774 return CLASS_E_NOAGGREGATION;
3776 fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
3777 if(!fdimpl)
3778 return E_OUTOFMEMORY;
3780 fdimpl->ref = 1;
3781 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
3782 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
3783 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
3784 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
3785 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
3786 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
3788 if(type == ITEMDLG_TYPE_OPEN)
3790 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
3791 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
3792 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
3793 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
3795 else
3797 WCHAR buf[16];
3798 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
3799 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
3800 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
3802 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
3803 fdimpl->custom_title = StrDupW(buf);
3804 fdimpl->custom_okbutton = StrDupW(buf);
3807 fdimpl->filterspecs = NULL;
3808 fdimpl->filterspec_count = 0;
3809 fdimpl->filetypeindex = 0;
3811 fdimpl->psia_selection = fdimpl->psia_results = NULL;
3812 fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
3814 list_init(&fdimpl->events_clients);
3815 fdimpl->events_next_cookie = 0;
3817 fdimpl->dlg_hwnd = NULL;
3818 fdimpl->peb = NULL;
3820 fdimpl->set_filename = NULL;
3821 fdimpl->default_ext = NULL;
3822 fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL;
3824 fdimpl->client_guid = GUID_NULL;
3826 /* FIXME: The default folder setting should be restored for the
3827 * application if it was previously set. */
3828 SHGetDesktopFolder(&psf);
3829 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
3830 IShellFolder_Release(psf);
3832 hr = init_custom_controls(fdimpl);
3833 if(FAILED(hr))
3835 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
3836 IUnknown_Release((IUnknown*)fdimpl);
3837 return E_FAIL;
3840 hr = IUnknown_QueryInterface((IUnknown*)fdimpl, riid, ppv);
3841 IUnknown_Release((IUnknown*)fdimpl);
3842 return hr;
3845 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3847 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
3850 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3852 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);