msvcirt: Add implementation of streambuf::sputbackc.
[wine.git] / dlls / comdlg32 / itemdlg.c
blobb5093b87b9b862d0f2fca75c130771a27f397977
1 /*
2 * Common Item Dialog
4 * Copyright 2010,2011 David Hedberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "wingdi.h"
30 #include "winreg.h"
31 #include "shlwapi.h"
33 #include "commdlg.h"
34 #include "cdlg.h"
35 #include "filedlgbrowser.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
40 #define IDC_NAV_TOOLBAR 200
41 #define IDC_NAVBACK 201
42 #define IDC_NAVFORWARD 202
44 #include <initguid.h>
45 /* This seems to be another version of IID_IFileDialogCustomize. If
46 * there is any difference I have yet to find it. */
47 DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F);
49 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
51 static const WCHAR notifysink_childW[] = {'n','f','s','_','c','h','i','l','d',0};
52 static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0};
54 enum ITEMDLG_TYPE {
55 ITEMDLG_TYPE_OPEN,
56 ITEMDLG_TYPE_SAVE
59 enum ITEMDLG_CCTRL_TYPE {
60 IDLG_CCTRL_MENU,
61 IDLG_CCTRL_PUSHBUTTON,
62 IDLG_CCTRL_COMBOBOX,
63 IDLG_CCTRL_RADIOBUTTONLIST,
64 IDLG_CCTRL_CHECKBUTTON,
65 IDLG_CCTRL_EDITBOX,
66 IDLG_CCTRL_SEPARATOR,
67 IDLG_CCTRL_TEXT,
68 IDLG_CCTRL_VISUALGROUP
71 typedef struct {
72 HWND hwnd, wrapper_hwnd;
73 UINT id, dlgid;
74 enum ITEMDLG_CCTRL_TYPE type;
75 CDCONTROLSTATEF cdcstate;
76 struct list entry;
78 struct list sub_cctrls;
79 struct list sub_cctrls_entry;
80 } customctrl;
82 typedef struct {
83 struct list entry;
84 IFileDialogEvents *pfde;
85 DWORD cookie;
86 } events_client;
88 typedef struct FileDialogImpl {
89 IFileDialog2 IFileDialog2_iface;
90 union {
91 IFileOpenDialog IFileOpenDialog_iface;
92 IFileSaveDialog IFileSaveDialog_iface;
93 } u;
94 enum ITEMDLG_TYPE dlg_type;
95 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
96 IServiceProvider IServiceProvider_iface;
97 ICommDlgBrowser3 ICommDlgBrowser3_iface;
98 IOleWindow IOleWindow_iface;
99 IFileDialogCustomize IFileDialogCustomize_iface;
100 LONG ref;
102 FILEOPENDIALOGOPTIONS options;
103 COMDLG_FILTERSPEC *filterspecs;
104 UINT filterspec_count;
105 UINT filetypeindex;
107 struct list events_clients;
108 DWORD events_next_cookie;
110 IShellItemArray *psia_selection;
111 IShellItemArray *psia_results;
112 IShellItem *psi_defaultfolder;
113 IShellItem *psi_setfolder;
114 IShellItem *psi_folder;
116 HWND dlg_hwnd;
117 IExplorerBrowser *peb;
118 DWORD ebevents_cookie;
120 LPWSTR set_filename;
121 LPWSTR default_ext;
122 LPWSTR custom_title;
123 LPWSTR custom_okbutton;
124 LPWSTR custom_cancelbutton;
125 LPWSTR custom_filenamelabel;
127 UINT cctrl_width, cctrl_def_height, cctrls_cols;
128 UINT cctrl_indent;
129 HWND cctrls_hwnd;
130 struct list cctrls;
131 UINT_PTR cctrl_next_dlgid;
132 customctrl *cctrl_active_vg;
134 GUID client_guid;
135 } FileDialogImpl;
137 /**************************************************************************
138 * Event wrappers.
140 static HRESULT events_OnFileOk(FileDialogImpl *This)
142 events_client *cursor;
143 HRESULT hr = S_OK;
144 TRACE("%p\n", This);
146 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
148 TRACE("Notifying %p\n", cursor);
149 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
150 if(FAILED(hr) && hr != E_NOTIMPL)
151 break;
154 if(hr == E_NOTIMPL)
155 hr = S_OK;
157 return hr;
160 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
162 events_client *cursor;
163 HRESULT hr = S_OK;
164 TRACE("%p (%p)\n", This, folder);
166 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
168 TRACE("Notifying %p\n", cursor);
169 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
170 if(FAILED(hr) && hr != E_NOTIMPL)
171 break;
174 if(hr == E_NOTIMPL)
175 hr = S_OK;
177 return hr;
180 static void events_OnFolderChange(FileDialogImpl *This)
182 events_client *cursor;
183 TRACE("%p\n", This);
185 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
187 TRACE("Notifying %p\n", cursor);
188 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
192 static void events_OnSelectionChange(FileDialogImpl *This)
194 events_client *cursor;
195 TRACE("%p\n", This);
197 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
199 TRACE("Notifying %p\n", cursor);
200 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
204 static void events_OnTypeChange(FileDialogImpl *This)
206 events_client *cursor;
207 TRACE("%p\n", This);
209 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
211 TRACE("Notifying %p\n", cursor);
212 IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
216 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
218 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
221 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
223 events_client *cursor;
224 TRACE("%p\n", This);
226 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
228 IFileDialogControlEvents *pfdce;
229 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
231 TRACE("Notifying %p\n", cursor);
232 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
233 IFileDialogControlEvents_Release(pfdce);
237 return S_OK;
240 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
242 events_client *cursor;
243 TRACE("%p\n", This);
245 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
247 IFileDialogControlEvents *pfdce;
248 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
250 TRACE("Notifying %p\n", cursor);
251 IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
252 IFileDialogControlEvents_Release(pfdce);
256 return S_OK;
259 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
261 events_client *cursor;
262 TRACE("%p\n", This);
264 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
266 IFileDialogControlEvents *pfdce;
267 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
269 TRACE("Notifying %p\n", cursor);
270 IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
271 IFileDialogControlEvents_Release(pfdce);
275 return S_OK;
278 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
279 DWORD ctl_id)
281 events_client *cursor;
282 TRACE("%p\n", This);
284 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
286 IFileDialogControlEvents *pfdce;
287 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
289 TRACE("Notifying %p\n", cursor);
290 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
291 IFileDialogControlEvents_Release(pfdce);
295 return S_OK;
298 /**************************************************************************
299 * Helper functions.
301 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
303 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
304 UINT len;
306 if(!hwnd_edit)
308 if(This->set_filename)
310 len = lstrlenW(This->set_filename);
311 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
312 lstrcpyW(*str, This->set_filename);
313 return len;
315 return FALSE;
318 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
319 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
320 if(!*str)
321 return FALSE;
323 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
324 return len;
327 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
329 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
331 if(This->set_filename)
332 LocalFree(This->set_filename);
334 This->set_filename = StrDupW(str);
336 return SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str);
339 static void fill_filename_from_selection(FileDialogImpl *This)
341 IShellItem *psi;
342 LPWSTR *names;
343 HRESULT hr;
344 UINT item_count, valid_count;
345 UINT len_total, i;
347 if(!This->psia_selection)
348 return;
350 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
351 if(FAILED(hr) || !item_count)
352 return;
354 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
356 /* Get names of the selected items */
357 valid_count = 0; len_total = 0;
358 for(i = 0; i < item_count; i++)
360 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
361 if(SUCCEEDED(hr))
363 UINT attr;
365 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
366 if(SUCCEEDED(hr) &&
367 (( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
368 (!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
369 continue;
371 hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
372 if(SUCCEEDED(hr))
374 len_total += lstrlenW(names[valid_count]) + 3;
375 valid_count++;
377 IShellItem_Release(psi);
381 if(valid_count == 1)
383 set_file_name(This, names[0]);
384 CoTaskMemFree(names[0]);
386 else if(valid_count > 1)
388 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
389 LPWSTR cur_point = string;
391 for(i = 0; i < valid_count; i++)
393 LPWSTR file = names[i];
394 *cur_point++ = '\"';
395 lstrcpyW(cur_point, file);
396 cur_point += lstrlenW(file);
397 *cur_point++ = '\"';
398 *cur_point++ = ' ';
399 CoTaskMemFree(file);
401 *(cur_point-1) = '\0';
403 set_file_name(This, string);
404 HeapFree(GetProcessHeap(), 0, string);
407 HeapFree(GetProcessHeap(), 0, names);
408 return;
411 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
413 WCHAR *endpos, *ext;
415 lstrcpyW(buf, spec);
416 if( (endpos = StrChrW(buf, ';')) )
417 *endpos = '\0';
419 ext = PathFindExtensionW(buf);
420 if(StrChrW(ext, '*'))
421 return NULL;
423 return ext;
426 static HRESULT on_default_action(FileDialogImpl *This)
428 IShellFolder *psf_parent, *psf_desktop;
429 LPITEMIDLIST *pidla;
430 LPITEMIDLIST current_folder;
431 LPWSTR fn_iter, files = NULL, tmp_files;
432 UINT file_count = 0, len, i;
433 int open_action;
434 HRESULT hr, ret = E_FAIL;
436 len = get_file_name(This, &tmp_files);
437 if(len)
439 UINT size_used;
440 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
441 CoTaskMemFree(tmp_files);
443 if(!file_count) return E_FAIL;
445 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
446 if(FAILED(hr))
448 ERR("Failed to get pidl for current directory.\n");
449 HeapFree(GetProcessHeap(), 0, files);
450 return hr;
453 TRACE("Acting on %d file(s).\n", file_count);
455 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
456 open_action = ONOPEN_OPEN;
457 fn_iter = files;
459 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
461 WCHAR canon_filename[MAX_PATH];
462 psf_parent = NULL;
464 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
466 if( (This->options & FOS_NOVALIDATE) &&
467 !(This->options & FOS_FILEMUSTEXIST) )
468 open_action = ONOPEN_OPEN;
469 else
470 open_action = ONOPEN_BROWSE;
472 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
473 This->options & ~FOS_FILEMUSTEXIST,
474 (This->dlg_type == ITEMDLG_TYPE_SAVE),
475 open_action);
477 /* Add the proper extension */
478 if(open_action == ONOPEN_OPEN)
480 static const WCHAR dotW[] = {'.',0};
482 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
484 WCHAR extbuf[MAX_PATH], *newext = NULL;
486 if(This->filterspec_count)
488 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
490 else if(This->default_ext)
492 lstrcpyW(extbuf, dotW);
493 lstrcatW(extbuf, This->default_ext);
494 newext = extbuf;
497 if(newext)
499 WCHAR *ext = PathFindExtensionW(canon_filename);
500 if(lstrcmpW(ext, newext))
501 lstrcatW(canon_filename, newext);
504 else
506 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
507 !PathFileExistsW(canon_filename))
509 if(This->default_ext)
511 lstrcatW(canon_filename, dotW);
512 lstrcatW(canon_filename, This->default_ext);
514 if(!PathFileExistsW(canon_filename))
516 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
517 open_action = ONOPEN_BROWSE;
520 else
522 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
523 open_action = ONOPEN_BROWSE;
529 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
531 if(psf_parent && !(open_action == ONOPEN_BROWSE))
532 IShellFolder_Release(psf_parent);
534 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
537 HeapFree(GetProcessHeap(), 0, files);
538 ILFree(current_folder);
540 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
541 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
543 switch(open_action)
545 case ONOPEN_SEARCH:
546 FIXME("Filtering not implemented.\n");
547 break;
549 case ONOPEN_BROWSE:
550 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
551 if(FAILED(hr))
552 ERR("Failed to browse to directory: %08x\n", hr);
554 IShellFolder_Release(psf_parent);
555 break;
557 case ONOPEN_OPEN:
558 hr = SHGetDesktopFolder(&psf_desktop);
559 if(SUCCEEDED(hr))
561 if(This->psia_results)
563 IShellItemArray_Release(This->psia_results);
564 This->psia_results = NULL;
567 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
568 &This->psia_results);
570 IShellFolder_Release(psf_desktop);
572 if(FAILED(hr))
573 break;
575 if(This->options & FOS_PICKFOLDERS)
577 SFGAOF attributes;
578 hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
579 if(hr != S_OK)
581 WCHAR buf[64];
582 LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, sizeof(buf)/sizeof(WCHAR));
584 MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
586 IShellItemArray_Release(This->psia_results);
587 This->psia_results = NULL;
588 break;
592 if(events_OnFileOk(This) == S_OK)
593 ret = S_OK;
595 break;
597 default:
598 ERR("Failed.\n");
599 break;
602 /* Clean up */
603 for(i = 0; i < file_count; i++)
604 ILFree(pidla[i]);
605 HeapFree(GetProcessHeap(), 0, pidla);
607 /* Success closes the dialog */
608 return ret;
611 /**************************************************************************
612 * Control functions.
614 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
616 customctrl *ctrl, *sub_ctrl;
618 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
620 if(ctrl->dlgid == dlgid)
621 return ctrl;
623 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
624 if(sub_ctrl->dlgid == dlgid)
625 return sub_ctrl;
628 ERR("Failed to find control with dialog id %d\n", dlgid);
629 return NULL;
632 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
634 customctrl *ctrl, *sub_ctrl;
636 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
638 if(ctrl->id == ctlid)
639 return ctrl;
641 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
642 if(sub_ctrl->id == ctlid)
643 return sub_ctrl;
647 TRACE("No existing control with control id %d\n", ctlid);
648 return NULL;
651 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
653 LPWSTR text;
654 UINT len, final_width;
655 UINT lines, final_height;
656 SIZE size;
657 RECT rc;
658 HDC hdc;
659 WCHAR *c;
661 TRACE("\n");
663 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
664 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
665 if(!text) return;
666 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
668 hdc = GetDC(hctrl);
669 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
670 ReleaseDC(hctrl, hdc);
672 if(len && multiline)
674 /* FIXME: line-wrap */
675 for(lines = 1, c = text; *c != '\0'; c++)
676 if(*c == '\n') lines++;
678 final_height = size.cy*lines + 2*4;
680 else
682 GetWindowRect(hctrl, &rc);
683 final_height = rc.bottom - rc.top;
686 final_width = min(max(size.cx, min_width) + 4, max_width);
687 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
688 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
690 HeapFree(GetProcessHeap(), 0, text);
693 static UINT ctrl_get_height(customctrl *ctrl) {
694 RECT rc;
695 GetWindowRect(ctrl->wrapper_hwnd, &rc);
696 return rc.bottom - rc.top;
699 static void ctrl_free(customctrl *ctrl)
701 customctrl *sub_cur1, *sub_cur2;
703 TRACE("Freeing control %p\n", ctrl);
704 if(ctrl->type == IDLG_CCTRL_MENU)
706 TBBUTTON tbb;
707 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
708 DestroyMenu((HMENU)tbb.dwData);
711 LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
713 list_remove(&sub_cur1->sub_cctrls_entry);
714 ctrl_free(sub_cur1);
717 DestroyWindow(ctrl->hwnd);
718 HeapFree(GetProcessHeap(), 0, ctrl);
721 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
723 RECT rc;
724 UINT total_height;
725 customctrl *sub_ctrl;
727 switch(ctrl->type)
729 case IDLG_CCTRL_PUSHBUTTON:
730 case IDLG_CCTRL_COMBOBOX:
731 case IDLG_CCTRL_CHECKBUTTON:
732 case IDLG_CCTRL_TEXT:
733 ctrl_resize(ctrl->hwnd, 160, 160, TRUE);
734 GetWindowRect(ctrl->hwnd, &rc);
735 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
736 SWP_NOZORDER|SWP_NOMOVE);
737 break;
738 case IDLG_CCTRL_VISUALGROUP:
739 total_height = 0;
740 ctrl_resize(ctrl->hwnd, 0, This->cctrl_indent, TRUE);
742 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
744 customctrl_resize(This, sub_ctrl);
745 SetWindowPos(sub_ctrl->wrapper_hwnd, NULL, This->cctrl_indent, total_height, 0, 0,
746 SWP_NOZORDER|SWP_NOSIZE);
748 total_height += ctrl_get_height(sub_ctrl);
751 /* The label should be right adjusted */
753 UINT width, height;
755 GetWindowRect(ctrl->hwnd, &rc);
756 width = rc.right - rc.left;
757 height = rc.bottom - rc.top;
759 SetWindowPos(ctrl->hwnd, NULL, This->cctrl_indent - width, 0, width, height, SWP_NOZORDER);
762 /* Resize the wrapper window to fit all the sub controls */
763 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, This->cctrl_width + This->cctrl_indent, total_height,
764 SWP_NOZORDER|SWP_NOMOVE);
765 break;
766 case IDLG_CCTRL_RADIOBUTTONLIST:
767 case IDLG_CCTRL_EDITBOX:
768 case IDLG_CCTRL_SEPARATOR:
769 case IDLG_CCTRL_MENU:
770 /* Nothing */
771 break;
775 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
777 FileDialogImpl *This = crs->lpCreateParams;
778 TRACE("%p\n", This);
780 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
781 return TRUE;
784 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
786 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
788 TRACE("%p, %lx\n", This, wparam);
790 if(ctrl)
792 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
794 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
795 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
797 else
798 cctrl_event_OnButtonClicked(This, ctrl->id);
801 return TRUE;
804 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
806 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
807 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
809 if(ctrl)
811 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
812 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
814 cctrl_event_OnItemSelected(This, ctrl->id, selid);
816 return TRUE;
819 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
821 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
822 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
823 POINT pt = { 0, nmtb->rcButton.bottom };
824 TBBUTTON tbb;
825 UINT idcmd;
827 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
829 if(ctrl)
831 cctrl_event_OnControlActivating(This,ctrl->id);
833 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
834 ClientToScreen(ctrl->hwnd, &pt);
835 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
836 if(idcmd)
837 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
840 return TBDDRET_DEFAULT;
843 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
845 switch(HIWORD(wparam))
847 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
848 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
851 return FALSE;
854 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
856 NMHDR *nmhdr = (NMHDR*)lparam;
858 switch(nmhdr->code)
860 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
863 return FALSE;
866 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
868 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
869 customctrl *ctrl;
870 HWND hwnd_child;
871 RECT rc;
873 switch(message)
875 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
876 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
877 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
878 case WM_SIZE:
879 hwnd_child = GetPropW(hwnd, notifysink_childW);
880 ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA);
881 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
883 GetClientRect(hwnd, &rc);
884 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
886 return TRUE;
889 return DefWindowProcW(hwnd, message, wparam, lparam);
892 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
893 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
894 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
896 HWND ns_hwnd, control_hwnd, parent_hwnd;
897 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
898 customctrl *ctrl;
900 if(get_cctrl(This, id))
901 return E_UNEXPECTED; /* Duplicate id */
903 if(This->cctrl_active_vg)
904 parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
905 else
906 parent_hwnd = This->cctrls_hwnd;
908 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
909 0, 0, This->cctrl_width, height, parent_hwnd,
910 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
911 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
912 0, 0, This->cctrl_width, height, ns_hwnd,
913 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
915 if(!ns_hwnd || !control_hwnd)
917 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
918 DestroyWindow(ns_hwnd);
919 DestroyWindow(control_hwnd);
921 return E_FAIL;
924 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
926 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
927 if(!ctrl)
928 return E_OUTOFMEMORY;
930 ctrl->hwnd = control_hwnd;
931 ctrl->wrapper_hwnd = ns_hwnd;
932 ctrl->id = id;
933 ctrl->dlgid = This->cctrl_next_dlgid;
934 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
935 list_init(&ctrl->sub_cctrls);
937 if(This->cctrl_active_vg)
938 list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
939 else
940 list_add_tail(&This->cctrls, &ctrl->entry);
942 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl);
944 if(ppctrl) *ppctrl = ctrl;
946 This->cctrl_next_dlgid++;
947 return S_OK;
950 /**************************************************************************
951 * Container functions.
953 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
955 UINT container_height;
956 UINT column_width;
957 UINT nr_of_cols;
958 UINT max_control_height, total_height = 0;
959 UINT cur_col_pos, cur_row_pos;
960 customctrl *ctrl;
961 BOOL fits_height;
962 static const UINT cspacing = 90; /* Columns are spaced with 90px */
963 static const UINT rspacing = 4; /* Rows are spaced with 4 px. */
965 /* Given the new width of the container, this function determines the
966 * needed height of the container and places the controls according to
967 * the new layout. Returns the new height.
970 TRACE("%p\n", This);
972 column_width = This->cctrl_width + cspacing;
973 nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
975 /* We don't need to do anything unless the number of visible columns has changed. */
976 if(nr_of_cols == This->cctrls_cols)
978 RECT rc;
979 GetWindowRect(This->cctrls_hwnd, &rc);
980 return rc.bottom - rc.top;
983 This->cctrls_cols = nr_of_cols;
985 /* Get the size of the tallest control, and the total size of
986 * all the controls to figure out the number of slots we need.
988 max_control_height = 0;
989 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
991 if(ctrl->cdcstate & CDCS_VISIBLE)
993 UINT control_height = ctrl_get_height(ctrl);
994 max_control_height = max(max_control_height, control_height);
996 total_height += control_height + rspacing;
1000 if(!total_height)
1001 return 0;
1003 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
1004 TRACE("Guess: container_height: %d\n",container_height);
1006 /* Incrementally increase container_height until all the controls
1007 * fit.
1009 do {
1010 UINT columns_needed = 1;
1011 cur_row_pos = 0;
1013 fits_height = TRUE;
1014 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1016 if(ctrl->cdcstate & CDCS_VISIBLE)
1018 UINT control_height = ctrl_get_height(ctrl);
1020 if(cur_row_pos + control_height > container_height)
1022 if(++columns_needed > nr_of_cols)
1024 container_height += 1;
1025 fits_height = FALSE;
1026 break;
1028 cur_row_pos = 0;
1031 cur_row_pos += control_height + rspacing;
1034 } while(!fits_height);
1036 TRACE("Final container height: %d\n", container_height);
1038 /* Move the controls to their final destination
1040 cur_col_pos = 0, cur_row_pos = 0;
1041 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1043 if(ctrl->cdcstate & CDCS_VISIBLE)
1045 RECT rc;
1046 UINT control_height, control_indent;
1047 GetWindowRect(ctrl->wrapper_hwnd, &rc);
1048 control_height = rc.bottom - rc.top;
1050 if(cur_row_pos + control_height > container_height)
1052 cur_row_pos = 0;
1053 cur_col_pos += This->cctrl_width + cspacing;
1057 if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
1058 control_indent = 0;
1059 else
1060 control_indent = This->cctrl_indent;
1062 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
1063 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1065 cur_row_pos += control_height + rspacing;
1069 /* Sanity check */
1070 if(cur_row_pos + This->cctrl_width > container_width)
1071 ERR("-- Failed to place controls properly.\n");
1073 return container_height;
1076 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
1078 LONG wndstyle;
1080 if(parent)
1082 customctrl *ctrl, *sub_ctrl;
1083 HFONT font;
1085 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1086 wndstyle &= ~(WS_POPUP);
1087 wndstyle |= WS_CHILD;
1088 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1090 SetParent(This->cctrls_hwnd, parent);
1091 ShowWindow(This->cctrls_hwnd, TRUE);
1093 /* Set the fonts to match the dialog font. */
1094 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
1095 if(!font)
1096 ERR("Failed to get font handle from dialog.\n");
1098 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1100 if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1102 /* If this is a VisualGroup */
1103 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1105 if(font) SendMessageW(sub_ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1108 customctrl_resize(This, ctrl);
1111 else
1113 ShowWindow(This->cctrls_hwnd, FALSE);
1115 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1116 wndstyle &= ~(WS_CHILD);
1117 wndstyle |= WS_POPUP;
1118 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1120 SetParent(This->cctrls_hwnd, NULL);
1124 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
1126 FileDialogImpl *This = crs->lpCreateParams;
1127 TRACE("%p\n", This);
1129 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1130 return TRUE;
1133 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
1135 customctrl *cur1, *cur2;
1136 TRACE("%p\n", This);
1138 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1140 list_remove(&cur1->entry);
1141 ctrl_free(cur1);
1144 return TRUE;
1147 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1149 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1151 switch(umessage)
1153 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1154 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1155 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1158 return FALSE;
1161 static HRESULT init_custom_controls(FileDialogImpl *This)
1163 WNDCLASSW wc;
1164 static const WCHAR ctrl_container_classname[] =
1165 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1167 InitCommonControlsEx(NULL);
1169 This->cctrl_width = 160; /* Controls have a fixed width */
1170 This->cctrl_indent = 100;
1171 This->cctrl_def_height = 23;
1172 This->cctrls_cols = 0;
1174 This->cctrl_next_dlgid = 0x2000;
1175 list_init(&This->cctrls);
1176 This->cctrl_active_vg = NULL;
1178 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1180 wc.style = CS_HREDRAW | CS_VREDRAW;
1181 wc.lpfnWndProc = ctrl_container_wndproc;
1182 wc.cbClsExtra = 0;
1183 wc.cbWndExtra = 0;
1184 wc.hInstance = COMDLG32_hInstance;
1185 wc.hIcon = 0;
1186 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1187 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1188 wc.lpszMenuName = NULL;
1189 wc.lpszClassName = ctrl_container_classname;
1191 if(!RegisterClassW(&wc)) return E_FAIL;
1194 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1195 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1196 0, 0, 0, 0, NULL, 0,
1197 COMDLG32_hInstance, (void*)This);
1198 if(!This->cctrls_hwnd)
1199 return E_FAIL;
1201 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1203 /* Register class for */
1204 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1205 wc.hInstance != COMDLG32_hInstance)
1207 wc.style = CS_HREDRAW | CS_VREDRAW;
1208 wc.lpfnWndProc = notifysink_proc;
1209 wc.cbClsExtra = 0;
1210 wc.cbWndExtra = 0;
1211 wc.hInstance = COMDLG32_hInstance;
1212 wc.hIcon = 0;
1213 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1214 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1215 wc.lpszMenuName = NULL;
1216 wc.lpszClassName = floatnotifysinkW;
1218 if (!RegisterClassW(&wc))
1219 ERR("Failed to register FloatNotifySink window class.\n");
1222 return S_OK;
1225 /**************************************************************************
1226 * Window related functions.
1228 static void update_layout(FileDialogImpl *This)
1230 HDWP hdwp;
1231 HWND hwnd;
1232 RECT dialog_rc;
1233 RECT cancel_rc, open_rc;
1234 RECT filetype_rc, filename_rc, filenamelabel_rc;
1235 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1236 static const UINT vspacing = 4, hspacing = 4;
1237 static const UINT min_width = 320, min_height = 200;
1239 if (!GetClientRect(This->dlg_hwnd, &dialog_rc))
1241 TRACE("Invalid dialog window, not updating layout\n");
1242 return;
1245 if(dialog_rc.right < min_width || dialog_rc.bottom < min_height)
1247 TRACE("Dialog size (%d, %d) too small, not updating layout\n", dialog_rc.right, dialog_rc.bottom);
1248 return;
1251 /****
1252 * Calculate the size of the dialog and all the parts.
1255 /* Cancel button */
1256 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1257 if(hwnd)
1259 int cancel_width, cancel_height;
1260 GetWindowRect(hwnd, &cancel_rc);
1261 cancel_width = cancel_rc.right - cancel_rc.left;
1262 cancel_height = cancel_rc.bottom - cancel_rc.top;
1264 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1265 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1266 cancel_rc.right = cancel_rc.left + cancel_width;
1267 cancel_rc.bottom = cancel_rc.top + cancel_height;
1270 /* Open/Save button */
1271 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1272 if(hwnd)
1274 int open_width, open_height;
1275 GetWindowRect(hwnd, &open_rc);
1276 open_width = open_rc.right - open_rc.left;
1277 open_height = open_rc.bottom - open_rc.top;
1279 open_rc.left = cancel_rc.left - open_width - hspacing;
1280 open_rc.top = cancel_rc.top;
1281 open_rc.right = open_rc.left + open_width;
1282 open_rc.bottom = open_rc.top + open_height;
1285 /* The filetype combobox. */
1286 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1287 if(hwnd)
1289 int filetype_width, filetype_height;
1290 GetWindowRect(hwnd, &filetype_rc);
1292 filetype_width = filetype_rc.right - filetype_rc.left;
1293 filetype_height = filetype_rc.bottom - filetype_rc.top;
1295 filetype_rc.right = cancel_rc.right;
1297 filetype_rc.left = filetype_rc.right - filetype_width;
1298 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1299 filetype_rc.bottom = filetype_rc.top + filetype_height;
1301 if(!This->filterspec_count)
1302 filetype_rc.left = filetype_rc.right;
1305 /* Filename label. */
1306 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1307 if(hwnd)
1309 int filetypelabel_width, filetypelabel_height;
1310 GetWindowRect(hwnd, &filenamelabel_rc);
1312 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1313 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1315 filenamelabel_rc.left = 160; /* FIXME */
1316 filenamelabel_rc.top = filetype_rc.top;
1317 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1318 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1321 /* Filename edit box. */
1322 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1323 if(hwnd)
1325 int filename_width, filename_height;
1326 GetWindowRect(hwnd, &filename_rc);
1328 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1329 filename_height = filename_rc.bottom - filename_rc.top;
1331 filename_rc.left = filenamelabel_rc.right + hspacing;
1332 filename_rc.top = filetype_rc.top;
1333 filename_rc.right = filename_rc.left + filename_width;
1334 filename_rc.bottom = filename_rc.top + filename_height;
1337 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1338 if(hwnd)
1340 GetWindowRect(hwnd, &toolbar_rc);
1341 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1344 /* The custom controls */
1345 customctrls_rc.left = dialog_rc.left + hspacing;
1346 customctrls_rc.right = dialog_rc.right - hspacing;
1347 customctrls_rc.bottom = filename_rc.top - vspacing;
1348 customctrls_rc.top = customctrls_rc.bottom -
1349 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1351 /* The ExplorerBrowser control. */
1352 ebrowser_rc.left = dialog_rc.left + hspacing;
1353 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1354 ebrowser_rc.right = dialog_rc.right - hspacing;
1355 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1357 /****
1358 * Move everything to the right place.
1361 /* FIXME: The Save Dialog uses a slightly different layout. */
1362 hdwp = BeginDeferWindowPos(7);
1364 if(hdwp && This->peb)
1365 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1367 if(hdwp && This->cctrls_hwnd)
1368 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1369 customctrls_rc.left, customctrls_rc.top,
1370 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1371 SWP_NOZORDER | SWP_NOACTIVATE);
1373 /* The default controls */
1374 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1375 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1376 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1378 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1379 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1380 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1381 SWP_NOZORDER | SWP_NOACTIVATE);
1383 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1384 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1385 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1387 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1388 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1389 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1391 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1392 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1393 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1395 if(hdwp)
1396 EndDeferWindowPos(hdwp);
1397 else
1398 ERR("Failed to position dialog controls.\n");
1400 return;
1403 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1405 IShellItem *psi_folder;
1406 FOLDERSETTINGS fos;
1407 RECT rc = {0};
1408 HRESULT hr;
1410 /* Create ExplorerBrowser instance */
1411 OleInitialize(NULL);
1413 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1414 &IID_IExplorerBrowser, (void**)&This->peb);
1415 if(FAILED(hr))
1417 ERR("Failed to instantiate ExplorerBrowser control.\n");
1418 return hr;
1421 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES);
1423 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1424 if(FAILED(hr))
1426 ERR("Failed to initialize the ExplorerBrowser control.\n");
1427 IExplorerBrowser_Release(This->peb);
1428 This->peb = NULL;
1429 return hr;
1431 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1432 if(FAILED(hr))
1433 ERR("Advise (ExplorerBrowser) failed.\n");
1435 /* Get previous options? */
1436 fos.ViewMode = fos.fFlags = 0;
1437 if(!(This->options & FOS_ALLOWMULTISELECT))
1438 fos.fFlags |= FWF_SINGLESEL;
1440 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1442 hr = IUnknown_SetSite((IUnknown*)This->peb, (IUnknown*)This);
1443 if(FAILED(hr))
1444 ERR("SetSite (ExplorerBrowser) failed.\n");
1446 /* Browse somewhere */
1447 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1448 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1450 return S_OK;
1453 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1455 HWND htoolbar;
1456 TBADDBITMAP tbab;
1457 TBBUTTON button[2];
1459 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1460 0, 0, 0, 0,
1461 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1463 tbab.hInst = HINST_COMMCTRL;
1464 tbab.nID = IDB_HIST_LARGE_COLOR;
1465 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1467 button[0].iBitmap = HIST_BACK;
1468 button[0].idCommand = IDC_NAVBACK;
1469 button[0].fsState = TBSTATE_ENABLED;
1470 button[0].fsStyle = BTNS_BUTTON;
1471 button[0].dwData = 0;
1472 button[0].iString = 0;
1474 button[1].iBitmap = HIST_FORWARD;
1475 button[1].idCommand = IDC_NAVFORWARD;
1476 button[1].fsState = TBSTATE_ENABLED;
1477 button[1].fsStyle = BTNS_BUTTON;
1478 button[1].dwData = 0;
1479 button[1].iString = 0;
1481 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1482 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1483 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1486 static void update_control_text(FileDialogImpl *This)
1488 HWND hitem;
1489 if(This->custom_title)
1490 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1492 if(This->custom_okbutton &&
1493 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1495 SetWindowTextW(hitem, This->custom_okbutton);
1496 ctrl_resize(hitem, 50, 250, FALSE);
1499 if(This->custom_cancelbutton &&
1500 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1502 SetWindowTextW(hitem, This->custom_cancelbutton);
1503 ctrl_resize(hitem, 50, 250, FALSE);
1506 if(This->custom_filenamelabel &&
1507 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1509 SetWindowTextW(hitem, This->custom_filenamelabel);
1510 ctrl_resize(hitem, 50, 250, FALSE);
1514 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1516 FileDialogImpl *This = (FileDialogImpl*)lParam;
1517 HWND hitem;
1519 TRACE("(%p, %p)\n", This, hwnd);
1521 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1522 This->dlg_hwnd = hwnd;
1524 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1525 if(hitem) ShowWindow(hitem, SW_HIDE);
1527 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1528 if(hitem) ShowWindow(hitem, SW_HIDE);
1530 /* Fill filetypes combobox, or hide it. */
1531 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1532 if(This->filterspec_count)
1534 HDC hdc;
1535 HFONT font;
1536 SIZE size;
1537 UINT i, maxwidth = 0;
1539 hdc = GetDC(hitem);
1540 font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
1541 SelectObject(hdc, font);
1543 for(i = 0; i < This->filterspec_count; i++)
1545 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
1547 if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
1548 maxwidth = max(maxwidth, size.cx);
1550 ReleaseDC(hitem, hdc);
1552 if(maxwidth > 0)
1554 maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
1555 SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
1557 else
1558 ERR("Failed to calculate width of filetype dropdown\n");
1560 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
1562 else
1563 ShowWindow(hitem, SW_HIDE);
1565 if(This->set_filename &&
1566 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1567 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
1569 ctrl_container_reparent(This, This->dlg_hwnd);
1570 init_explorerbrowser(This);
1571 init_toolbar(This, hwnd);
1572 update_control_text(This);
1573 update_layout(This);
1575 if(This->filterspec_count)
1576 events_OnTypeChange(This);
1578 return TRUE;
1581 static LRESULT on_wm_size(FileDialogImpl *This)
1583 update_layout(This);
1584 return FALSE;
1587 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
1589 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
1590 TRACE("%p (%p)\n", This, mmi);
1592 /* FIXME */
1593 mmi->ptMinTrackSize.x = 640;
1594 mmi->ptMinTrackSize.y = 480;
1596 return FALSE;
1599 static LRESULT on_wm_destroy(FileDialogImpl *This)
1601 TRACE("%p\n", This);
1603 if(This->peb)
1605 IExplorerBrowser_Destroy(This->peb);
1606 IExplorerBrowser_Release(This->peb);
1607 This->peb = NULL;
1610 ctrl_container_reparent(This, NULL);
1611 This->dlg_hwnd = NULL;
1613 return TRUE;
1616 static LRESULT on_idok(FileDialogImpl *This)
1618 TRACE("%p\n", This);
1620 if(SUCCEEDED(on_default_action(This)))
1621 EndDialog(This->dlg_hwnd, S_OK);
1623 return FALSE;
1626 static LRESULT on_idcancel(FileDialogImpl *This)
1628 TRACE("%p\n", This);
1630 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
1632 return FALSE;
1635 static LRESULT on_browse_back(FileDialogImpl *This)
1637 TRACE("%p\n", This);
1638 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
1639 return FALSE;
1642 static LRESULT on_browse_forward(FileDialogImpl *This)
1644 TRACE("%p\n", This);
1645 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
1646 return FALSE;
1649 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1651 if(HIWORD(wparam) == CBN_SELCHANGE)
1653 IShellView *psv;
1654 HRESULT hr;
1655 LPWSTR filename;
1656 UINT prev_index = This->filetypeindex;
1658 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
1659 TRACE("File type selection changed to %d.\n", This->filetypeindex);
1661 if(prev_index == This->filetypeindex)
1662 return FALSE;
1664 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
1665 if(SUCCEEDED(hr))
1667 IShellView_Refresh(psv);
1668 IShellView_Release(psv);
1671 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
1673 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
1675 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
1676 if(ext)
1678 lstrcpyW(buf, filename);
1680 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
1681 PathRemoveExtensionW(buf);
1683 lstrcatW(buf, ext);
1684 set_file_name(This, buf);
1686 CoTaskMemFree(filename);
1689 /* The documentation claims that OnTypeChange is called only
1690 * when the dialog is opened, but this is obviously not the
1691 * case. */
1692 events_OnTypeChange(This);
1695 return FALSE;
1698 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1700 switch(LOWORD(wparam))
1702 case IDOK: return on_idok(This);
1703 case IDCANCEL: return on_idcancel(This);
1704 case IDC_NAVBACK: return on_browse_back(This);
1705 case IDC_NAVFORWARD: return on_browse_forward(This);
1706 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
1707 default: TRACE("Unknown command.\n");
1709 return FALSE;
1712 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1714 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1716 switch(umessage)
1718 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
1719 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
1720 case WM_SIZE: return on_wm_size(This);
1721 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
1722 case WM_DESTROY: return on_wm_destroy(This);
1725 return FALSE;
1728 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
1730 INT_PTR res;
1732 SetLastError(0);
1733 res = DialogBoxParamW(COMDLG32_hInstance,
1734 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
1735 parent, itemdlg_dlgproc, (LPARAM)This);
1736 This->dlg_hwnd = NULL;
1737 if(res == -1)
1739 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
1740 return E_FAIL;
1743 TRACE("Returning 0x%08x\n", (HRESULT)res);
1744 return (HRESULT)res;
1747 /**************************************************************************
1748 * IFileDialog implementation
1750 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
1752 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
1755 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
1756 REFIID riid,
1757 void **ppvObject)
1759 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1760 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1762 *ppvObject = NULL;
1763 if(IsEqualGUID(riid, &IID_IUnknown) ||
1764 IsEqualGUID(riid, &IID_IFileDialog) ||
1765 IsEqualGUID(riid, &IID_IFileDialog2))
1767 *ppvObject = iface;
1769 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
1771 *ppvObject = &This->u.IFileOpenDialog_iface;
1773 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
1775 *ppvObject = &This->u.IFileSaveDialog_iface;
1777 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
1779 *ppvObject = &This->IExplorerBrowserEvents_iface;
1781 else if(IsEqualGUID(riid, &IID_IServiceProvider))
1783 *ppvObject = &This->IServiceProvider_iface;
1785 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
1786 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
1787 IsEqualGUID(&IID_ICommDlgBrowser, riid))
1789 *ppvObject = &This->ICommDlgBrowser3_iface;
1791 else if(IsEqualGUID(&IID_IOleWindow, riid))
1793 *ppvObject = &This->IOleWindow_iface;
1795 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
1796 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
1798 *ppvObject = &This->IFileDialogCustomize_iface;
1800 else
1801 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
1803 if(*ppvObject)
1805 IUnknown_AddRef((IUnknown*)*ppvObject);
1806 return S_OK;
1809 return E_NOINTERFACE;
1812 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
1814 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1815 LONG ref = InterlockedIncrement(&This->ref);
1816 TRACE("%p - ref %d\n", This, ref);
1818 return ref;
1821 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
1823 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1824 LONG ref = InterlockedDecrement(&This->ref);
1825 TRACE("%p - ref %d\n", This, ref);
1827 if(!ref)
1829 UINT i;
1830 for(i = 0; i < This->filterspec_count; i++)
1832 LocalFree((void*)This->filterspecs[i].pszName);
1833 LocalFree((void*)This->filterspecs[i].pszSpec);
1835 HeapFree(GetProcessHeap(), 0, This->filterspecs);
1837 DestroyWindow(This->cctrls_hwnd);
1839 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
1840 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
1841 if(This->psi_folder) IShellItem_Release(This->psi_folder);
1842 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
1843 if(This->psia_results) IShellItemArray_Release(This->psia_results);
1845 LocalFree(This->set_filename);
1846 LocalFree(This->default_ext);
1847 LocalFree(This->custom_title);
1848 LocalFree(This->custom_okbutton);
1849 LocalFree(This->custom_cancelbutton);
1850 LocalFree(This->custom_filenamelabel);
1852 HeapFree(GetProcessHeap(), 0, This);
1855 return ref;
1858 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
1860 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1861 TRACE("%p (%p)\n", iface, hwndOwner);
1863 return create_dialog(This, hwndOwner);
1866 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
1867 const COMDLG_FILTERSPEC *rgFilterSpec)
1869 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1870 UINT i;
1871 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
1873 if(This->filterspecs)
1874 return E_UNEXPECTED;
1876 if(!rgFilterSpec)
1877 return E_INVALIDARG;
1879 if(!cFileTypes)
1880 return S_OK;
1882 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
1883 for(i = 0; i < cFileTypes; i++)
1885 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
1886 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
1888 This->filterspec_count = cFileTypes;
1890 return S_OK;
1893 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
1895 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1896 TRACE("%p (%d)\n", This, iFileType);
1898 if(!This->filterspecs)
1899 return E_FAIL;
1901 iFileType = max(iFileType, 1);
1902 iFileType = min(iFileType, This->filterspec_count);
1903 This->filetypeindex = iFileType-1;
1905 return S_OK;
1908 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
1910 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1911 TRACE("%p (%p)\n", This, piFileType);
1913 if(!piFileType)
1914 return E_INVALIDARG;
1916 if(This->filterspec_count == 0)
1917 *piFileType = 0;
1918 else
1919 *piFileType = This->filetypeindex + 1;
1921 return S_OK;
1924 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
1926 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1927 events_client *client;
1928 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
1930 if(!pfde || !pdwCookie)
1931 return E_INVALIDARG;
1933 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
1934 client->pfde = pfde;
1935 client->cookie = ++This->events_next_cookie;
1937 IFileDialogEvents_AddRef(pfde);
1938 *pdwCookie = client->cookie;
1940 list_add_tail(&This->events_clients, &client->entry);
1942 return S_OK;
1945 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
1947 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1948 events_client *client, *found = NULL;
1949 TRACE("%p (%d)\n", This, dwCookie);
1951 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
1953 if(client->cookie == dwCookie)
1955 found = client;
1956 break;
1960 if(found)
1962 list_remove(&found->entry);
1963 IFileDialogEvents_Release(found->pfde);
1964 HeapFree(GetProcessHeap(), 0, found);
1965 return S_OK;
1968 return E_INVALIDARG;
1971 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
1973 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1974 TRACE("%p (0x%x)\n", This, fos);
1976 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
1978 WCHAR buf[30];
1979 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, sizeof(buf)/sizeof(WCHAR));
1980 IFileDialog2_SetTitle(iface, buf);
1983 This->options = fos;
1985 return S_OK;
1988 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
1990 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1991 TRACE("%p (%p)\n", This, pfos);
1993 if(!pfos)
1994 return E_INVALIDARG;
1996 *pfos = This->options;
1998 return S_OK;
2001 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
2003 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2004 TRACE("%p (%p)\n", This, psi);
2005 if(This->psi_defaultfolder)
2006 IShellItem_Release(This->psi_defaultfolder);
2008 This->psi_defaultfolder = psi;
2010 if(This->psi_defaultfolder)
2011 IShellItem_AddRef(This->psi_defaultfolder);
2013 return S_OK;
2016 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
2018 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2019 TRACE("%p (%p)\n", This, psi);
2020 if(This->psi_setfolder)
2021 IShellItem_Release(This->psi_setfolder);
2023 This->psi_setfolder = psi;
2025 if(This->psi_setfolder)
2026 IShellItem_AddRef(This->psi_setfolder);
2028 return S_OK;
2031 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
2033 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2034 TRACE("%p (%p)\n", This, ppsi);
2035 if(!ppsi)
2036 return E_INVALIDARG;
2038 /* FIXME:
2039 If the dialog is shown, return the current(ly selected) folder. */
2041 *ppsi = NULL;
2042 if(This->psi_folder)
2043 *ppsi = This->psi_folder;
2044 else if(This->psi_setfolder)
2045 *ppsi = This->psi_setfolder;
2046 else if(This->psi_defaultfolder)
2047 *ppsi = This->psi_defaultfolder;
2049 if(*ppsi)
2051 IShellItem_AddRef(*ppsi);
2052 return S_OK;
2055 return E_FAIL;
2058 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
2060 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2061 HRESULT hr;
2062 TRACE("%p (%p)\n", This, ppsi);
2064 if(!ppsi)
2065 return E_INVALIDARG;
2067 if(This->psia_selection)
2069 /* FIXME: Check filename edit box */
2070 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2071 return hr;
2074 return E_FAIL;
2077 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
2079 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2080 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2082 set_file_name(This, pszName);
2084 return S_OK;
2087 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
2089 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2090 TRACE("%p (%p)\n", iface, pszName);
2092 if(!pszName)
2093 return E_INVALIDARG;
2095 *pszName = NULL;
2096 if(get_file_name(This, pszName))
2097 return S_OK;
2098 else
2099 return E_FAIL;
2102 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
2104 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2105 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2107 LocalFree(This->custom_title);
2108 This->custom_title = StrDupW(pszTitle);
2109 update_control_text(This);
2111 return S_OK;
2114 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
2116 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2117 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2119 LocalFree(This->custom_okbutton);
2120 This->custom_okbutton = StrDupW(pszText);
2121 update_control_text(This);
2122 update_layout(This);
2124 return S_OK;
2127 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2129 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2130 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2132 LocalFree(This->custom_filenamelabel);
2133 This->custom_filenamelabel = StrDupW(pszLabel);
2134 update_control_text(This);
2135 update_layout(This);
2137 return S_OK;
2140 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
2142 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2143 HRESULT hr;
2144 TRACE("%p (%p)\n", This, ppsi);
2146 if(!ppsi)
2147 return E_INVALIDARG;
2149 if(This->psia_results)
2151 UINT item_count;
2152 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2153 if(SUCCEEDED(hr))
2155 if(item_count != 1)
2156 return E_FAIL;
2158 /* Adds a reference. */
2159 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2162 return hr;
2165 return E_UNEXPECTED;
2168 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2170 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2171 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2172 return E_NOTIMPL;
2175 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2177 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2178 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2180 LocalFree(This->default_ext);
2181 This->default_ext = StrDupW(pszDefaultExtension);
2183 return S_OK;
2186 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2188 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2189 TRACE("%p (0x%08x)\n", This, hr);
2191 if(This->dlg_hwnd)
2192 EndDialog(This->dlg_hwnd, hr);
2194 return S_OK;
2197 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2199 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2200 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2201 This->client_guid = *guid;
2202 return S_OK;
2205 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2207 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2208 FIXME("stub - %p\n", This);
2209 return E_NOTIMPL;
2212 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2214 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2215 FIXME("stub - %p (%p)\n", This, pFilter);
2216 return E_NOTIMPL;
2219 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2221 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2222 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2224 LocalFree(This->custom_cancelbutton);
2225 This->custom_cancelbutton = StrDupW(pszLabel);
2226 update_control_text(This);
2227 update_layout(This);
2229 return S_OK;
2232 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2234 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2235 FIXME("stub - %p (%p)\n", This, psi);
2236 return E_NOTIMPL;
2239 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2240 IFileDialog2_fnQueryInterface,
2241 IFileDialog2_fnAddRef,
2242 IFileDialog2_fnRelease,
2243 IFileDialog2_fnShow,
2244 IFileDialog2_fnSetFileTypes,
2245 IFileDialog2_fnSetFileTypeIndex,
2246 IFileDialog2_fnGetFileTypeIndex,
2247 IFileDialog2_fnAdvise,
2248 IFileDialog2_fnUnadvise,
2249 IFileDialog2_fnSetOptions,
2250 IFileDialog2_fnGetOptions,
2251 IFileDialog2_fnSetDefaultFolder,
2252 IFileDialog2_fnSetFolder,
2253 IFileDialog2_fnGetFolder,
2254 IFileDialog2_fnGetCurrentSelection,
2255 IFileDialog2_fnSetFileName,
2256 IFileDialog2_fnGetFileName,
2257 IFileDialog2_fnSetTitle,
2258 IFileDialog2_fnSetOkButtonLabel,
2259 IFileDialog2_fnSetFileNameLabel,
2260 IFileDialog2_fnGetResult,
2261 IFileDialog2_fnAddPlace,
2262 IFileDialog2_fnSetDefaultExtension,
2263 IFileDialog2_fnClose,
2264 IFileDialog2_fnSetClientGuid,
2265 IFileDialog2_fnClearClientData,
2266 IFileDialog2_fnSetFilter,
2267 IFileDialog2_fnSetCancelButtonLabel,
2268 IFileDialog2_fnSetNavigationRoot
2271 /**************************************************************************
2272 * IFileOpenDialog
2274 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2276 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2279 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2280 REFIID riid, void **ppvObject)
2282 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2283 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2286 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2288 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2289 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2292 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2294 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2295 return IFileDialog2_Release(&This->IFileDialog2_iface);
2298 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2300 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2301 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2304 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2305 const COMDLG_FILTERSPEC *rgFilterSpec)
2307 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2308 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2311 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2313 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2314 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2317 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2319 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2320 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2323 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2324 DWORD *pdwCookie)
2326 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2327 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2330 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2332 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2333 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2336 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2338 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2339 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2342 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2344 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2345 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2348 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2350 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2351 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2354 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2356 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2357 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2360 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2362 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2363 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2366 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2368 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2369 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2372 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2374 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2375 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2378 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2380 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2381 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2384 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2386 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2387 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2390 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2392 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2393 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2396 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2398 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2399 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2402 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2404 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2405 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2408 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2410 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2411 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2414 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2415 LPCWSTR pszDefaultExtension)
2417 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2418 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2421 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2423 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2424 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2427 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2429 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2430 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2433 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2435 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2436 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2439 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2441 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2442 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2445 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2447 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2448 TRACE("%p (%p)\n", This, ppenum);
2450 *ppenum = This->psia_results;
2452 if(*ppenum)
2454 IShellItemArray_AddRef(*ppenum);
2455 return S_OK;
2458 return E_FAIL;
2461 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2463 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2464 TRACE("%p (%p)\n", This, ppsai);
2466 if(This->psia_selection)
2468 *ppsai = This->psia_selection;
2469 IShellItemArray_AddRef(*ppsai);
2470 return S_OK;
2473 return E_FAIL;
2476 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2477 IFileOpenDialog_fnQueryInterface,
2478 IFileOpenDialog_fnAddRef,
2479 IFileOpenDialog_fnRelease,
2480 IFileOpenDialog_fnShow,
2481 IFileOpenDialog_fnSetFileTypes,
2482 IFileOpenDialog_fnSetFileTypeIndex,
2483 IFileOpenDialog_fnGetFileTypeIndex,
2484 IFileOpenDialog_fnAdvise,
2485 IFileOpenDialog_fnUnadvise,
2486 IFileOpenDialog_fnSetOptions,
2487 IFileOpenDialog_fnGetOptions,
2488 IFileOpenDialog_fnSetDefaultFolder,
2489 IFileOpenDialog_fnSetFolder,
2490 IFileOpenDialog_fnGetFolder,
2491 IFileOpenDialog_fnGetCurrentSelection,
2492 IFileOpenDialog_fnSetFileName,
2493 IFileOpenDialog_fnGetFileName,
2494 IFileOpenDialog_fnSetTitle,
2495 IFileOpenDialog_fnSetOkButtonLabel,
2496 IFileOpenDialog_fnSetFileNameLabel,
2497 IFileOpenDialog_fnGetResult,
2498 IFileOpenDialog_fnAddPlace,
2499 IFileOpenDialog_fnSetDefaultExtension,
2500 IFileOpenDialog_fnClose,
2501 IFileOpenDialog_fnSetClientGuid,
2502 IFileOpenDialog_fnClearClientData,
2503 IFileOpenDialog_fnSetFilter,
2504 IFileOpenDialog_fnGetResults,
2505 IFileOpenDialog_fnGetSelectedItems
2508 /**************************************************************************
2509 * IFileSaveDialog
2511 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
2513 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
2516 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
2517 REFIID riid,
2518 void **ppvObject)
2520 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2521 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2524 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
2526 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2527 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2530 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
2532 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2533 return IFileDialog2_Release(&This->IFileDialog2_iface);
2536 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
2538 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2539 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2542 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
2543 const COMDLG_FILTERSPEC *rgFilterSpec)
2545 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2546 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2549 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
2551 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2552 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2555 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
2557 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2558 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2561 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
2562 DWORD *pdwCookie)
2564 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2565 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2568 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
2570 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2571 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2574 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
2576 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2577 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2580 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2582 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2583 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2586 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
2588 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2589 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2592 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
2594 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2595 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2598 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
2600 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2601 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2604 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
2606 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2607 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2610 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
2612 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2613 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2616 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
2618 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2619 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2622 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
2624 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2625 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2628 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
2630 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2631 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2634 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
2636 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2637 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2640 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
2642 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2643 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2646 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
2648 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2649 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2652 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
2653 LPCWSTR pszDefaultExtension)
2655 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2656 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2659 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
2661 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2662 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2665 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
2667 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2668 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2671 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
2673 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2674 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2677 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
2679 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2680 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2683 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
2685 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2686 FIXME("stub - %p (%p)\n", This, psi);
2687 return E_NOTIMPL;
2690 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
2692 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2693 FIXME("stub - %p (%p)\n", This, pStore);
2694 return E_NOTIMPL;
2697 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
2698 IPropertyDescriptionList *pList,
2699 BOOL fAppendDefault)
2701 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2702 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
2703 return E_NOTIMPL;
2706 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
2708 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2709 FIXME("stub - %p (%p)\n", This, ppStore);
2710 return E_NOTIMPL;
2713 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
2714 IShellItem *psi,
2715 IPropertyStore *pStore,
2716 HWND hwnd,
2717 IFileOperationProgressSink *pSink)
2719 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2720 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
2721 return E_NOTIMPL;
2724 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
2725 IFileSaveDialog_fnQueryInterface,
2726 IFileSaveDialog_fnAddRef,
2727 IFileSaveDialog_fnRelease,
2728 IFileSaveDialog_fnShow,
2729 IFileSaveDialog_fnSetFileTypes,
2730 IFileSaveDialog_fnSetFileTypeIndex,
2731 IFileSaveDialog_fnGetFileTypeIndex,
2732 IFileSaveDialog_fnAdvise,
2733 IFileSaveDialog_fnUnadvise,
2734 IFileSaveDialog_fnSetOptions,
2735 IFileSaveDialog_fnGetOptions,
2736 IFileSaveDialog_fnSetDefaultFolder,
2737 IFileSaveDialog_fnSetFolder,
2738 IFileSaveDialog_fnGetFolder,
2739 IFileSaveDialog_fnGetCurrentSelection,
2740 IFileSaveDialog_fnSetFileName,
2741 IFileSaveDialog_fnGetFileName,
2742 IFileSaveDialog_fnSetTitle,
2743 IFileSaveDialog_fnSetOkButtonLabel,
2744 IFileSaveDialog_fnSetFileNameLabel,
2745 IFileSaveDialog_fnGetResult,
2746 IFileSaveDialog_fnAddPlace,
2747 IFileSaveDialog_fnSetDefaultExtension,
2748 IFileSaveDialog_fnClose,
2749 IFileSaveDialog_fnSetClientGuid,
2750 IFileSaveDialog_fnClearClientData,
2751 IFileSaveDialog_fnSetFilter,
2752 IFileSaveDialog_fnSetSaveAsItem,
2753 IFileSaveDialog_fnSetProperties,
2754 IFileSaveDialog_fnSetCollectedProperties,
2755 IFileSaveDialog_fnGetProperties,
2756 IFileSaveDialog_fnApplyProperties
2759 /**************************************************************************
2760 * IExplorerBrowserEvents implementation
2762 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
2764 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
2767 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
2768 REFIID riid, void **ppvObject)
2770 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2771 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2773 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2776 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
2778 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2779 TRACE("%p\n", This);
2780 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2783 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
2785 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2786 TRACE("%p\n", This);
2787 return IFileDialog2_Release(&This->IFileDialog2_iface);
2790 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
2791 PCIDLIST_ABSOLUTE pidlFolder)
2793 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2794 IShellItem *psi;
2795 HRESULT hr;
2796 TRACE("%p (%p)\n", This, pidlFolder);
2798 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
2799 if(SUCCEEDED(hr))
2801 hr = events_OnFolderChanging(This, psi);
2802 IShellItem_Release(psi);
2804 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
2805 if(hr == S_FALSE)
2806 hr = E_FAIL;
2808 return hr;
2810 else
2811 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
2813 return S_OK;
2816 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
2817 IShellView *psv)
2819 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2820 TRACE("%p (%p)\n", This, psv);
2821 return S_OK;
2824 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
2825 PCIDLIST_ABSOLUTE pidlFolder)
2827 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2828 HRESULT hr;
2829 TRACE("%p (%p)\n", This, pidlFolder);
2831 if(This->psi_folder)
2832 IShellItem_Release(This->psi_folder);
2834 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
2835 if(FAILED(hr))
2837 ERR("Failed to get the current folder.\n");
2838 This->psi_folder = NULL;
2841 events_OnFolderChange(This);
2843 return S_OK;
2846 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
2847 PCIDLIST_ABSOLUTE pidlFolder)
2849 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2850 TRACE("%p (%p)\n", This, pidlFolder);
2851 return S_OK;
2854 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
2855 IExplorerBrowserEvents_fnQueryInterface,
2856 IExplorerBrowserEvents_fnAddRef,
2857 IExplorerBrowserEvents_fnRelease,
2858 IExplorerBrowserEvents_fnOnNavigationPending,
2859 IExplorerBrowserEvents_fnOnViewCreated,
2860 IExplorerBrowserEvents_fnOnNavigationComplete,
2861 IExplorerBrowserEvents_fnOnNavigationFailed
2864 /**************************************************************************
2865 * IServiceProvider implementation
2867 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2869 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
2872 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
2873 REFIID riid, void **ppvObject)
2875 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2876 TRACE("%p\n", This);
2877 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2880 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
2882 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2883 TRACE("%p\n", This);
2884 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2887 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
2889 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2890 TRACE("%p\n", This);
2891 return IFileDialog2_Release(&This->IFileDialog2_iface);
2894 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
2895 REFGUID guidService,
2896 REFIID riid, void **ppv)
2898 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2899 HRESULT hr = E_NOTIMPL;
2900 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
2902 *ppv = NULL;
2903 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
2904 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
2905 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
2906 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
2907 else
2908 FIXME("Interface %s requested from unknown service %s\n",
2909 debugstr_guid(riid), debugstr_guid(guidService));
2911 return hr;
2914 static const IServiceProviderVtbl vt_IServiceProvider = {
2915 IServiceProvider_fnQueryInterface,
2916 IServiceProvider_fnAddRef,
2917 IServiceProvider_fnRelease,
2918 IServiceProvider_fnQueryService
2921 /**************************************************************************
2922 * ICommDlgBrowser3 implementation
2924 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
2926 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
2929 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
2930 REFIID riid, void **ppvObject)
2932 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2933 TRACE("%p\n", This);
2934 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2937 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
2939 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2940 TRACE("%p\n", This);
2941 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2944 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
2946 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2947 TRACE("%p\n", This);
2948 return IFileDialog2_Release(&This->IFileDialog2_iface);
2951 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
2952 IShellView *shv)
2954 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2955 HRESULT hr;
2956 TRACE("%p (%p)\n", This, shv);
2958 hr = on_default_action(This);
2960 if(SUCCEEDED(hr))
2961 EndDialog(This->dlg_hwnd, S_OK);
2963 return S_OK;
2966 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
2967 IShellView *shv, ULONG uChange )
2969 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2970 IDataObject *new_selection;
2971 HRESULT hr;
2972 TRACE("%p (%p, %x)\n", This, shv, uChange);
2974 switch(uChange)
2976 case CDBOSC_SELCHANGE:
2977 if(This->psia_selection)
2979 IShellItemArray_Release(This->psia_selection);
2980 This->psia_selection = NULL;
2983 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
2984 if(SUCCEEDED(hr))
2986 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
2987 (void**)&This->psia_selection);
2988 if(SUCCEEDED(hr))
2990 fill_filename_from_selection(This);
2991 events_OnSelectionChange(This);
2994 IDataObject_Release(new_selection);
2996 break;
2997 default:
2998 TRACE("Unhandled state change\n");
3000 return S_OK;
3003 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
3004 IShellView *shv, LPCITEMIDLIST pidl)
3006 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3007 IShellItem *psi;
3008 LPWSTR filename;
3009 LPITEMIDLIST parent_pidl;
3010 HRESULT hr;
3011 ULONG attr;
3012 TRACE("%p (%p, %p)\n", This, shv, pidl);
3014 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
3015 return S_OK;
3017 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3018 if(SUCCEEDED(hr))
3020 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3021 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3022 ILFree(parent_pidl);
3023 ILFree(full_pidl);
3025 if(FAILED(hr))
3027 ERR("Failed to get shellitem (%08x).\n", hr);
3028 return S_OK;
3031 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3032 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3034 IShellItem_Release(psi);
3035 return S_OK;
3038 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
3040 IShellItem_Release(psi);
3041 return S_FALSE;
3044 hr = S_OK;
3045 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
3047 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
3048 hr = S_FALSE;
3049 CoTaskMemFree(filename);
3052 IShellItem_Release(psi);
3053 return hr;
3056 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
3057 IShellView *ppshv, DWORD dwNotifyType)
3059 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3060 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
3061 return E_NOTIMPL;
3064 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
3065 IShellView *pshv,
3066 LPWSTR pszText, int cchMax)
3068 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3069 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
3070 return E_NOTIMPL;
3073 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
3075 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3076 FIXME("Stub: %p (%p)\n", This, pdwFlags);
3077 return E_NOTIMPL;
3080 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
3081 IShellView *pshv, int iColumn)
3083 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3084 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
3085 return E_NOTIMPL;
3088 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
3089 LPWSTR pszFileSpec, int cchFileSpec)
3091 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3092 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
3093 return E_NOTIMPL;
3096 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
3097 IShellView *pshv)
3099 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3100 FIXME("Stub: %p (%p)\n", This, pshv);
3101 return E_NOTIMPL;
3104 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
3105 ICommDlgBrowser3_fnQueryInterface,
3106 ICommDlgBrowser3_fnAddRef,
3107 ICommDlgBrowser3_fnRelease,
3108 ICommDlgBrowser3_fnOnDefaultCommand,
3109 ICommDlgBrowser3_fnOnStateChange,
3110 ICommDlgBrowser3_fnIncludeObject,
3111 ICommDlgBrowser3_fnNotify,
3112 ICommDlgBrowser3_fnGetDefaultMenuText,
3113 ICommDlgBrowser3_fnGetViewFlags,
3114 ICommDlgBrowser3_fnOnColumnClicked,
3115 ICommDlgBrowser3_fnGetCurrentFilter,
3116 ICommDlgBrowser3_fnOnPreviewCreated
3119 /**************************************************************************
3120 * IOleWindow implementation
3122 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
3124 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
3127 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
3129 FileDialogImpl *This = impl_from_IOleWindow(iface);
3130 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3133 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
3135 FileDialogImpl *This = impl_from_IOleWindow(iface);
3136 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3139 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
3141 FileDialogImpl *This = impl_from_IOleWindow(iface);
3142 return IFileDialog2_Release(&This->IFileDialog2_iface);
3145 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
3147 FileDialogImpl *This = impl_from_IOleWindow(iface);
3148 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
3149 return E_NOTIMPL;
3152 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
3154 FileDialogImpl *This = impl_from_IOleWindow(iface);
3155 TRACE("%p (%p)\n", This, phwnd);
3156 *phwnd = This->dlg_hwnd;
3157 return S_OK;
3160 static const IOleWindowVtbl vt_IOleWindow = {
3161 IOleWindow_fnQueryInterface,
3162 IOleWindow_fnAddRef,
3163 IOleWindow_fnRelease,
3164 IOleWindow_fnGetWindow,
3165 IOleWindow_fnContextSensitiveHelp
3168 /**************************************************************************
3169 * IFileDialogCustomize implementation
3171 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3173 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3176 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3177 REFIID riid, void **ppvObject)
3179 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3180 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3183 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3185 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3186 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3189 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3191 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3192 return IFileDialog2_Release(&This->IFileDialog2_iface);
3195 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3196 DWORD dwIDCtl)
3198 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3199 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3200 return E_NOTIMPL;
3203 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3204 DWORD dwIDCtl,
3205 LPCWSTR pszLabel)
3207 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3208 customctrl *ctrl;
3209 TBBUTTON tbb;
3210 HRESULT hr;
3211 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3213 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3214 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3215 This->cctrl_def_height, &ctrl);
3216 if(SUCCEEDED(hr))
3218 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3219 ctrl->type = IDLG_CCTRL_MENU;
3221 /* Add the actual button with a popup menu. */
3222 tbb.iBitmap = I_IMAGENONE;
3223 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3224 tbb.iString = (DWORD_PTR)pszLabel;
3225 tbb.fsState = TBSTATE_ENABLED;
3226 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3227 tbb.idCommand = 1;
3229 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3232 return hr;
3235 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3236 DWORD dwIDCtl,
3237 LPCWSTR pszLabel)
3239 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3240 customctrl *ctrl;
3241 HRESULT hr;
3242 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3244 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3245 This->cctrl_def_height, &ctrl);
3246 if(SUCCEEDED(hr))
3247 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3249 return hr;
3252 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3253 DWORD dwIDCtl)
3255 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3256 customctrl *ctrl;
3257 HRESULT hr;
3258 TRACE("%p (%d)\n", This, dwIDCtl);
3260 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3261 This->cctrl_def_height, &ctrl);
3262 if(SUCCEEDED(hr))
3263 ctrl->type = IDLG_CCTRL_COMBOBOX;
3265 return hr;
3268 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3269 DWORD dwIDCtl)
3271 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3272 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3273 return E_NOTIMPL;
3276 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3277 DWORD dwIDCtl,
3278 LPCWSTR pszLabel,
3279 BOOL bChecked)
3281 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3282 customctrl *ctrl;
3283 HRESULT hr;
3284 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3286 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0,
3287 This->cctrl_def_height, &ctrl);
3288 if(SUCCEEDED(hr))
3290 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3291 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3294 return hr;
3297 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3298 DWORD dwIDCtl,
3299 LPCWSTR pszText)
3301 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3302 customctrl *ctrl;
3303 HRESULT hr;
3304 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3306 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3307 This->cctrl_def_height, &ctrl);
3308 if(SUCCEEDED(hr))
3309 ctrl->type = IDLG_CCTRL_EDITBOX;
3311 return hr;
3314 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3315 DWORD dwIDCtl)
3317 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3318 customctrl *ctrl;
3319 HRESULT hr;
3320 TRACE("%p (%d)\n", This, dwIDCtl);
3322 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3323 GetSystemMetrics(SM_CYEDGE), &ctrl);
3324 if(SUCCEEDED(hr))
3325 ctrl->type = IDLG_CCTRL_SEPARATOR;
3327 return hr;
3330 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3331 DWORD dwIDCtl,
3332 LPCWSTR pszText)
3334 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3335 customctrl *ctrl;
3336 HRESULT hr;
3337 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3339 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3340 This->cctrl_def_height, &ctrl);
3341 if(SUCCEEDED(hr))
3342 ctrl->type = IDLG_CCTRL_TEXT;
3344 return hr;
3347 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3348 DWORD dwIDCtl,
3349 LPCWSTR pszLabel)
3351 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3352 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3353 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3355 if(!ctrl) return E_INVALIDARG;
3357 switch(ctrl->type)
3359 case IDLG_CCTRL_MENU:
3360 case IDLG_CCTRL_PUSHBUTTON:
3361 case IDLG_CCTRL_CHECKBUTTON:
3362 case IDLG_CCTRL_TEXT:
3363 case IDLG_CCTRL_VISUALGROUP:
3364 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3365 break;
3366 default:
3367 break;
3370 return S_OK;
3373 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3374 DWORD dwIDCtl,
3375 CDCONTROLSTATEF *pdwState)
3377 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3378 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3379 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3381 if(!ctrl) return E_NOTIMPL;
3383 *pdwState = ctrl->cdcstate;
3384 return S_OK;
3387 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3388 DWORD dwIDCtl,
3389 CDCONTROLSTATEF dwState)
3391 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3392 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3393 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3395 if(ctrl)
3397 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3399 if(dwState & CDCS_ENABLED)
3400 wndstyle &= ~(WS_DISABLED);
3401 else
3402 wndstyle |= WS_DISABLED;
3404 if(dwState & CDCS_VISIBLE)
3405 wndstyle |= WS_VISIBLE;
3406 else
3407 wndstyle &= ~(WS_VISIBLE);
3409 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3411 /* We save the state separately since at least one application
3412 * relies on being able to hide a control. */
3413 ctrl->cdcstate = dwState;
3416 return S_OK;
3419 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3420 DWORD dwIDCtl,
3421 WCHAR **ppszText)
3423 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3424 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3425 WCHAR len, *text;
3426 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
3428 if(!ctrl || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3429 return E_FAIL;
3431 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3432 if(!text) return E_FAIL;
3434 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3435 *ppszText = text;
3436 return S_OK;
3439 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
3440 DWORD dwIDCtl,
3441 LPCWSTR pszText)
3443 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3444 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3445 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
3447 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
3448 return E_FAIL;
3450 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
3451 return S_OK;
3454 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
3455 DWORD dwIDCtl,
3456 BOOL *pbChecked)
3458 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3459 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3460 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
3462 if(ctrl)
3463 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
3465 return S_OK;
3468 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
3469 DWORD dwIDCtl,
3470 BOOL bChecked)
3472 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3473 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3474 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
3476 if(ctrl)
3477 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
3479 return S_OK;
3482 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
3484 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
3485 UINT i;
3486 if(!count || (count == CB_ERR))
3487 return -1;
3489 for(i = 0; i < count; i++)
3490 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3491 return i;
3493 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
3494 return -1;
3497 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
3498 DWORD dwIDCtl,
3499 DWORD dwIDItem,
3500 LPCWSTR pszLabel)
3502 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3503 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3504 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3506 if(!ctrl) return E_FAIL;
3508 switch(ctrl->type)
3510 case IDLG_CCTRL_COMBOBOX:
3512 UINT index;
3514 if(get_combobox_index_from_id(ctrl->hwnd, dwIDItem) != -1)
3515 return E_INVALIDARG;
3517 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
3518 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
3520 return S_OK;
3522 case IDLG_CCTRL_MENU:
3524 TBBUTTON tbb;
3525 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3527 if(GetMenuState((HMENU)tbb.dwData, dwIDItem, MF_BYCOMMAND) != -1)
3528 return E_INVALIDARG;
3530 AppendMenuW((HMENU)tbb.dwData, MF_STRING, dwIDItem, pszLabel);
3531 return S_OK;
3533 default:
3534 break;
3537 return E_NOINTERFACE; /* win7 */
3540 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
3541 DWORD dwIDCtl,
3542 DWORD dwIDItem)
3544 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3545 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3546 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3548 if(!ctrl) return E_FAIL;
3550 switch(ctrl->type)
3552 case IDLG_CCTRL_COMBOBOX:
3554 UINT i, count = SendMessageW(ctrl->hwnd, CB_GETCOUNT, 0, 0);
3555 if(!count || (count == CB_ERR))
3556 return E_FAIL;
3558 for(i = 0; i < count; i++)
3559 if(SendMessageW(ctrl->hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3561 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, i, 0) == CB_ERR)
3562 return E_FAIL;
3563 return S_OK;
3566 return E_UNEXPECTED;
3568 case IDLG_CCTRL_MENU:
3570 TBBUTTON tbb;
3571 HMENU hmenu;
3572 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3573 hmenu = (HMENU)tbb.dwData;
3575 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
3576 return E_UNEXPECTED;
3578 return S_OK;
3580 default:
3581 break;
3584 return E_FAIL;
3587 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
3588 DWORD dwIDCtl)
3590 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3591 TRACE("%p (%d)\n", This, dwIDCtl);
3593 /* Not implemented by native */
3594 return E_NOTIMPL;
3597 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
3598 DWORD dwIDCtl,
3599 DWORD dwIDItem,
3600 CDCONTROLSTATEF *pdwState)
3602 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3603 FIXME("stub - %p\n", This);
3604 return E_NOTIMPL;
3607 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
3608 DWORD dwIDCtl,
3609 DWORD dwIDItem,
3610 CDCONTROLSTATEF dwState)
3612 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3613 FIXME("stub - %p\n", This);
3614 return E_NOTIMPL;
3617 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
3618 DWORD dwIDCtl,
3619 DWORD *pdwIDItem)
3621 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3622 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3623 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
3625 if(!ctrl) return E_FAIL;
3627 switch(ctrl->type)
3629 case IDLG_CCTRL_COMBOBOX:
3631 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
3632 if(index == CB_ERR)
3633 return E_FAIL;
3635 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
3636 return S_OK;
3638 default:
3639 FIXME("Unsupported control type %d\n", ctrl->type);
3642 return E_NOTIMPL;
3645 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
3646 DWORD dwIDCtl,
3647 DWORD dwIDItem)
3649 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3650 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3651 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3653 if(!ctrl) return E_INVALIDARG;
3655 switch(ctrl->type)
3657 case IDLG_CCTRL_COMBOBOX:
3659 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
3661 if(index == -1)
3662 return E_INVALIDARG;
3664 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
3665 return E_FAIL;
3667 return S_OK;
3669 default:
3670 FIXME("Unsupported control type %d\n", ctrl->type);
3673 return E_INVALIDARG;
3676 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
3677 DWORD dwIDCtl,
3678 LPCWSTR pszLabel)
3680 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3681 customctrl *vg;
3682 HRESULT hr;
3683 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
3685 if(This->cctrl_active_vg)
3686 return E_UNEXPECTED;
3688 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0,
3689 This->cctrl_def_height, &vg);
3690 if(SUCCEEDED(hr))
3692 vg->type = IDLG_CCTRL_VISUALGROUP;
3693 This->cctrl_active_vg = vg;
3696 return hr;
3699 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
3701 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3702 TRACE("%p\n", This);
3704 This->cctrl_active_vg = NULL;
3706 return S_OK;
3709 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
3710 DWORD dwIDCtl)
3712 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3713 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3714 return E_NOTIMPL;
3717 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
3718 DWORD dwIDCtl,
3719 DWORD dwIDItem,
3720 LPCWSTR pszLabel)
3722 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3723 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3724 return E_NOTIMPL;
3727 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
3728 IFileDialogCustomize_fnQueryInterface,
3729 IFileDialogCustomize_fnAddRef,
3730 IFileDialogCustomize_fnRelease,
3731 IFileDialogCustomize_fnEnableOpenDropDown,
3732 IFileDialogCustomize_fnAddMenu,
3733 IFileDialogCustomize_fnAddPushButton,
3734 IFileDialogCustomize_fnAddComboBox,
3735 IFileDialogCustomize_fnAddRadioButtonList,
3736 IFileDialogCustomize_fnAddCheckButton,
3737 IFileDialogCustomize_fnAddEditBox,
3738 IFileDialogCustomize_fnAddSeparator,
3739 IFileDialogCustomize_fnAddText,
3740 IFileDialogCustomize_fnSetControlLabel,
3741 IFileDialogCustomize_fnGetControlState,
3742 IFileDialogCustomize_fnSetControlState,
3743 IFileDialogCustomize_fnGetEditBoxText,
3744 IFileDialogCustomize_fnSetEditBoxText,
3745 IFileDialogCustomize_fnGetCheckButtonState,
3746 IFileDialogCustomize_fnSetCheckButtonState,
3747 IFileDialogCustomize_fnAddControlItem,
3748 IFileDialogCustomize_fnRemoveControlItem,
3749 IFileDialogCustomize_fnRemoveAllControlItems,
3750 IFileDialogCustomize_fnGetControlItemState,
3751 IFileDialogCustomize_fnSetControlItemState,
3752 IFileDialogCustomize_fnGetSelectedControlItem,
3753 IFileDialogCustomize_fnSetSelectedControlItem,
3754 IFileDialogCustomize_fnStartVisualGroup,
3755 IFileDialogCustomize_fnEndVisualGroup,
3756 IFileDialogCustomize_fnMakeProminent,
3757 IFileDialogCustomize_fnSetControlItemText
3760 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
3762 FileDialogImpl *fdimpl;
3763 HRESULT hr;
3764 IShellFolder *psf;
3765 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
3767 if(!ppv)
3768 return E_POINTER;
3769 if(pUnkOuter)
3770 return CLASS_E_NOAGGREGATION;
3772 fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
3773 if(!fdimpl)
3774 return E_OUTOFMEMORY;
3776 fdimpl->ref = 1;
3777 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
3778 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
3779 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
3780 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
3781 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
3782 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
3784 if(type == ITEMDLG_TYPE_OPEN)
3786 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
3787 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
3788 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
3789 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
3791 else
3793 WCHAR buf[16];
3794 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
3795 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
3796 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
3798 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
3799 fdimpl->custom_title = StrDupW(buf);
3800 fdimpl->custom_okbutton = StrDupW(buf);
3803 fdimpl->filterspecs = NULL;
3804 fdimpl->filterspec_count = 0;
3805 fdimpl->filetypeindex = 0;
3807 fdimpl->psia_selection = fdimpl->psia_results = NULL;
3808 fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
3810 list_init(&fdimpl->events_clients);
3811 fdimpl->events_next_cookie = 0;
3813 fdimpl->dlg_hwnd = NULL;
3814 fdimpl->peb = NULL;
3816 fdimpl->set_filename = NULL;
3817 fdimpl->default_ext = NULL;
3818 fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL;
3820 fdimpl->client_guid = GUID_NULL;
3822 /* FIXME: The default folder setting should be restored for the
3823 * application if it was previously set. */
3824 SHGetDesktopFolder(&psf);
3825 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
3826 IShellFolder_Release(psf);
3828 hr = init_custom_controls(fdimpl);
3829 if(FAILED(hr))
3831 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
3832 IUnknown_Release((IUnknown*)fdimpl);
3833 return E_FAIL;
3836 hr = IUnknown_QueryInterface((IUnknown*)fdimpl, riid, ppv);
3837 IUnknown_Release((IUnknown*)fdimpl);
3838 return hr;
3841 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3843 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
3846 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3848 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);