comdlg32: Set BS_MULTILINE also for check buttons.
[wine/multimedia.git] / dlls / comdlg32 / itemdlg.c
blob04264889a0e7abc798c261dde9a2b78aa1a7f1a5
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 UINT i;
1539 for(i = 0; i < This->filterspec_count; i++)
1540 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
1542 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
1544 else
1545 ShowWindow(hitem, SW_HIDE);
1547 if(This->set_filename &&
1548 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1549 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
1551 ctrl_container_reparent(This, This->dlg_hwnd);
1552 init_explorerbrowser(This);
1553 init_toolbar(This, hwnd);
1554 update_control_text(This);
1555 update_layout(This);
1557 if(This->filterspec_count)
1558 events_OnTypeChange(This);
1560 return TRUE;
1563 static LRESULT on_wm_size(FileDialogImpl *This)
1565 update_layout(This);
1566 return FALSE;
1569 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
1571 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
1572 TRACE("%p (%p)\n", This, mmi);
1574 /* FIXME */
1575 mmi->ptMinTrackSize.x = 640;
1576 mmi->ptMinTrackSize.y = 480;
1578 return FALSE;
1581 static LRESULT on_wm_destroy(FileDialogImpl *This)
1583 TRACE("%p\n", This);
1585 if(This->peb)
1587 IExplorerBrowser_Destroy(This->peb);
1588 IExplorerBrowser_Release(This->peb);
1589 This->peb = NULL;
1592 ctrl_container_reparent(This, NULL);
1593 This->dlg_hwnd = NULL;
1595 return TRUE;
1598 static LRESULT on_idok(FileDialogImpl *This)
1600 TRACE("%p\n", This);
1602 if(SUCCEEDED(on_default_action(This)))
1603 EndDialog(This->dlg_hwnd, S_OK);
1605 return FALSE;
1608 static LRESULT on_idcancel(FileDialogImpl *This)
1610 TRACE("%p\n", This);
1612 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
1614 return FALSE;
1617 static LRESULT on_browse_back(FileDialogImpl *This)
1619 TRACE("%p\n", This);
1620 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
1621 return FALSE;
1624 static LRESULT on_browse_forward(FileDialogImpl *This)
1626 TRACE("%p\n", This);
1627 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
1628 return FALSE;
1631 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1633 if(HIWORD(wparam) == CBN_SELCHANGE)
1635 IShellView *psv;
1636 HRESULT hr;
1637 LPWSTR filename;
1638 UINT prev_index = This->filetypeindex;
1640 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
1641 TRACE("File type selection changed to %d.\n", This->filetypeindex);
1643 if(prev_index == This->filetypeindex)
1644 return FALSE;
1646 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
1647 if(SUCCEEDED(hr))
1649 IShellView_Refresh(psv);
1650 IShellView_Release(psv);
1653 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
1655 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
1657 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
1658 if(ext)
1660 lstrcpyW(buf, filename);
1662 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
1663 PathRemoveExtensionW(buf);
1665 lstrcatW(buf, ext);
1666 set_file_name(This, buf);
1668 CoTaskMemFree(filename);
1671 /* The documentation claims that OnTypeChange is called only
1672 * when the dialog is opened, but this is obviously not the
1673 * case. */
1674 events_OnTypeChange(This);
1677 return FALSE;
1680 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1682 switch(LOWORD(wparam))
1684 case IDOK: return on_idok(This);
1685 case IDCANCEL: return on_idcancel(This);
1686 case IDC_NAVBACK: return on_browse_back(This);
1687 case IDC_NAVFORWARD: return on_browse_forward(This);
1688 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
1689 default: TRACE("Unknown command.\n");
1691 return FALSE;
1694 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1696 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1698 switch(umessage)
1700 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
1701 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
1702 case WM_SIZE: return on_wm_size(This);
1703 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
1704 case WM_DESTROY: return on_wm_destroy(This);
1707 return FALSE;
1710 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
1712 INT_PTR res;
1714 SetLastError(0);
1715 res = DialogBoxParamW(COMDLG32_hInstance,
1716 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
1717 parent, itemdlg_dlgproc, (LPARAM)This);
1718 This->dlg_hwnd = NULL;
1719 if(res == -1)
1721 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
1722 return E_FAIL;
1725 TRACE("Returning 0x%08x\n", (HRESULT)res);
1726 return (HRESULT)res;
1729 /**************************************************************************
1730 * IFileDialog implementation
1732 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
1734 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
1737 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
1738 REFIID riid,
1739 void **ppvObject)
1741 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1742 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1744 *ppvObject = NULL;
1745 if(IsEqualGUID(riid, &IID_IUnknown) ||
1746 IsEqualGUID(riid, &IID_IFileDialog) ||
1747 IsEqualGUID(riid, &IID_IFileDialog2))
1749 *ppvObject = iface;
1751 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
1753 *ppvObject = &This->u.IFileOpenDialog_iface;
1755 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
1757 *ppvObject = &This->u.IFileSaveDialog_iface;
1759 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
1761 *ppvObject = &This->IExplorerBrowserEvents_iface;
1763 else if(IsEqualGUID(riid, &IID_IServiceProvider))
1765 *ppvObject = &This->IServiceProvider_iface;
1767 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
1768 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
1769 IsEqualGUID(&IID_ICommDlgBrowser, riid))
1771 *ppvObject = &This->ICommDlgBrowser3_iface;
1773 else if(IsEqualGUID(&IID_IOleWindow, riid))
1775 *ppvObject = &This->IOleWindow_iface;
1777 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
1778 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
1780 *ppvObject = &This->IFileDialogCustomize_iface;
1782 else
1783 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
1785 if(*ppvObject)
1787 IUnknown_AddRef((IUnknown*)*ppvObject);
1788 return S_OK;
1791 return E_NOINTERFACE;
1794 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
1796 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1797 LONG ref = InterlockedIncrement(&This->ref);
1798 TRACE("%p - ref %d\n", This, ref);
1800 return ref;
1803 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
1805 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1806 LONG ref = InterlockedDecrement(&This->ref);
1807 TRACE("%p - ref %d\n", This, ref);
1809 if(!ref)
1811 UINT i;
1812 for(i = 0; i < This->filterspec_count; i++)
1814 LocalFree((void*)This->filterspecs[i].pszName);
1815 LocalFree((void*)This->filterspecs[i].pszSpec);
1817 HeapFree(GetProcessHeap(), 0, This->filterspecs);
1819 DestroyWindow(This->cctrls_hwnd);
1821 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
1822 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
1823 if(This->psi_folder) IShellItem_Release(This->psi_folder);
1824 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
1825 if(This->psia_results) IShellItemArray_Release(This->psia_results);
1827 LocalFree(This->set_filename);
1828 LocalFree(This->default_ext);
1829 LocalFree(This->custom_title);
1830 LocalFree(This->custom_okbutton);
1831 LocalFree(This->custom_cancelbutton);
1832 LocalFree(This->custom_filenamelabel);
1834 HeapFree(GetProcessHeap(), 0, This);
1837 return ref;
1840 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
1842 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1843 TRACE("%p (%p)\n", iface, hwndOwner);
1845 return create_dialog(This, hwndOwner);
1848 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
1849 const COMDLG_FILTERSPEC *rgFilterSpec)
1851 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1852 UINT i;
1853 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
1855 if(This->filterspecs)
1856 return E_UNEXPECTED;
1858 if(!rgFilterSpec)
1859 return E_INVALIDARG;
1861 if(!cFileTypes)
1862 return S_OK;
1864 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
1865 for(i = 0; i < cFileTypes; i++)
1867 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
1868 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
1870 This->filterspec_count = cFileTypes;
1872 return S_OK;
1875 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
1877 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1878 TRACE("%p (%d)\n", This, iFileType);
1880 if(!This->filterspecs)
1881 return E_FAIL;
1883 iFileType = max(iFileType, 1);
1884 iFileType = min(iFileType, This->filterspec_count);
1885 This->filetypeindex = iFileType-1;
1887 return S_OK;
1890 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
1892 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1893 TRACE("%p (%p)\n", This, piFileType);
1895 if(!piFileType)
1896 return E_INVALIDARG;
1898 if(This->filterspec_count == 0)
1899 *piFileType = 0;
1900 else
1901 *piFileType = This->filetypeindex + 1;
1903 return S_OK;
1906 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
1908 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1909 events_client *client;
1910 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
1912 if(!pfde || !pdwCookie)
1913 return E_INVALIDARG;
1915 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
1916 client->pfde = pfde;
1917 client->cookie = ++This->events_next_cookie;
1919 IFileDialogEvents_AddRef(pfde);
1920 *pdwCookie = client->cookie;
1922 list_add_tail(&This->events_clients, &client->entry);
1924 return S_OK;
1927 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
1929 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1930 events_client *client, *found = NULL;
1931 TRACE("%p (%d)\n", This, dwCookie);
1933 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
1935 if(client->cookie == dwCookie)
1937 found = client;
1938 break;
1942 if(found)
1944 list_remove(&found->entry);
1945 IFileDialogEvents_Release(found->pfde);
1946 HeapFree(GetProcessHeap(), 0, found);
1947 return S_OK;
1950 return E_INVALIDARG;
1953 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
1955 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1956 TRACE("%p (0x%x)\n", This, fos);
1958 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
1960 WCHAR buf[30];
1961 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, sizeof(buf)/sizeof(WCHAR));
1962 IFileDialog2_SetTitle(iface, buf);
1965 This->options = fos;
1967 return S_OK;
1970 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
1972 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1973 TRACE("%p (%p)\n", This, pfos);
1975 if(!pfos)
1976 return E_INVALIDARG;
1978 *pfos = This->options;
1980 return S_OK;
1983 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
1985 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1986 TRACE("%p (%p)\n", This, psi);
1987 if(This->psi_defaultfolder)
1988 IShellItem_Release(This->psi_defaultfolder);
1990 This->psi_defaultfolder = psi;
1992 if(This->psi_defaultfolder)
1993 IShellItem_AddRef(This->psi_defaultfolder);
1995 return S_OK;
1998 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
2000 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2001 TRACE("%p (%p)\n", This, psi);
2002 if(This->psi_setfolder)
2003 IShellItem_Release(This->psi_setfolder);
2005 This->psi_setfolder = psi;
2007 if(This->psi_setfolder)
2008 IShellItem_AddRef(This->psi_setfolder);
2010 return S_OK;
2013 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
2015 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2016 TRACE("%p (%p)\n", This, ppsi);
2017 if(!ppsi)
2018 return E_INVALIDARG;
2020 /* FIXME:
2021 If the dialog is shown, return the current(ly selected) folder. */
2023 *ppsi = NULL;
2024 if(This->psi_folder)
2025 *ppsi = This->psi_folder;
2026 else if(This->psi_setfolder)
2027 *ppsi = This->psi_setfolder;
2028 else if(This->psi_defaultfolder)
2029 *ppsi = This->psi_defaultfolder;
2031 if(*ppsi)
2033 IShellItem_AddRef(*ppsi);
2034 return S_OK;
2037 return E_FAIL;
2040 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
2042 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2043 HRESULT hr;
2044 TRACE("%p (%p)\n", This, ppsi);
2046 if(!ppsi)
2047 return E_INVALIDARG;
2049 if(This->psia_selection)
2051 /* FIXME: Check filename edit box */
2052 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2053 return hr;
2056 return E_FAIL;
2059 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
2061 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2062 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2064 set_file_name(This, pszName);
2066 return S_OK;
2069 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
2071 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2072 TRACE("%p (%p)\n", iface, pszName);
2074 if(!pszName)
2075 return E_INVALIDARG;
2077 *pszName = NULL;
2078 if(get_file_name(This, pszName))
2079 return S_OK;
2080 else
2081 return E_FAIL;
2084 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
2086 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2087 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2089 LocalFree(This->custom_title);
2090 This->custom_title = StrDupW(pszTitle);
2091 update_control_text(This);
2093 return S_OK;
2096 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
2098 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2099 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2101 LocalFree(This->custom_okbutton);
2102 This->custom_okbutton = StrDupW(pszText);
2103 update_control_text(This);
2104 update_layout(This);
2106 return S_OK;
2109 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2111 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2112 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2114 LocalFree(This->custom_filenamelabel);
2115 This->custom_filenamelabel = StrDupW(pszLabel);
2116 update_control_text(This);
2117 update_layout(This);
2119 return S_OK;
2122 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
2124 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2125 HRESULT hr;
2126 TRACE("%p (%p)\n", This, ppsi);
2128 if(!ppsi)
2129 return E_INVALIDARG;
2131 if(This->psia_results)
2133 UINT item_count;
2134 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2135 if(SUCCEEDED(hr))
2137 if(item_count != 1)
2138 return E_FAIL;
2140 /* Adds a reference. */
2141 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2144 return hr;
2147 return E_UNEXPECTED;
2150 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2152 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2153 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2154 return E_NOTIMPL;
2157 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2159 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2160 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2162 LocalFree(This->default_ext);
2163 This->default_ext = StrDupW(pszDefaultExtension);
2165 return S_OK;
2168 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2170 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2171 TRACE("%p (0x%08x)\n", This, hr);
2173 if(This->dlg_hwnd)
2174 EndDialog(This->dlg_hwnd, hr);
2176 return S_OK;
2179 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2181 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2182 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2183 This->client_guid = *guid;
2184 return S_OK;
2187 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2189 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2190 FIXME("stub - %p\n", This);
2191 return E_NOTIMPL;
2194 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2196 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2197 FIXME("stub - %p (%p)\n", This, pFilter);
2198 return E_NOTIMPL;
2201 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2203 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2204 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2206 LocalFree(This->custom_cancelbutton);
2207 This->custom_cancelbutton = StrDupW(pszLabel);
2208 update_control_text(This);
2209 update_layout(This);
2211 return S_OK;
2214 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2216 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2217 FIXME("stub - %p (%p)\n", This, psi);
2218 return E_NOTIMPL;
2221 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2222 IFileDialog2_fnQueryInterface,
2223 IFileDialog2_fnAddRef,
2224 IFileDialog2_fnRelease,
2225 IFileDialog2_fnShow,
2226 IFileDialog2_fnSetFileTypes,
2227 IFileDialog2_fnSetFileTypeIndex,
2228 IFileDialog2_fnGetFileTypeIndex,
2229 IFileDialog2_fnAdvise,
2230 IFileDialog2_fnUnadvise,
2231 IFileDialog2_fnSetOptions,
2232 IFileDialog2_fnGetOptions,
2233 IFileDialog2_fnSetDefaultFolder,
2234 IFileDialog2_fnSetFolder,
2235 IFileDialog2_fnGetFolder,
2236 IFileDialog2_fnGetCurrentSelection,
2237 IFileDialog2_fnSetFileName,
2238 IFileDialog2_fnGetFileName,
2239 IFileDialog2_fnSetTitle,
2240 IFileDialog2_fnSetOkButtonLabel,
2241 IFileDialog2_fnSetFileNameLabel,
2242 IFileDialog2_fnGetResult,
2243 IFileDialog2_fnAddPlace,
2244 IFileDialog2_fnSetDefaultExtension,
2245 IFileDialog2_fnClose,
2246 IFileDialog2_fnSetClientGuid,
2247 IFileDialog2_fnClearClientData,
2248 IFileDialog2_fnSetFilter,
2249 IFileDialog2_fnSetCancelButtonLabel,
2250 IFileDialog2_fnSetNavigationRoot
2253 /**************************************************************************
2254 * IFileOpenDialog
2256 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2258 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2261 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2262 REFIID riid, void **ppvObject)
2264 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2265 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2268 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2270 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2271 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2274 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2276 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2277 return IFileDialog2_Release(&This->IFileDialog2_iface);
2280 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2282 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2283 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2286 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2287 const COMDLG_FILTERSPEC *rgFilterSpec)
2289 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2290 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2293 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2295 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2296 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2299 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2301 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2302 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2305 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2306 DWORD *pdwCookie)
2308 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2309 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2312 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2314 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2315 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2318 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2320 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2321 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2324 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2326 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2327 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2330 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2332 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2333 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2336 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2338 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2339 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2342 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2344 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2345 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2348 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2350 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2351 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2354 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2356 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2357 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2360 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2362 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2363 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2366 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2368 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2369 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2372 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2374 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2375 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2378 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2380 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2381 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2384 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2386 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2387 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2390 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2392 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2393 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2396 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2397 LPCWSTR pszDefaultExtension)
2399 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2400 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2403 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2405 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2406 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2409 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2411 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2412 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2415 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2417 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2418 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2421 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2423 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2424 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2427 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2429 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2430 TRACE("%p (%p)\n", This, ppenum);
2432 *ppenum = This->psia_results;
2434 if(*ppenum)
2436 IShellItemArray_AddRef(*ppenum);
2437 return S_OK;
2440 return E_FAIL;
2443 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2445 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2446 TRACE("%p (%p)\n", This, ppsai);
2448 if(This->psia_selection)
2450 *ppsai = This->psia_selection;
2451 IShellItemArray_AddRef(*ppsai);
2452 return S_OK;
2455 return E_FAIL;
2458 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2459 IFileOpenDialog_fnQueryInterface,
2460 IFileOpenDialog_fnAddRef,
2461 IFileOpenDialog_fnRelease,
2462 IFileOpenDialog_fnShow,
2463 IFileOpenDialog_fnSetFileTypes,
2464 IFileOpenDialog_fnSetFileTypeIndex,
2465 IFileOpenDialog_fnGetFileTypeIndex,
2466 IFileOpenDialog_fnAdvise,
2467 IFileOpenDialog_fnUnadvise,
2468 IFileOpenDialog_fnSetOptions,
2469 IFileOpenDialog_fnGetOptions,
2470 IFileOpenDialog_fnSetDefaultFolder,
2471 IFileOpenDialog_fnSetFolder,
2472 IFileOpenDialog_fnGetFolder,
2473 IFileOpenDialog_fnGetCurrentSelection,
2474 IFileOpenDialog_fnSetFileName,
2475 IFileOpenDialog_fnGetFileName,
2476 IFileOpenDialog_fnSetTitle,
2477 IFileOpenDialog_fnSetOkButtonLabel,
2478 IFileOpenDialog_fnSetFileNameLabel,
2479 IFileOpenDialog_fnGetResult,
2480 IFileOpenDialog_fnAddPlace,
2481 IFileOpenDialog_fnSetDefaultExtension,
2482 IFileOpenDialog_fnClose,
2483 IFileOpenDialog_fnSetClientGuid,
2484 IFileOpenDialog_fnClearClientData,
2485 IFileOpenDialog_fnSetFilter,
2486 IFileOpenDialog_fnGetResults,
2487 IFileOpenDialog_fnGetSelectedItems
2490 /**************************************************************************
2491 * IFileSaveDialog
2493 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
2495 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
2498 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
2499 REFIID riid,
2500 void **ppvObject)
2502 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2503 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2506 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
2508 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2509 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2512 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
2514 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2515 return IFileDialog2_Release(&This->IFileDialog2_iface);
2518 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
2520 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2521 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2524 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
2525 const COMDLG_FILTERSPEC *rgFilterSpec)
2527 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2528 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2531 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
2533 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2534 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2537 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
2539 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2540 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2543 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
2544 DWORD *pdwCookie)
2546 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2547 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2550 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
2552 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2553 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2556 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
2558 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2559 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2562 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2564 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2565 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2568 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
2570 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2571 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2574 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
2576 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2577 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2580 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
2582 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2583 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2586 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
2588 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2589 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2592 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
2594 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2595 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2598 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
2600 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2601 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2604 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
2606 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2607 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2610 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
2612 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2613 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2616 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
2618 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2619 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2622 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
2624 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2625 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2628 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
2630 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2631 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2634 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
2635 LPCWSTR pszDefaultExtension)
2637 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2638 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2641 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
2643 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2644 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2647 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
2649 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2650 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2653 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
2655 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2656 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2659 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
2661 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2662 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2665 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
2667 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2668 FIXME("stub - %p (%p)\n", This, psi);
2669 return E_NOTIMPL;
2672 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
2674 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2675 FIXME("stub - %p (%p)\n", This, pStore);
2676 return E_NOTIMPL;
2679 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
2680 IPropertyDescriptionList *pList,
2681 BOOL fAppendDefault)
2683 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2684 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
2685 return E_NOTIMPL;
2688 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
2690 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2691 FIXME("stub - %p (%p)\n", This, ppStore);
2692 return E_NOTIMPL;
2695 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
2696 IShellItem *psi,
2697 IPropertyStore *pStore,
2698 HWND hwnd,
2699 IFileOperationProgressSink *pSink)
2701 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2702 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
2703 return E_NOTIMPL;
2706 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
2707 IFileSaveDialog_fnQueryInterface,
2708 IFileSaveDialog_fnAddRef,
2709 IFileSaveDialog_fnRelease,
2710 IFileSaveDialog_fnShow,
2711 IFileSaveDialog_fnSetFileTypes,
2712 IFileSaveDialog_fnSetFileTypeIndex,
2713 IFileSaveDialog_fnGetFileTypeIndex,
2714 IFileSaveDialog_fnAdvise,
2715 IFileSaveDialog_fnUnadvise,
2716 IFileSaveDialog_fnSetOptions,
2717 IFileSaveDialog_fnGetOptions,
2718 IFileSaveDialog_fnSetDefaultFolder,
2719 IFileSaveDialog_fnSetFolder,
2720 IFileSaveDialog_fnGetFolder,
2721 IFileSaveDialog_fnGetCurrentSelection,
2722 IFileSaveDialog_fnSetFileName,
2723 IFileSaveDialog_fnGetFileName,
2724 IFileSaveDialog_fnSetTitle,
2725 IFileSaveDialog_fnSetOkButtonLabel,
2726 IFileSaveDialog_fnSetFileNameLabel,
2727 IFileSaveDialog_fnGetResult,
2728 IFileSaveDialog_fnAddPlace,
2729 IFileSaveDialog_fnSetDefaultExtension,
2730 IFileSaveDialog_fnClose,
2731 IFileSaveDialog_fnSetClientGuid,
2732 IFileSaveDialog_fnClearClientData,
2733 IFileSaveDialog_fnSetFilter,
2734 IFileSaveDialog_fnSetSaveAsItem,
2735 IFileSaveDialog_fnSetProperties,
2736 IFileSaveDialog_fnSetCollectedProperties,
2737 IFileSaveDialog_fnGetProperties,
2738 IFileSaveDialog_fnApplyProperties
2741 /**************************************************************************
2742 * IExplorerBrowserEvents implementation
2744 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
2746 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
2749 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
2750 REFIID riid, void **ppvObject)
2752 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2753 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2755 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2758 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
2760 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2761 TRACE("%p\n", This);
2762 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2765 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
2767 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2768 TRACE("%p\n", This);
2769 return IFileDialog2_Release(&This->IFileDialog2_iface);
2772 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
2773 PCIDLIST_ABSOLUTE pidlFolder)
2775 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2776 IShellItem *psi;
2777 HRESULT hr;
2778 TRACE("%p (%p)\n", This, pidlFolder);
2780 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
2781 if(SUCCEEDED(hr))
2783 hr = events_OnFolderChanging(This, psi);
2784 IShellItem_Release(psi);
2786 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
2787 if(hr == S_FALSE)
2788 hr = E_FAIL;
2790 return hr;
2792 else
2793 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
2795 return S_OK;
2798 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
2799 IShellView *psv)
2801 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2802 TRACE("%p (%p)\n", This, psv);
2803 return S_OK;
2806 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
2807 PCIDLIST_ABSOLUTE pidlFolder)
2809 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2810 HRESULT hr;
2811 TRACE("%p (%p)\n", This, pidlFolder);
2813 if(This->psi_folder)
2814 IShellItem_Release(This->psi_folder);
2816 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
2817 if(FAILED(hr))
2819 ERR("Failed to get the current folder.\n");
2820 This->psi_folder = NULL;
2823 events_OnFolderChange(This);
2825 return S_OK;
2828 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
2829 PCIDLIST_ABSOLUTE pidlFolder)
2831 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2832 TRACE("%p (%p)\n", This, pidlFolder);
2833 return S_OK;
2836 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
2837 IExplorerBrowserEvents_fnQueryInterface,
2838 IExplorerBrowserEvents_fnAddRef,
2839 IExplorerBrowserEvents_fnRelease,
2840 IExplorerBrowserEvents_fnOnNavigationPending,
2841 IExplorerBrowserEvents_fnOnViewCreated,
2842 IExplorerBrowserEvents_fnOnNavigationComplete,
2843 IExplorerBrowserEvents_fnOnNavigationFailed
2846 /**************************************************************************
2847 * IServiceProvider implementation
2849 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2851 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
2854 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
2855 REFIID riid, void **ppvObject)
2857 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2858 TRACE("%p\n", This);
2859 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2862 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
2864 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2865 TRACE("%p\n", This);
2866 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2869 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
2871 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2872 TRACE("%p\n", This);
2873 return IFileDialog2_Release(&This->IFileDialog2_iface);
2876 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
2877 REFGUID guidService,
2878 REFIID riid, void **ppv)
2880 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2881 HRESULT hr = E_NOTIMPL;
2882 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
2884 *ppv = NULL;
2885 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
2886 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
2887 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
2888 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
2889 else
2890 FIXME("Interface %s requested from unknown service %s\n",
2891 debugstr_guid(riid), debugstr_guid(guidService));
2893 return hr;
2896 static const IServiceProviderVtbl vt_IServiceProvider = {
2897 IServiceProvider_fnQueryInterface,
2898 IServiceProvider_fnAddRef,
2899 IServiceProvider_fnRelease,
2900 IServiceProvider_fnQueryService
2903 /**************************************************************************
2904 * ICommDlgBrowser3 implementation
2906 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
2908 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
2911 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
2912 REFIID riid, void **ppvObject)
2914 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2915 TRACE("%p\n", This);
2916 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2919 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
2921 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2922 TRACE("%p\n", This);
2923 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2926 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
2928 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2929 TRACE("%p\n", This);
2930 return IFileDialog2_Release(&This->IFileDialog2_iface);
2933 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
2934 IShellView *shv)
2936 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2937 HRESULT hr;
2938 TRACE("%p (%p)\n", This, shv);
2940 hr = on_default_action(This);
2942 if(SUCCEEDED(hr))
2943 EndDialog(This->dlg_hwnd, S_OK);
2945 return S_OK;
2948 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
2949 IShellView *shv, ULONG uChange )
2951 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2952 IDataObject *new_selection;
2953 HRESULT hr;
2954 TRACE("%p (%p, %x)\n", This, shv, uChange);
2956 switch(uChange)
2958 case CDBOSC_SELCHANGE:
2959 if(This->psia_selection)
2961 IShellItemArray_Release(This->psia_selection);
2962 This->psia_selection = NULL;
2965 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
2966 if(SUCCEEDED(hr))
2968 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
2969 (void**)&This->psia_selection);
2970 if(SUCCEEDED(hr))
2972 fill_filename_from_selection(This);
2973 events_OnSelectionChange(This);
2976 IDataObject_Release(new_selection);
2978 break;
2979 default:
2980 TRACE("Unhandled state change\n");
2982 return S_OK;
2985 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
2986 IShellView *shv, LPCITEMIDLIST pidl)
2988 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2989 IShellItem *psi;
2990 LPWSTR filename;
2991 LPITEMIDLIST parent_pidl;
2992 HRESULT hr;
2993 ULONG attr;
2994 TRACE("%p (%p, %p)\n", This, shv, pidl);
2996 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
2997 return S_OK;
2999 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3000 if(SUCCEEDED(hr))
3002 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3003 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3004 ILFree(parent_pidl);
3005 ILFree(full_pidl);
3007 if(FAILED(hr))
3009 ERR("Failed to get shellitem (%08x).\n", hr);
3010 return S_OK;
3013 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3014 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3016 IShellItem_Release(psi);
3017 return S_OK;
3020 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
3022 IShellItem_Release(psi);
3023 return S_FALSE;
3026 hr = S_OK;
3027 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
3029 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
3030 hr = S_FALSE;
3031 CoTaskMemFree(filename);
3034 IShellItem_Release(psi);
3035 return hr;
3038 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
3039 IShellView *ppshv, DWORD dwNotifyType)
3041 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3042 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
3043 return E_NOTIMPL;
3046 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
3047 IShellView *pshv,
3048 LPWSTR pszText, int cchMax)
3050 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3051 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
3052 return E_NOTIMPL;
3055 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
3057 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3058 FIXME("Stub: %p (%p)\n", This, pdwFlags);
3059 return E_NOTIMPL;
3062 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
3063 IShellView *pshv, int iColumn)
3065 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3066 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
3067 return E_NOTIMPL;
3070 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
3071 LPWSTR pszFileSpec, int cchFileSpec)
3073 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3074 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
3075 return E_NOTIMPL;
3078 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
3079 IShellView *pshv)
3081 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3082 FIXME("Stub: %p (%p)\n", This, pshv);
3083 return E_NOTIMPL;
3086 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
3087 ICommDlgBrowser3_fnQueryInterface,
3088 ICommDlgBrowser3_fnAddRef,
3089 ICommDlgBrowser3_fnRelease,
3090 ICommDlgBrowser3_fnOnDefaultCommand,
3091 ICommDlgBrowser3_fnOnStateChange,
3092 ICommDlgBrowser3_fnIncludeObject,
3093 ICommDlgBrowser3_fnNotify,
3094 ICommDlgBrowser3_fnGetDefaultMenuText,
3095 ICommDlgBrowser3_fnGetViewFlags,
3096 ICommDlgBrowser3_fnOnColumnClicked,
3097 ICommDlgBrowser3_fnGetCurrentFilter,
3098 ICommDlgBrowser3_fnOnPreviewCreated
3101 /**************************************************************************
3102 * IOleWindow implementation
3104 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
3106 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
3109 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
3111 FileDialogImpl *This = impl_from_IOleWindow(iface);
3112 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3115 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
3117 FileDialogImpl *This = impl_from_IOleWindow(iface);
3118 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3121 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
3123 FileDialogImpl *This = impl_from_IOleWindow(iface);
3124 return IFileDialog2_Release(&This->IFileDialog2_iface);
3127 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
3129 FileDialogImpl *This = impl_from_IOleWindow(iface);
3130 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
3131 return E_NOTIMPL;
3134 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
3136 FileDialogImpl *This = impl_from_IOleWindow(iface);
3137 TRACE("%p (%p)\n", This, phwnd);
3138 *phwnd = This->dlg_hwnd;
3139 return S_OK;
3142 static const IOleWindowVtbl vt_IOleWindow = {
3143 IOleWindow_fnQueryInterface,
3144 IOleWindow_fnAddRef,
3145 IOleWindow_fnRelease,
3146 IOleWindow_fnGetWindow,
3147 IOleWindow_fnContextSensitiveHelp
3150 /**************************************************************************
3151 * IFileDialogCustomize implementation
3153 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3155 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3158 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3159 REFIID riid, void **ppvObject)
3161 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3162 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3165 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3167 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3168 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3171 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3173 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3174 return IFileDialog2_Release(&This->IFileDialog2_iface);
3177 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3178 DWORD dwIDCtl)
3180 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3181 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3182 return E_NOTIMPL;
3185 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3186 DWORD dwIDCtl,
3187 LPCWSTR pszLabel)
3189 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3190 customctrl *ctrl;
3191 TBBUTTON tbb;
3192 HRESULT hr;
3193 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3195 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3196 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3197 This->cctrl_def_height, &ctrl);
3198 if(SUCCEEDED(hr))
3200 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3201 ctrl->type = IDLG_CCTRL_MENU;
3203 /* Add the actual button with a popup menu. */
3204 tbb.iBitmap = I_IMAGENONE;
3205 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3206 tbb.iString = (DWORD_PTR)pszLabel;
3207 tbb.fsState = TBSTATE_ENABLED;
3208 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3209 tbb.idCommand = 1;
3211 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3214 return hr;
3217 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3218 DWORD dwIDCtl,
3219 LPCWSTR pszLabel)
3221 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3222 customctrl *ctrl;
3223 HRESULT hr;
3224 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3226 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3227 This->cctrl_def_height, &ctrl);
3228 if(SUCCEEDED(hr))
3229 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3231 return hr;
3234 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3235 DWORD dwIDCtl)
3237 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3238 customctrl *ctrl;
3239 HRESULT hr;
3240 TRACE("%p (%d)\n", This, dwIDCtl);
3242 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3243 This->cctrl_def_height, &ctrl);
3244 if(SUCCEEDED(hr))
3245 ctrl->type = IDLG_CCTRL_COMBOBOX;
3247 return hr;
3250 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3251 DWORD dwIDCtl)
3253 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3254 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3255 return E_NOTIMPL;
3258 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3259 DWORD dwIDCtl,
3260 LPCWSTR pszLabel,
3261 BOOL bChecked)
3263 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3264 customctrl *ctrl;
3265 HRESULT hr;
3266 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3268 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0,
3269 This->cctrl_def_height, &ctrl);
3270 if(SUCCEEDED(hr))
3272 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3273 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3276 return hr;
3279 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3280 DWORD dwIDCtl,
3281 LPCWSTR pszText)
3283 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3284 customctrl *ctrl;
3285 HRESULT hr;
3286 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3288 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3289 This->cctrl_def_height, &ctrl);
3290 if(SUCCEEDED(hr))
3291 ctrl->type = IDLG_CCTRL_EDITBOX;
3293 return hr;
3296 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3297 DWORD dwIDCtl)
3299 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3300 customctrl *ctrl;
3301 HRESULT hr;
3302 TRACE("%p (%d)\n", This, dwIDCtl);
3304 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3305 GetSystemMetrics(SM_CYEDGE), &ctrl);
3306 if(SUCCEEDED(hr))
3307 ctrl->type = IDLG_CCTRL_SEPARATOR;
3309 return hr;
3312 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3313 DWORD dwIDCtl,
3314 LPCWSTR pszText)
3316 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3317 customctrl *ctrl;
3318 HRESULT hr;
3319 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3321 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3322 This->cctrl_def_height, &ctrl);
3323 if(SUCCEEDED(hr))
3324 ctrl->type = IDLG_CCTRL_TEXT;
3326 return hr;
3329 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3330 DWORD dwIDCtl,
3331 LPCWSTR pszLabel)
3333 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3334 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3335 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3337 if(!ctrl) return E_INVALIDARG;
3339 switch(ctrl->type)
3341 case IDLG_CCTRL_MENU:
3342 case IDLG_CCTRL_PUSHBUTTON:
3343 case IDLG_CCTRL_CHECKBUTTON:
3344 case IDLG_CCTRL_TEXT:
3345 case IDLG_CCTRL_VISUALGROUP:
3346 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3347 break;
3348 default:
3349 break;
3352 return S_OK;
3355 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3356 DWORD dwIDCtl,
3357 CDCONTROLSTATEF *pdwState)
3359 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3360 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3361 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3363 if(!ctrl) return E_NOTIMPL;
3365 *pdwState = ctrl->cdcstate;
3366 return S_OK;
3369 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3370 DWORD dwIDCtl,
3371 CDCONTROLSTATEF dwState)
3373 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3374 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3375 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3377 if(ctrl)
3379 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3381 if(dwState & CDCS_ENABLED)
3382 wndstyle &= ~(WS_DISABLED);
3383 else
3384 wndstyle |= WS_DISABLED;
3386 if(dwState & CDCS_VISIBLE)
3387 wndstyle |= WS_VISIBLE;
3388 else
3389 wndstyle &= ~(WS_VISIBLE);
3391 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3393 /* We save the state separately since at least one application
3394 * relies on being able to hide a control. */
3395 ctrl->cdcstate = dwState;
3398 return S_OK;
3401 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3402 DWORD dwIDCtl,
3403 WCHAR **ppszText)
3405 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3406 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3407 WCHAR len, *text;
3408 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
3410 if(!ctrl || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3411 return E_FAIL;
3413 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3414 if(!text) return E_FAIL;
3416 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3417 *ppszText = text;
3418 return S_OK;
3421 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
3422 DWORD dwIDCtl,
3423 LPCWSTR pszText)
3425 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3426 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3427 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
3429 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
3430 return E_FAIL;
3432 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
3433 return S_OK;
3436 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
3437 DWORD dwIDCtl,
3438 BOOL *pbChecked)
3440 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3441 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3442 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
3444 if(ctrl)
3445 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
3447 return S_OK;
3450 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
3451 DWORD dwIDCtl,
3452 BOOL bChecked)
3454 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3455 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3456 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
3458 if(ctrl)
3459 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
3461 return S_OK;
3464 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
3466 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
3467 UINT i;
3468 if(!count || (count == CB_ERR))
3469 return -1;
3471 for(i = 0; i < count; i++)
3472 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3473 return i;
3475 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
3476 return -1;
3479 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
3480 DWORD dwIDCtl,
3481 DWORD dwIDItem,
3482 LPCWSTR pszLabel)
3484 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3485 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3486 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3488 if(!ctrl) return E_FAIL;
3490 switch(ctrl->type)
3492 case IDLG_CCTRL_COMBOBOX:
3494 UINT index;
3496 if(get_combobox_index_from_id(ctrl->hwnd, dwIDItem) != -1)
3497 return E_INVALIDARG;
3499 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
3500 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
3502 return S_OK;
3504 case IDLG_CCTRL_MENU:
3506 TBBUTTON tbb;
3507 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3509 if(GetMenuState((HMENU)tbb.dwData, dwIDItem, MF_BYCOMMAND) != -1)
3510 return E_INVALIDARG;
3512 AppendMenuW((HMENU)tbb.dwData, MF_STRING, dwIDItem, pszLabel);
3513 return S_OK;
3515 default:
3516 break;
3519 return E_NOINTERFACE; /* win7 */
3522 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
3523 DWORD dwIDCtl,
3524 DWORD dwIDItem)
3526 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3527 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3528 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3530 if(!ctrl) return E_FAIL;
3532 switch(ctrl->type)
3534 case IDLG_CCTRL_COMBOBOX:
3536 UINT i, count = SendMessageW(ctrl->hwnd, CB_GETCOUNT, 0, 0);
3537 if(!count || (count == CB_ERR))
3538 return E_FAIL;
3540 for(i = 0; i < count; i++)
3541 if(SendMessageW(ctrl->hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3543 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, i, 0) == CB_ERR)
3544 return E_FAIL;
3545 return S_OK;
3548 return E_UNEXPECTED;
3550 case IDLG_CCTRL_MENU:
3552 TBBUTTON tbb;
3553 HMENU hmenu;
3554 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3555 hmenu = (HMENU)tbb.dwData;
3557 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
3558 return E_UNEXPECTED;
3560 return S_OK;
3562 default:
3563 break;
3566 return E_FAIL;
3569 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
3570 DWORD dwIDCtl)
3572 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3573 TRACE("%p (%d)\n", This, dwIDCtl);
3575 /* Not implemented by native */
3576 return E_NOTIMPL;
3579 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
3580 DWORD dwIDCtl,
3581 DWORD dwIDItem,
3582 CDCONTROLSTATEF *pdwState)
3584 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3585 FIXME("stub - %p\n", This);
3586 return E_NOTIMPL;
3589 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
3590 DWORD dwIDCtl,
3591 DWORD dwIDItem,
3592 CDCONTROLSTATEF dwState)
3594 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3595 FIXME("stub - %p\n", This);
3596 return E_NOTIMPL;
3599 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
3600 DWORD dwIDCtl,
3601 DWORD *pdwIDItem)
3603 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3604 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3605 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
3607 if(!ctrl) return E_FAIL;
3609 switch(ctrl->type)
3611 case IDLG_CCTRL_COMBOBOX:
3613 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
3614 if(index == CB_ERR)
3615 return E_FAIL;
3617 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
3618 return S_OK;
3620 default:
3621 FIXME("Unsupported control type %d\n", ctrl->type);
3624 return E_NOTIMPL;
3627 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
3628 DWORD dwIDCtl,
3629 DWORD dwIDItem)
3631 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3632 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3633 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3635 if(!ctrl) return E_INVALIDARG;
3637 switch(ctrl->type)
3639 case IDLG_CCTRL_COMBOBOX:
3641 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
3643 if(index == -1)
3644 return E_INVALIDARG;
3646 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
3647 return E_FAIL;
3649 return S_OK;
3651 default:
3652 FIXME("Unsupported control type %d\n", ctrl->type);
3655 return E_INVALIDARG;
3658 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
3659 DWORD dwIDCtl,
3660 LPCWSTR pszLabel)
3662 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3663 customctrl *vg;
3664 HRESULT hr;
3665 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
3667 if(This->cctrl_active_vg)
3668 return E_UNEXPECTED;
3670 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0,
3671 This->cctrl_def_height, &vg);
3672 if(SUCCEEDED(hr))
3674 vg->type = IDLG_CCTRL_VISUALGROUP;
3675 This->cctrl_active_vg = vg;
3678 return hr;
3681 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
3683 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3684 TRACE("%p\n", This);
3686 This->cctrl_active_vg = NULL;
3688 return S_OK;
3691 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
3692 DWORD dwIDCtl)
3694 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3695 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3696 return E_NOTIMPL;
3699 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
3700 DWORD dwIDCtl,
3701 DWORD dwIDItem,
3702 LPCWSTR pszLabel)
3704 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3705 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3706 return E_NOTIMPL;
3709 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
3710 IFileDialogCustomize_fnQueryInterface,
3711 IFileDialogCustomize_fnAddRef,
3712 IFileDialogCustomize_fnRelease,
3713 IFileDialogCustomize_fnEnableOpenDropDown,
3714 IFileDialogCustomize_fnAddMenu,
3715 IFileDialogCustomize_fnAddPushButton,
3716 IFileDialogCustomize_fnAddComboBox,
3717 IFileDialogCustomize_fnAddRadioButtonList,
3718 IFileDialogCustomize_fnAddCheckButton,
3719 IFileDialogCustomize_fnAddEditBox,
3720 IFileDialogCustomize_fnAddSeparator,
3721 IFileDialogCustomize_fnAddText,
3722 IFileDialogCustomize_fnSetControlLabel,
3723 IFileDialogCustomize_fnGetControlState,
3724 IFileDialogCustomize_fnSetControlState,
3725 IFileDialogCustomize_fnGetEditBoxText,
3726 IFileDialogCustomize_fnSetEditBoxText,
3727 IFileDialogCustomize_fnGetCheckButtonState,
3728 IFileDialogCustomize_fnSetCheckButtonState,
3729 IFileDialogCustomize_fnAddControlItem,
3730 IFileDialogCustomize_fnRemoveControlItem,
3731 IFileDialogCustomize_fnRemoveAllControlItems,
3732 IFileDialogCustomize_fnGetControlItemState,
3733 IFileDialogCustomize_fnSetControlItemState,
3734 IFileDialogCustomize_fnGetSelectedControlItem,
3735 IFileDialogCustomize_fnSetSelectedControlItem,
3736 IFileDialogCustomize_fnStartVisualGroup,
3737 IFileDialogCustomize_fnEndVisualGroup,
3738 IFileDialogCustomize_fnMakeProminent,
3739 IFileDialogCustomize_fnSetControlItemText
3742 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
3744 FileDialogImpl *fdimpl;
3745 HRESULT hr;
3746 IShellFolder *psf;
3747 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
3749 if(!ppv)
3750 return E_POINTER;
3751 if(pUnkOuter)
3752 return CLASS_E_NOAGGREGATION;
3754 fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
3755 if(!fdimpl)
3756 return E_OUTOFMEMORY;
3758 fdimpl->ref = 1;
3759 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
3760 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
3761 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
3762 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
3763 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
3764 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
3766 if(type == ITEMDLG_TYPE_OPEN)
3768 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
3769 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
3770 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
3771 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
3773 else
3775 WCHAR buf[16];
3776 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
3777 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
3778 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
3780 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
3781 fdimpl->custom_title = StrDupW(buf);
3782 fdimpl->custom_okbutton = StrDupW(buf);
3785 fdimpl->filterspecs = NULL;
3786 fdimpl->filterspec_count = 0;
3787 fdimpl->filetypeindex = 0;
3789 fdimpl->psia_selection = fdimpl->psia_results = NULL;
3790 fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
3792 list_init(&fdimpl->events_clients);
3793 fdimpl->events_next_cookie = 0;
3795 fdimpl->dlg_hwnd = NULL;
3796 fdimpl->peb = NULL;
3798 fdimpl->set_filename = NULL;
3799 fdimpl->default_ext = NULL;
3800 fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL;
3802 fdimpl->client_guid = GUID_NULL;
3804 /* FIXME: The default folder setting should be restored for the
3805 * application if it was previously set. */
3806 SHGetDesktopFolder(&psf);
3807 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
3808 IShellFolder_Release(psf);
3810 hr = init_custom_controls(fdimpl);
3811 if(FAILED(hr))
3813 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
3814 IUnknown_Release((IUnknown*)fdimpl);
3815 return E_FAIL;
3818 hr = IUnknown_QueryInterface((IUnknown*)fdimpl, riid, ppv);
3819 IUnknown_Release((IUnknown*)fdimpl);
3820 return hr;
3823 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3825 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
3828 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3830 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);