comdlg32/tests: Use win8 failure-code as default result.
[wine/wine-gecko.git] / dlls / comdlg32 / itemdlg.c
blob96ee5dc6615498a71b86f1f1203223097e39cf44
1 /*
2 * Common Item Dialog
4 * Copyright 2010,2011 David Hedberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "wingdi.h"
31 #include "winreg.h"
32 #include "shlwapi.h"
34 #include "commdlg.h"
35 #include "cdlg.h"
36 #include "filedlgbrowser.h"
38 #include "wine/debug.h"
39 #include "wine/list.h"
41 #define IDC_NAV_TOOLBAR 200
42 #define IDC_NAVBACK 201
43 #define IDC_NAVFORWARD 202
45 #include <initguid.h>
46 /* This seems to be another version of IID_IFileDialogCustomize. If
47 * there is any difference I have yet to find it. */
48 DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F);
50 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
52 static const WCHAR notifysink_childW[] = {'n','f','s','_','c','h','i','l','d',0};
53 static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0};
55 enum ITEMDLG_TYPE {
56 ITEMDLG_TYPE_OPEN,
57 ITEMDLG_TYPE_SAVE
60 enum ITEMDLG_CCTRL_TYPE {
61 IDLG_CCTRL_MENU,
62 IDLG_CCTRL_PUSHBUTTON,
63 IDLG_CCTRL_COMBOBOX,
64 IDLG_CCTRL_RADIOBUTTONLIST,
65 IDLG_CCTRL_CHECKBUTTON,
66 IDLG_CCTRL_EDITBOX,
67 IDLG_CCTRL_SEPARATOR,
68 IDLG_CCTRL_TEXT
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;
77 } customctrl;
79 typedef struct {
80 struct list entry;
81 IFileDialogEvents *pfde;
82 DWORD cookie;
83 } events_client;
85 typedef struct FileDialogImpl {
86 IFileDialog2 IFileDialog2_iface;
87 union {
88 IFileOpenDialog IFileOpenDialog_iface;
89 IFileSaveDialog IFileSaveDialog_iface;
90 } u;
91 enum ITEMDLG_TYPE dlg_type;
92 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
93 IServiceProvider IServiceProvider_iface;
94 ICommDlgBrowser3 ICommDlgBrowser3_iface;
95 IOleWindow IOleWindow_iface;
96 IFileDialogCustomize IFileDialogCustomize_iface;
97 LONG ref;
99 FILEOPENDIALOGOPTIONS options;
100 COMDLG_FILTERSPEC *filterspecs;
101 UINT filterspec_count;
102 UINT filetypeindex;
104 struct list events_clients;
105 DWORD events_next_cookie;
107 IShellItemArray *psia_selection;
108 IShellItemArray *psia_results;
109 IShellItem *psi_defaultfolder;
110 IShellItem *psi_setfolder;
111 IShellItem *psi_folder;
113 HWND dlg_hwnd;
114 IExplorerBrowser *peb;
115 DWORD ebevents_cookie;
117 LPWSTR set_filename;
118 LPWSTR default_ext;
119 LPWSTR custom_title;
120 LPWSTR custom_okbutton;
121 LPWSTR custom_cancelbutton;
122 LPWSTR custom_filenamelabel;
124 UINT cctrl_width, cctrl_def_height, cctrls_cols;
125 HWND cctrls_hwnd;
126 struct list cctrls;
127 UINT_PTR cctrl_next_dlgid;
128 } FileDialogImpl;
130 /**************************************************************************
131 * Event wrappers.
133 static HRESULT events_OnFileOk(FileDialogImpl *This)
135 events_client *cursor;
136 HRESULT hr = S_OK;
137 TRACE("%p\n", This);
139 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
141 TRACE("Notifying %p\n", cursor);
142 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
143 if(FAILED(hr) && hr != E_NOTIMPL)
144 break;
147 if(hr == E_NOTIMPL)
148 hr = S_OK;
150 return hr;
153 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
155 events_client *cursor;
156 HRESULT hr = S_OK;
157 TRACE("%p (%p)\n", This, folder);
159 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
161 TRACE("Notifying %p\n", cursor);
162 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
163 if(FAILED(hr) && hr != E_NOTIMPL)
164 break;
167 if(hr == E_NOTIMPL)
168 hr = S_OK;
170 return hr;
173 static void events_OnFolderChange(FileDialogImpl *This)
175 events_client *cursor;
176 TRACE("%p\n", This);
178 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
180 TRACE("Notifying %p\n", cursor);
181 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
185 static void events_OnSelectionChange(FileDialogImpl *This)
187 events_client *cursor;
188 TRACE("%p\n", This);
190 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
192 TRACE("Notifying %p\n", cursor);
193 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
197 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
199 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
202 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
204 events_client *cursor;
205 TRACE("%p\n", This);
207 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
209 IFileDialogControlEvents *pfdce;
210 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
212 TRACE("Notifying %p\n", cursor);
213 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
214 IFileDialogControlEvents_Release(pfdce);
218 return S_OK;
221 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_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_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
233 IFileDialogControlEvents_Release(pfdce);
237 return S_OK;
240 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
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_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
252 IFileDialogControlEvents_Release(pfdce);
256 return S_OK;
259 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
260 DWORD ctl_id)
262 events_client *cursor;
263 TRACE("%p\n", This);
265 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
267 IFileDialogControlEvents *pfdce;
268 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
270 TRACE("Notifying %p\n", cursor);
271 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
272 IFileDialogControlEvents_Release(pfdce);
276 return S_OK;
279 /**************************************************************************
280 * Helper functions.
282 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
284 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
285 UINT len;
287 if(!hwnd_edit)
289 if(This->set_filename)
291 len = lstrlenW(This->set_filename);
292 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
293 lstrcpyW(*str, This->set_filename);
294 return len;
296 return FALSE;
299 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
300 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
301 if(!*str)
302 return FALSE;
304 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
305 return len;
308 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
310 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
312 if(This->set_filename)
313 LocalFree(This->set_filename);
315 This->set_filename = StrDupW(str);
317 return SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str);
320 static void fill_filename_from_selection(FileDialogImpl *This)
322 IShellItem *psi;
323 LPWSTR *names;
324 HRESULT hr;
325 UINT item_count, valid_count;
326 UINT len_total, i;
328 if(!This->psia_selection)
329 return;
331 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
332 if(FAILED(hr) || !item_count)
333 return;
335 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
337 /* Get names of the selected items */
338 valid_count = 0; len_total = 0;
339 for(i = 0; i < item_count; i++)
341 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
342 if(SUCCEEDED(hr))
344 UINT attr;
346 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
347 if(SUCCEEDED(hr) && (attr & SFGAO_FOLDER))
348 continue; /* FIXME: FOS_PICKFOLDERS */
350 hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
351 if(SUCCEEDED(hr))
353 len_total += lstrlenW(names[valid_count]) + 3;
354 valid_count++;
356 IShellItem_Release(psi);
360 if(valid_count == 1)
362 set_file_name(This, names[0]);
363 CoTaskMemFree(names[0]);
365 else if(valid_count > 1)
367 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
368 LPWSTR cur_point = string;
370 for(i = 0; i < valid_count; i++)
372 LPWSTR file = names[i];
373 *cur_point++ = '\"';
374 lstrcpyW(cur_point, file);
375 cur_point += lstrlenW(file);
376 *cur_point++ = '\"';
377 *cur_point++ = ' ';
378 CoTaskMemFree(file);
380 *(cur_point-1) = '\0';
382 set_file_name(This, string);
383 HeapFree(GetProcessHeap(), 0, string);
386 HeapFree(GetProcessHeap(), 0, names);
387 return;
390 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
392 WCHAR *endpos, *ext;
394 lstrcpyW(buf, spec);
395 if( (endpos = StrChrW(buf, ';')) )
396 *endpos = '\0';
398 ext = PathFindExtensionW(buf);
399 if(StrChrW(ext, '*'))
400 return NULL;
402 return ext;
405 static HRESULT on_default_action(FileDialogImpl *This)
407 IShellFolder *psf_parent, *psf_desktop;
408 LPITEMIDLIST *pidla;
409 LPITEMIDLIST current_folder;
410 LPWSTR fn_iter, files, tmp_files;
411 UINT file_count = 0, len, i;
412 int open_action;
413 HRESULT hr, ret = E_FAIL;
415 len = get_file_name(This, &tmp_files);
416 if(len)
418 UINT size_used;
419 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
420 CoTaskMemFree(tmp_files);
422 if(!file_count) return E_FAIL;
424 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
425 if(FAILED(hr))
427 ERR("Failed to get pidl for current directory.\n");
428 return hr;
431 TRACE("Acting on %d file(s).\n", file_count);
433 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
434 open_action = ONOPEN_OPEN;
435 fn_iter = files;
437 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
439 WCHAR canon_filename[MAX_PATH];
440 psf_parent = NULL;
442 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
444 if( (This->options & FOS_NOVALIDATE) &&
445 !(This->options & FOS_FILEMUSTEXIST) )
446 open_action = ONOPEN_OPEN;
447 else
448 open_action = ONOPEN_BROWSE;
450 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
451 This->options & ~FOS_FILEMUSTEXIST,
452 (This->dlg_type == ITEMDLG_TYPE_SAVE),
453 open_action);
455 /* Add the proper extension */
456 if(open_action == ONOPEN_OPEN)
458 static const WCHAR dotW[] = {'.',0};
460 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
462 WCHAR extbuf[MAX_PATH], *newext = NULL;
464 if(This->filterspec_count)
466 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
468 else if(This->default_ext)
470 lstrcpyW(extbuf, dotW);
471 lstrcatW(extbuf, This->default_ext);
472 newext = extbuf;
475 if(newext)
477 WCHAR *ext = PathFindExtensionW(canon_filename);
478 if(lstrcmpW(ext, newext))
479 lstrcatW(canon_filename, newext);
482 else
484 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
485 !PathFileExistsW(canon_filename))
487 if(This->default_ext)
489 lstrcatW(canon_filename, dotW);
490 lstrcatW(canon_filename, This->default_ext);
492 if(!PathFileExistsW(canon_filename))
494 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
495 open_action = ONOPEN_BROWSE;
498 else
500 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
501 open_action = ONOPEN_BROWSE;
507 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
509 if(psf_parent && !(open_action == ONOPEN_BROWSE))
510 IShellFolder_Release(psf_parent);
512 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
515 HeapFree(GetProcessHeap(), 0, files);
516 ILFree(current_folder);
518 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
519 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
521 switch(open_action)
523 case ONOPEN_SEARCH:
524 FIXME("Filtering not implemented.\n");
525 break;
527 case ONOPEN_BROWSE:
528 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
529 if(FAILED(hr))
530 ERR("Failed to browse to directory: %08x\n", hr);
532 IShellFolder_Release(psf_parent);
533 break;
535 case ONOPEN_OPEN:
536 if(events_OnFileOk(This) != S_OK)
537 break;
539 hr = SHGetDesktopFolder(&psf_desktop);
540 if(SUCCEEDED(hr))
542 if(This->psia_results)
543 IShellItemArray_Release(This->psia_results);
545 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
546 &This->psia_results);
547 if(SUCCEEDED(hr))
548 ret = S_OK;
550 IShellFolder_Release(psf_desktop);
552 break;
554 default:
555 ERR("Failed.\n");
556 break;
559 /* Clean up */
560 for(i = 0; i < file_count; i++)
561 ILFree(pidla[i]);
562 HeapFree(GetProcessHeap(), 0, pidla);
564 /* Success closes the dialog */
565 return ret;
568 /**************************************************************************
569 * Control functions.
571 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
573 customctrl *ctrl;
575 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
576 if(ctrl->dlgid == dlgid)
577 return ctrl;
579 ERR("Failed to find control with dialog id %d\n", dlgid);
580 return NULL;
583 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
585 customctrl *ctrl;
587 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
588 if(ctrl->id == ctlid)
589 return ctrl;
591 ERR("Failed to find control with control id %d\n", ctlid);
592 return NULL;
595 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
597 LPWSTR text;
598 UINT len, final_width;
599 UINT lines, final_height;
600 SIZE size;
601 RECT rc;
602 HDC hdc;
603 WCHAR *c;
605 TRACE("\n");
607 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
608 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
609 if(!text) return;
610 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
612 hdc = GetDC(hctrl);
613 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
614 ReleaseDC(hctrl, hdc);
616 if(len && multiline)
618 /* FIXME: line-wrap */
619 for(lines = 1, c = text; *c != '\0'; c++)
620 if(*c == '\n') lines++;
622 final_height = size.cy*lines + 2*4;
624 else
626 GetWindowRect(hctrl, &rc);
627 final_height = rc.bottom - rc.top;
630 final_width = min(max(size.cx, min_width) + 4, max_width);
631 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
632 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
634 HeapFree(GetProcessHeap(), 0, text);
637 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
639 RECT rc;
641 switch(ctrl->type)
643 case IDLG_CCTRL_PUSHBUTTON:
644 case IDLG_CCTRL_COMBOBOX:
645 case IDLG_CCTRL_CHECKBUTTON:
646 case IDLG_CCTRL_TEXT:
647 ctrl_resize(ctrl->hwnd, 160, 160, TRUE);
648 GetWindowRect(ctrl->hwnd, &rc);
649 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
650 SWP_NOZORDER|SWP_NOMOVE|SWP_NOZORDER);
651 break;
652 case IDLG_CCTRL_RADIOBUTTONLIST:
653 case IDLG_CCTRL_EDITBOX:
654 case IDLG_CCTRL_SEPARATOR:
655 case IDLG_CCTRL_MENU:
656 /* Nothing */
657 break;
661 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
663 FileDialogImpl *This = crs->lpCreateParams;
664 TRACE("%p\n", This);
666 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
667 return TRUE;
670 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
672 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
674 TRACE("%p, %lx\n", This, wparam);
676 if(ctrl)
678 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
680 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
681 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
683 else
684 cctrl_event_OnButtonClicked(This, ctrl->id);
687 return TRUE;
690 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
692 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
693 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
695 if(ctrl)
697 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
698 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
700 cctrl_event_OnItemSelected(This, ctrl->id, selid);
702 return TRUE;
705 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
707 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
708 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
709 POINT pt = { 0, nmtb->rcButton.bottom };
710 TBBUTTON tbb;
711 UINT idcmd;
713 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
715 if(ctrl)
717 cctrl_event_OnControlActivating(This,ctrl->id);
719 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
720 ClientToScreen(ctrl->hwnd, &pt);
721 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
722 if(idcmd)
723 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
726 return TBDDRET_DEFAULT;
729 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
731 switch(HIWORD(wparam))
733 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
734 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
737 return FALSE;
740 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
742 NMHDR *nmhdr = (NMHDR*)lparam;
744 switch(nmhdr->code)
746 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
749 return FALSE;
752 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
754 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
755 HWND hwnd_child;
756 RECT rc;
758 switch(message)
760 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
761 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
762 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
763 case WM_SIZE:
764 hwnd_child = GetPropW(hwnd, notifysink_childW);
765 GetClientRect(hwnd, &rc);
766 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
767 return TRUE;
770 return DefWindowProcW(hwnd, message, wparam, lparam);
773 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
774 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
775 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
777 HWND ns_hwnd, control_hwnd;
778 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
779 customctrl *ctrl;
781 if(get_cctrl(This, id))
782 return E_UNEXPECTED; /* Duplicate id */
784 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
785 0, 0, This->cctrl_width, height, This->cctrls_hwnd,
786 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
787 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
788 0, 0, This->cctrl_width, height, ns_hwnd,
789 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
791 if(!ns_hwnd || !control_hwnd)
793 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
794 DestroyWindow(ns_hwnd);
795 DestroyWindow(control_hwnd);
797 return E_FAIL;
800 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
802 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
803 if(!ctrl)
804 return E_OUTOFMEMORY;
806 ctrl->hwnd = control_hwnd;
807 ctrl->wrapper_hwnd = ns_hwnd;
808 ctrl->id = id;
809 ctrl->dlgid = This->cctrl_next_dlgid;
810 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
811 list_add_tail(&This->cctrls, &ctrl->entry);
812 if(ppctrl) *ppctrl = ctrl;
814 This->cctrl_next_dlgid++;
815 return S_OK;
818 /**************************************************************************
819 * Container functions.
821 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
823 UINT container_height;
824 UINT column_width;
825 UINT nr_of_cols;
826 UINT max_control_height, total_height = 0;
827 UINT cur_col_pos, cur_row_pos;
828 customctrl *ctrl;
829 BOOL fits_height;
830 static const UINT col_indent = 100; /* The first column is indented 100px */
831 static const UINT cspacing = 90; /* Columns are spaced with 90px */
832 static const UINT rspacing = 4; /* Rows are spaced with 4 px. */
834 /* Given the new width of the container, this function determines the
835 * needed height of the container and places the controls according to
836 * the new layout. Returns the new height.
839 TRACE("%p\n", This);
841 column_width = This->cctrl_width + cspacing;
842 nr_of_cols = (container_width - col_indent + cspacing) / column_width;
844 /* We don't need to do anything unless the number of visible columns has changed. */
845 if(nr_of_cols == This->cctrls_cols)
847 RECT rc;
848 GetWindowRect(This->cctrls_hwnd, &rc);
849 return rc.bottom - rc.top;
852 This->cctrls_cols = nr_of_cols;
854 /* Get the size of the tallest control, and the total size of
855 * all the controls to figure out the number of slots we need.
857 max_control_height = 0;
858 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
860 if(ctrl->cdcstate & CDCS_VISIBLE)
862 RECT rc;
863 UINT control_height;
864 GetWindowRect(ctrl->wrapper_hwnd, &rc);
865 control_height = rc.bottom - rc.top;
866 max_control_height = max(max_control_height, control_height);
868 total_height += control_height + rspacing;
872 if(!total_height)
873 return 0;
875 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
876 TRACE("Guess: container_height: %d\n",container_height);
878 /* Incrementally increase container_height until all the controls
879 * fit.
881 do {
882 UINT columns_needed = 1;
883 cur_row_pos = 0;
885 fits_height = TRUE;
886 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
888 if(ctrl->cdcstate & CDCS_VISIBLE)
890 RECT rc;
891 UINT control_height;
892 GetWindowRect(ctrl->wrapper_hwnd, &rc);
893 control_height = rc.bottom - rc.top;
895 if(cur_row_pos + control_height > container_height)
897 if(++columns_needed > nr_of_cols)
899 container_height += 1;
900 fits_height = FALSE;
901 break;
903 cur_row_pos = 0;
906 cur_row_pos += control_height + rspacing;
909 } while(!fits_height);
911 TRACE("Final container height: %d\n", container_height);
913 /* Move the controls to their final destination
915 cur_col_pos = col_indent, cur_row_pos = 0;
916 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
918 if(ctrl->cdcstate & CDCS_VISIBLE)
920 RECT rc;
921 UINT control_height;
922 GetWindowRect(ctrl->wrapper_hwnd, &rc);
923 control_height = rc.bottom - rc.top;
925 if(cur_row_pos + control_height > container_height)
927 cur_row_pos = 0;
928 cur_col_pos += This->cctrl_width + cspacing;
931 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos, cur_row_pos, 0, 0,
932 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
934 cur_row_pos += control_height + rspacing;
938 /* Sanity check */
939 if(cur_row_pos + This->cctrl_width > container_width)
940 ERR("-- Failed to place controls properly.\n");
942 return container_height;
945 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
947 LONG wndstyle;
949 if(parent)
951 customctrl *ctrl;
952 HFONT font;
954 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
955 wndstyle &= ~(WS_POPUP);
956 wndstyle |= WS_CHILD;
957 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
959 SetParent(This->cctrls_hwnd, parent);
960 ShowWindow(This->cctrls_hwnd, TRUE);
962 /* Set the fonts to match the dialog font. */
963 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
964 if(!font)
965 ERR("Failed to get font handle from dialog.\n");
967 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
969 if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
970 customctrl_resize(This, ctrl);
973 else
975 ShowWindow(This->cctrls_hwnd, FALSE);
977 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
978 wndstyle &= ~(WS_CHILD);
979 wndstyle |= WS_POPUP;
980 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
982 SetParent(This->cctrls_hwnd, NULL);
986 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
988 FileDialogImpl *This = crs->lpCreateParams;
989 TRACE("%p\n", This);
991 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
992 return TRUE;
995 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
997 customctrl *cur1, *cur2;
998 TRACE("%p\n", This);
1000 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1002 TRACE("Freeing control %p\n", cur1);
1003 list_remove(&cur1->entry);
1005 if(cur1->type == IDLG_CCTRL_MENU)
1007 TBBUTTON tbb;
1008 SendMessageW(cur1->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1009 DestroyMenu((HMENU)tbb.dwData);
1012 DestroyWindow(cur1->hwnd);
1013 HeapFree(GetProcessHeap(), 0, cur1);
1016 return TRUE;
1019 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1021 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1023 switch(umessage)
1025 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1026 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1027 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1030 return FALSE;
1033 static HRESULT init_custom_controls(FileDialogImpl *This)
1035 WNDCLASSW wc;
1036 static const WCHAR ctrl_container_classname[] =
1037 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1039 InitCommonControlsEx(NULL);
1041 This->cctrl_width = 160; /* Controls have a fixed width */
1042 This->cctrl_def_height = 23;
1043 This->cctrls_cols = 0;
1045 This->cctrl_next_dlgid = 0x2000;
1046 list_init(&This->cctrls);
1048 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1050 wc.style = CS_HREDRAW | CS_VREDRAW;
1051 wc.lpfnWndProc = ctrl_container_wndproc;
1052 wc.cbClsExtra = 0;
1053 wc.cbWndExtra = 0;
1054 wc.hInstance = COMDLG32_hInstance;
1055 wc.hIcon = 0;
1056 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1057 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1058 wc.lpszMenuName = NULL;
1059 wc.lpszClassName = ctrl_container_classname;
1061 if(!RegisterClassW(&wc)) return E_FAIL;
1064 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1065 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1066 0, 0, 0, 0, NULL, 0,
1067 COMDLG32_hInstance, (void*)This);
1068 if(!This->cctrls_hwnd)
1069 return E_FAIL;
1071 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1073 /* Register class for */
1074 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1075 wc.hInstance != COMDLG32_hInstance)
1077 wc.style = CS_HREDRAW | CS_VREDRAW;
1078 wc.lpfnWndProc = notifysink_proc;
1079 wc.cbClsExtra = 0;
1080 wc.cbWndExtra = 0;
1081 wc.hInstance = COMDLG32_hInstance;
1082 wc.hIcon = 0;
1083 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1084 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1085 wc.lpszMenuName = NULL;
1086 wc.lpszClassName = floatnotifysinkW;
1088 if (!RegisterClassW(&wc))
1089 ERR("Failed to register FloatNotifySink window class.\n");
1092 return S_OK;
1095 /**************************************************************************
1096 * Window related functions.
1098 static SIZE update_layout(FileDialogImpl *This)
1100 HDWP hdwp;
1101 HWND hwnd;
1102 RECT dialog_rc;
1103 RECT cancel_rc, open_rc;
1104 RECT filetype_rc, filename_rc, filenamelabel_rc;
1105 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1106 int missing_width, missing_height;
1107 static const UINT vspacing = 4, hspacing = 4;
1108 SIZE ret;
1110 GetClientRect(This->dlg_hwnd, &dialog_rc);
1112 missing_width = max(0, 320 - dialog_rc.right);
1113 missing_height = max(0, 200 - dialog_rc.bottom);
1115 if(missing_width || missing_height)
1117 TRACE("Missing (%d, %d)\n", missing_width, missing_height);
1118 ret.cx = missing_width;
1119 ret.cy = missing_height;
1120 return ret;
1123 /****
1124 * Calculate the size of the dialog and all the parts.
1127 /* Cancel button */
1128 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1129 if(hwnd)
1131 int cancel_width, cancel_height;
1132 GetWindowRect(hwnd, &cancel_rc);
1133 cancel_width = cancel_rc.right - cancel_rc.left;
1134 cancel_height = cancel_rc.bottom - cancel_rc.top;
1136 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1137 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1138 cancel_rc.right = cancel_rc.left + cancel_width;
1139 cancel_rc.bottom = cancel_rc.top + cancel_height;
1142 /* Open/Save button */
1143 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1144 if(hwnd)
1146 int open_width, open_height;
1147 GetWindowRect(hwnd, &open_rc);
1148 open_width = open_rc.right - open_rc.left;
1149 open_height = open_rc.bottom - open_rc.top;
1151 open_rc.left = cancel_rc.left - open_width - hspacing;
1152 open_rc.top = cancel_rc.top;
1153 open_rc.right = open_rc.left + open_width;
1154 open_rc.bottom = open_rc.top + open_height;
1157 /* The filetype combobox. */
1158 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1159 if(hwnd)
1161 int filetype_width, filetype_height;
1162 GetWindowRect(hwnd, &filetype_rc);
1164 filetype_width = filetype_rc.right - filetype_rc.left;
1165 filetype_height = filetype_rc.bottom - filetype_rc.top;
1167 filetype_rc.right = cancel_rc.right;
1169 filetype_rc.left = filetype_rc.right - filetype_width;
1170 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1171 filetype_rc.bottom = filetype_rc.top + filetype_height;
1173 if(!This->filterspec_count)
1174 filetype_rc.left = filetype_rc.right;
1177 /* Filename label. */
1178 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1179 if(hwnd)
1181 int filetypelabel_width, filetypelabel_height;
1182 GetWindowRect(hwnd, &filenamelabel_rc);
1184 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1185 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1187 filenamelabel_rc.left = 160; /* FIXME */
1188 filenamelabel_rc.top = filetype_rc.top;
1189 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1190 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1193 /* Filename edit box. */
1194 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1195 if(hwnd)
1197 int filename_width, filename_height;
1198 GetWindowRect(hwnd, &filename_rc);
1200 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1201 filename_height = filename_rc.bottom - filename_rc.top;
1203 filename_rc.left = filenamelabel_rc.right + hspacing;
1204 filename_rc.top = filetype_rc.top;
1205 filename_rc.right = filename_rc.left + filename_width;
1206 filename_rc.bottom = filename_rc.top + filename_height;
1209 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1210 if(hwnd)
1212 GetWindowRect(hwnd, &toolbar_rc);
1213 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1216 /* The custom controls */
1217 customctrls_rc.left = dialog_rc.left + hspacing;
1218 customctrls_rc.right = dialog_rc.right - hspacing;
1219 customctrls_rc.bottom = filename_rc.top - vspacing;
1220 customctrls_rc.top = customctrls_rc.bottom -
1221 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1223 /* The ExplorerBrowser control. */
1224 ebrowser_rc.left = dialog_rc.left + hspacing;
1225 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1226 ebrowser_rc.right = dialog_rc.right - hspacing;
1227 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1229 /****
1230 * Move everything to the right place.
1233 /* FIXME: The Save Dialog uses a slightly different layout. */
1234 hdwp = BeginDeferWindowPos(7);
1236 if(hdwp && This->peb)
1237 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1239 if(hdwp && This->cctrls_hwnd)
1240 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1241 customctrls_rc.left, customctrls_rc.top,
1242 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1243 SWP_NOZORDER | SWP_NOACTIVATE);
1245 /* The default controls */
1246 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1247 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1248 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1250 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1251 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1252 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1253 SWP_NOZORDER | SWP_NOACTIVATE);
1255 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1256 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1257 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1259 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1260 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1261 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1263 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1264 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1265 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1267 if(hdwp)
1268 EndDeferWindowPos(hdwp);
1269 else
1270 ERR("Failed to position dialog controls.\n");
1272 ret.cx = 0; ret.cy = 0;
1273 return ret;
1276 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1278 IShellItem *psi_folder;
1279 FOLDERSETTINGS fos;
1280 RECT rc = {0};
1281 HRESULT hr;
1283 /* Create ExplorerBrowser instance */
1284 OleInitialize(NULL);
1286 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1287 &IID_IExplorerBrowser, (void**)&This->peb);
1288 if(FAILED(hr))
1290 ERR("Failed to instantiate ExplorerBrowser control.\n");
1291 return hr;
1294 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES);
1296 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1297 if(FAILED(hr))
1299 ERR("Failed to initialize the ExplorerBrowser control.\n");
1300 IExplorerBrowser_Release(This->peb);
1301 This->peb = NULL;
1302 return hr;
1304 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1305 if(FAILED(hr))
1306 ERR("Advise (ExplorerBrowser) failed.\n");
1308 /* Get previous options? */
1309 fos.ViewMode = fos.fFlags = 0;
1310 if(!(This->options & FOS_ALLOWMULTISELECT))
1311 fos.fFlags |= FWF_SINGLESEL;
1313 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1315 hr = IUnknown_SetSite((IUnknown*)This->peb, (IUnknown*)This);
1316 if(FAILED(hr))
1317 ERR("SetSite (ExplorerBrowser) failed.\n");
1319 /* Browse somewhere */
1320 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1321 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1323 return S_OK;
1326 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1328 HWND htoolbar;
1329 TBADDBITMAP tbab;
1330 TBBUTTON button[2];
1332 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1333 0, 0, 0, 0,
1334 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1336 tbab.hInst = HINST_COMMCTRL;
1337 tbab.nID = IDB_HIST_LARGE_COLOR;
1338 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1340 button[0].iBitmap = HIST_BACK;
1341 button[0].idCommand = IDC_NAVBACK;
1342 button[0].fsState = TBSTATE_ENABLED;
1343 button[0].fsStyle = BTNS_BUTTON;
1344 button[0].dwData = 0;
1345 button[0].iString = 0;
1347 button[1].iBitmap = HIST_FORWARD;
1348 button[1].idCommand = IDC_NAVFORWARD;
1349 button[1].fsState = TBSTATE_ENABLED;
1350 button[1].fsStyle = BTNS_BUTTON;
1351 button[1].dwData = 0;
1352 button[1].iString = 0;
1354 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1355 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1356 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1359 static void update_control_text(FileDialogImpl *This)
1361 HWND hitem;
1362 if(This->custom_title)
1363 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1365 if(This->custom_okbutton &&
1366 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1368 SetWindowTextW(hitem, This->custom_okbutton);
1369 ctrl_resize(hitem, 50, 250, FALSE);
1372 if(This->custom_cancelbutton &&
1373 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1375 SetWindowTextW(hitem, This->custom_cancelbutton);
1376 ctrl_resize(hitem, 50, 250, FALSE);
1379 if(This->custom_filenamelabel &&
1380 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1382 SetWindowTextW(hitem, This->custom_filenamelabel);
1383 ctrl_resize(hitem, 50, 250, FALSE);
1387 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1389 FileDialogImpl *This = (FileDialogImpl*)lParam;
1390 HWND hitem;
1392 TRACE("(%p, %p)\n", This, hwnd);
1394 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1395 This->dlg_hwnd = hwnd;
1397 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1398 if(hitem) ShowWindow(hitem, SW_HIDE);
1400 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1401 if(hitem) ShowWindow(hitem, SW_HIDE);
1403 /* Fill filetypes combobox, or hide it. */
1404 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1405 if(This->filterspec_count)
1407 UINT i;
1408 for(i = 0; i < This->filterspec_count; i++)
1409 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
1411 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
1413 else
1414 ShowWindow(hitem, SW_HIDE);
1416 if(This->set_filename &&
1417 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1418 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
1420 ctrl_container_reparent(This, This->dlg_hwnd);
1421 init_explorerbrowser(This);
1422 init_toolbar(This, hwnd);
1423 update_control_text(This);
1424 update_layout(This);
1426 return TRUE;
1429 static LRESULT on_wm_size(FileDialogImpl *This)
1431 update_layout(This);
1432 return FALSE;
1435 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
1437 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
1438 TRACE("%p (%p)\n", This, mmi);
1440 /* FIXME */
1441 mmi->ptMinTrackSize.x = 640;
1442 mmi->ptMinTrackSize.y = 480;
1444 return FALSE;
1447 static LRESULT on_wm_destroy(FileDialogImpl *This)
1449 TRACE("%p\n", This);
1451 if(This->peb)
1453 IExplorerBrowser_Destroy(This->peb);
1454 IExplorerBrowser_Release(This->peb);
1455 This->peb = NULL;
1458 ctrl_container_reparent(This, NULL);
1459 This->dlg_hwnd = NULL;
1461 return TRUE;
1464 static LRESULT on_idok(FileDialogImpl *This)
1466 TRACE("%p\n", This);
1468 if(SUCCEEDED(on_default_action(This)))
1469 EndDialog(This->dlg_hwnd, S_OK);
1471 return FALSE;
1474 static LRESULT on_idcancel(FileDialogImpl *This)
1476 TRACE("%p\n", This);
1478 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
1480 return FALSE;
1483 static LRESULT on_browse_back(FileDialogImpl *This)
1485 TRACE("%p\n", This);
1486 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
1487 return FALSE;
1490 static LRESULT on_browse_forward(FileDialogImpl *This)
1492 TRACE("%p\n", This);
1493 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
1494 return FALSE;
1497 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1499 if(HIWORD(wparam) == CBN_SELCHANGE)
1501 IShellView *psv;
1502 HRESULT hr;
1503 LPWSTR filename;
1504 UINT prev_index = This->filetypeindex;
1506 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
1507 TRACE("File type selection changed to %d.\n", This->filetypeindex);
1509 if(prev_index == This->filetypeindex)
1510 return FALSE;
1512 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
1513 if(SUCCEEDED(hr))
1515 IShellView_Refresh(psv);
1516 IShellView_Release(psv);
1519 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
1521 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
1523 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
1524 if(ext)
1526 lstrcpyW(buf, filename);
1528 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
1529 PathRemoveExtensionW(buf);
1531 lstrcatW(buf, ext);
1532 set_file_name(This, buf);
1534 CoTaskMemFree(filename);
1538 return FALSE;
1541 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1543 switch(LOWORD(wparam))
1545 case IDOK: return on_idok(This);
1546 case IDCANCEL: return on_idcancel(This);
1547 case IDC_NAVBACK: return on_browse_back(This);
1548 case IDC_NAVFORWARD: return on_browse_forward(This);
1549 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
1550 default: TRACE("Unknown command.\n");
1552 return FALSE;
1555 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1557 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1559 switch(umessage)
1561 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
1562 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
1563 case WM_SIZE: return on_wm_size(This);
1564 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
1565 case WM_DESTROY: return on_wm_destroy(This);
1568 return FALSE;
1571 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
1573 INT_PTR res;
1575 SetLastError(0);
1576 res = DialogBoxParamW(COMDLG32_hInstance,
1577 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
1578 parent, itemdlg_dlgproc, (LPARAM)This);
1579 This->dlg_hwnd = NULL;
1580 if(res == -1)
1582 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
1583 return E_FAIL;
1586 TRACE("Returning 0x%08x\n", (HRESULT)res);
1587 return (HRESULT)res;
1590 /**************************************************************************
1591 * IFileDialog implementation
1593 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
1595 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
1598 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
1599 REFIID riid,
1600 void **ppvObject)
1602 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1603 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1605 *ppvObject = NULL;
1606 if(IsEqualGUID(riid, &IID_IUnknown) ||
1607 IsEqualGUID(riid, &IID_IFileDialog) ||
1608 IsEqualGUID(riid, &IID_IFileDialog2))
1610 *ppvObject = iface;
1612 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
1614 *ppvObject = &This->u.IFileOpenDialog_iface;
1616 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
1618 *ppvObject = &This->u.IFileSaveDialog_iface;
1620 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
1622 *ppvObject = &This->IExplorerBrowserEvents_iface;
1624 else if(IsEqualGUID(riid, &IID_IServiceProvider))
1626 *ppvObject = &This->IServiceProvider_iface;
1628 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
1629 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
1630 IsEqualGUID(&IID_ICommDlgBrowser, riid))
1632 *ppvObject = &This->ICommDlgBrowser3_iface;
1634 else if(IsEqualGUID(&IID_IOleWindow, riid))
1636 *ppvObject = &This->IOleWindow_iface;
1638 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
1639 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
1641 *ppvObject = &This->IFileDialogCustomize_iface;
1643 else
1644 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
1646 if(*ppvObject)
1648 IUnknown_AddRef((IUnknown*)*ppvObject);
1649 return S_OK;
1652 return E_NOINTERFACE;
1655 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
1657 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1658 LONG ref = InterlockedIncrement(&This->ref);
1659 TRACE("%p - ref %d\n", This, ref);
1661 return ref;
1664 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
1666 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1667 LONG ref = InterlockedDecrement(&This->ref);
1668 TRACE("%p - ref %d\n", This, ref);
1670 if(!ref)
1672 UINT i;
1673 for(i = 0; i < This->filterspec_count; i++)
1675 LocalFree((void*)This->filterspecs[i].pszName);
1676 LocalFree((void*)This->filterspecs[i].pszSpec);
1678 HeapFree(GetProcessHeap(), 0, This->filterspecs);
1680 DestroyWindow(This->cctrls_hwnd);
1682 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
1683 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
1684 if(This->psi_folder) IShellItem_Release(This->psi_folder);
1685 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
1686 if(This->psia_results) IShellItemArray_Release(This->psia_results);
1688 LocalFree(This->set_filename);
1689 LocalFree(This->default_ext);
1690 LocalFree(This->custom_title);
1691 LocalFree(This->custom_okbutton);
1692 LocalFree(This->custom_cancelbutton);
1693 LocalFree(This->custom_filenamelabel);
1695 HeapFree(GetProcessHeap(), 0, This);
1698 return ref;
1701 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
1703 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1704 TRACE("%p (%p)\n", iface, hwndOwner);
1706 return create_dialog(This, hwndOwner);
1709 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
1710 const COMDLG_FILTERSPEC *rgFilterSpec)
1712 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1713 UINT i;
1714 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
1716 if(This->filterspecs)
1717 return E_UNEXPECTED;
1719 if(!rgFilterSpec)
1720 return E_INVALIDARG;
1722 if(!cFileTypes)
1723 return S_OK;
1725 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
1726 for(i = 0; i < cFileTypes; i++)
1728 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
1729 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
1731 This->filterspec_count = cFileTypes;
1733 return S_OK;
1736 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
1738 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1739 TRACE("%p (%d)\n", This, iFileType);
1741 if(!This->filterspecs)
1742 return E_FAIL;
1744 if(iFileType >= This->filterspec_count)
1745 This->filetypeindex = This->filterspec_count - 1;
1746 else
1747 This->filetypeindex = iFileType;
1749 return S_OK;
1752 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
1754 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1755 TRACE("%p (%p)\n", This, piFileType);
1757 if(!piFileType)
1758 return E_INVALIDARG;
1760 *piFileType = This->filetypeindex;
1762 return S_OK;
1765 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
1767 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1768 events_client *client;
1769 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
1771 if(!pfde || !pdwCookie)
1772 return E_INVALIDARG;
1774 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
1775 client->pfde = pfde;
1776 client->cookie = ++This->events_next_cookie;
1778 IFileDialogEvents_AddRef(pfde);
1779 *pdwCookie = client->cookie;
1781 list_add_tail(&This->events_clients, &client->entry);
1783 return S_OK;
1786 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
1788 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1789 events_client *client, *found = NULL;
1790 TRACE("%p (%d)\n", This, dwCookie);
1792 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
1794 if(client->cookie == dwCookie)
1796 found = client;
1797 break;
1801 if(found)
1803 list_remove(&found->entry);
1804 IFileDialogEvents_Release(found->pfde);
1805 HeapFree(GetProcessHeap(), 0, found);
1806 return S_OK;
1809 return E_INVALIDARG;
1812 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
1814 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1815 TRACE("%p (0x%x)\n", This, fos);
1817 This->options = fos;
1819 return S_OK;
1822 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
1824 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1825 TRACE("%p (%p)\n", This, pfos);
1827 if(!pfos)
1828 return E_INVALIDARG;
1830 *pfos = This->options;
1832 return S_OK;
1835 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
1837 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1838 TRACE("%p (%p)\n", This, psi);
1839 if(This->psi_defaultfolder)
1840 IShellItem_Release(This->psi_defaultfolder);
1842 This->psi_defaultfolder = psi;
1844 if(This->psi_defaultfolder)
1845 IShellItem_AddRef(This->psi_defaultfolder);
1847 return S_OK;
1850 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
1852 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1853 TRACE("%p (%p)\n", This, psi);
1854 if(This->psi_setfolder)
1855 IShellItem_Release(This->psi_setfolder);
1857 This->psi_setfolder = psi;
1859 if(This->psi_setfolder)
1860 IShellItem_AddRef(This->psi_setfolder);
1862 return S_OK;
1865 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
1867 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1868 TRACE("%p (%p)\n", This, ppsi);
1869 if(!ppsi)
1870 return E_INVALIDARG;
1872 /* FIXME:
1873 If the dialog is shown, return the current(ly selected) folder. */
1875 *ppsi = NULL;
1876 if(This->psi_folder)
1877 *ppsi = This->psi_folder;
1878 else if(This->psi_setfolder)
1879 *ppsi = This->psi_setfolder;
1880 else if(This->psi_defaultfolder)
1881 *ppsi = This->psi_defaultfolder;
1883 if(*ppsi)
1885 IShellItem_AddRef(*ppsi);
1886 return S_OK;
1889 return E_FAIL;
1892 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
1894 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1895 HRESULT hr;
1896 TRACE("%p (%p)\n", This, ppsi);
1898 if(!ppsi)
1899 return E_INVALIDARG;
1901 if(This->psia_selection)
1903 /* FIXME: Check filename edit box */
1904 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
1905 return hr;
1908 return E_FAIL;
1911 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
1913 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1914 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
1916 set_file_name(This, pszName);
1918 return S_OK;
1921 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
1923 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1924 TRACE("%p (%p)\n", iface, pszName);
1926 if(!pszName)
1927 return E_INVALIDARG;
1929 *pszName = NULL;
1930 if(get_file_name(This, pszName))
1931 return S_OK;
1932 else
1933 return E_FAIL;
1936 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
1938 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1939 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
1941 LocalFree(This->custom_title);
1942 This->custom_title = StrDupW(pszTitle);
1943 update_control_text(This);
1945 return S_OK;
1948 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
1950 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1951 TRACE("%p (%s)\n", This, debugstr_w(pszText));
1953 LocalFree(This->custom_okbutton);
1954 This->custom_okbutton = StrDupW(pszText);
1955 update_control_text(This);
1956 update_layout(This);
1958 return S_OK;
1961 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
1963 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1964 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
1966 LocalFree(This->custom_filenamelabel);
1967 This->custom_filenamelabel = StrDupW(pszLabel);
1968 update_control_text(This);
1969 update_layout(This);
1971 return S_OK;
1974 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
1976 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1977 HRESULT hr;
1978 TRACE("%p (%p)\n", This, ppsi);
1980 if(!ppsi)
1981 return E_INVALIDARG;
1983 if(This->psia_results)
1985 UINT item_count;
1986 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
1987 if(SUCCEEDED(hr))
1989 if(item_count != 1)
1990 return E_FAIL;
1992 /* Adds a reference. */
1993 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
1996 return hr;
1999 return E_UNEXPECTED;
2002 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2004 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2005 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2006 return E_NOTIMPL;
2009 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2011 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2012 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2014 LocalFree(This->default_ext);
2015 This->default_ext = StrDupW(pszDefaultExtension);
2017 return S_OK;
2020 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2022 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2023 TRACE("%p (0x%08x)\n", This, hr);
2025 if(This->dlg_hwnd)
2026 EndDialog(This->dlg_hwnd, hr);
2028 return S_OK;
2031 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2033 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2034 FIXME("stub - %p (%s)\n", This, debugstr_guid(guid));
2035 return E_NOTIMPL;
2038 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2040 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2041 FIXME("stub - %p\n", This);
2042 return E_NOTIMPL;
2045 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2047 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2048 FIXME("stub - %p (%p)\n", This, pFilter);
2049 return E_NOTIMPL;
2052 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2054 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2055 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2057 LocalFree(This->custom_cancelbutton);
2058 This->custom_cancelbutton = StrDupW(pszLabel);
2059 update_control_text(This);
2060 update_layout(This);
2062 return S_OK;
2065 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2067 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2068 FIXME("stub - %p (%p)\n", This, psi);
2069 return E_NOTIMPL;
2072 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2073 IFileDialog2_fnQueryInterface,
2074 IFileDialog2_fnAddRef,
2075 IFileDialog2_fnRelease,
2076 IFileDialog2_fnShow,
2077 IFileDialog2_fnSetFileTypes,
2078 IFileDialog2_fnSetFileTypeIndex,
2079 IFileDialog2_fnGetFileTypeIndex,
2080 IFileDialog2_fnAdvise,
2081 IFileDialog2_fnUnadvise,
2082 IFileDialog2_fnSetOptions,
2083 IFileDialog2_fnGetOptions,
2084 IFileDialog2_fnSetDefaultFolder,
2085 IFileDialog2_fnSetFolder,
2086 IFileDialog2_fnGetFolder,
2087 IFileDialog2_fnGetCurrentSelection,
2088 IFileDialog2_fnSetFileName,
2089 IFileDialog2_fnGetFileName,
2090 IFileDialog2_fnSetTitle,
2091 IFileDialog2_fnSetOkButtonLabel,
2092 IFileDialog2_fnSetFileNameLabel,
2093 IFileDialog2_fnGetResult,
2094 IFileDialog2_fnAddPlace,
2095 IFileDialog2_fnSetDefaultExtension,
2096 IFileDialog2_fnClose,
2097 IFileDialog2_fnSetClientGuid,
2098 IFileDialog2_fnClearClientData,
2099 IFileDialog2_fnSetFilter,
2100 IFileDialog2_fnSetCancelButtonLabel,
2101 IFileDialog2_fnSetNavigationRoot
2104 /**************************************************************************
2105 * IFileOpenDialog
2107 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2109 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2112 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2113 REFIID riid, void **ppvObject)
2115 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2116 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2119 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2121 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2122 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2125 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2127 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2128 return IFileDialog2_Release(&This->IFileDialog2_iface);
2131 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2133 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2134 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2137 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2138 const COMDLG_FILTERSPEC *rgFilterSpec)
2140 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2141 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2144 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2146 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2147 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2150 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2152 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2153 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2156 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2157 DWORD *pdwCookie)
2159 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2160 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2163 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2165 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2166 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2169 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2171 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2172 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2175 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2177 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2178 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2181 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2183 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2184 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2187 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2189 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2190 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2193 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2195 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2196 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2199 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2201 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2202 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2205 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2207 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2208 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2211 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2213 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2214 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2217 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2219 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2220 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2223 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2225 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2226 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2229 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2231 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2232 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2235 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2237 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2238 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2241 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2243 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2244 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2247 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2248 LPCWSTR pszDefaultExtension)
2250 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2251 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2254 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2256 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2257 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2260 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2262 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2263 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2266 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2268 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2269 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2272 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2274 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2275 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2278 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2280 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2281 TRACE("%p (%p)\n", This, ppenum);
2283 *ppenum = This->psia_results;
2285 if(*ppenum)
2287 IShellItemArray_AddRef(*ppenum);
2288 return S_OK;
2291 return E_FAIL;
2294 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2296 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2297 TRACE("%p (%p)\n", This, ppsai);
2299 if(This->psia_selection)
2301 *ppsai = This->psia_selection;
2302 IShellItemArray_AddRef(*ppsai);
2303 return S_OK;
2306 return E_FAIL;
2309 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2310 IFileOpenDialog_fnQueryInterface,
2311 IFileOpenDialog_fnAddRef,
2312 IFileOpenDialog_fnRelease,
2313 IFileOpenDialog_fnShow,
2314 IFileOpenDialog_fnSetFileTypes,
2315 IFileOpenDialog_fnSetFileTypeIndex,
2316 IFileOpenDialog_fnGetFileTypeIndex,
2317 IFileOpenDialog_fnAdvise,
2318 IFileOpenDialog_fnUnadvise,
2319 IFileOpenDialog_fnSetOptions,
2320 IFileOpenDialog_fnGetOptions,
2321 IFileOpenDialog_fnSetDefaultFolder,
2322 IFileOpenDialog_fnSetFolder,
2323 IFileOpenDialog_fnGetFolder,
2324 IFileOpenDialog_fnGetCurrentSelection,
2325 IFileOpenDialog_fnSetFileName,
2326 IFileOpenDialog_fnGetFileName,
2327 IFileOpenDialog_fnSetTitle,
2328 IFileOpenDialog_fnSetOkButtonLabel,
2329 IFileOpenDialog_fnSetFileNameLabel,
2330 IFileOpenDialog_fnGetResult,
2331 IFileOpenDialog_fnAddPlace,
2332 IFileOpenDialog_fnSetDefaultExtension,
2333 IFileOpenDialog_fnClose,
2334 IFileOpenDialog_fnSetClientGuid,
2335 IFileOpenDialog_fnClearClientData,
2336 IFileOpenDialog_fnSetFilter,
2337 IFileOpenDialog_fnGetResults,
2338 IFileOpenDialog_fnGetSelectedItems
2341 /**************************************************************************
2342 * IFileSaveDialog
2344 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
2346 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
2349 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
2350 REFIID riid,
2351 void **ppvObject)
2353 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2354 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2357 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
2359 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2360 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2363 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
2365 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2366 return IFileDialog2_Release(&This->IFileDialog2_iface);
2369 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
2371 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2372 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2375 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
2376 const COMDLG_FILTERSPEC *rgFilterSpec)
2378 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2379 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2382 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
2384 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2385 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2388 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
2390 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2391 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2394 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
2395 DWORD *pdwCookie)
2397 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2398 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2401 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
2403 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2404 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2407 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
2409 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2410 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2413 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2415 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2416 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2419 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
2421 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2422 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2425 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
2427 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2428 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2431 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
2433 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2434 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2437 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
2439 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2440 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2443 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
2445 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2446 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2449 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
2451 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2452 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2455 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
2457 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2458 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2461 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
2463 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2464 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2467 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
2469 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2470 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2473 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
2475 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2476 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2479 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
2481 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2482 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2485 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
2486 LPCWSTR pszDefaultExtension)
2488 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2489 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2492 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
2494 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2495 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2498 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
2500 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2501 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2504 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
2506 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2507 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2510 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
2512 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2513 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2516 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
2518 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2519 FIXME("stub - %p (%p)\n", This, psi);
2520 return E_NOTIMPL;
2523 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
2525 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2526 FIXME("stub - %p (%p)\n", This, pStore);
2527 return E_NOTIMPL;
2530 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
2531 IPropertyDescriptionList *pList,
2532 BOOL fAppendDefault)
2534 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2535 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
2536 return E_NOTIMPL;
2539 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
2541 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2542 FIXME("stub - %p (%p)\n", This, ppStore);
2543 return E_NOTIMPL;
2546 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
2547 IShellItem *psi,
2548 IPropertyStore *pStore,
2549 HWND hwnd,
2550 IFileOperationProgressSink *pSink)
2552 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2553 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
2554 return E_NOTIMPL;
2557 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
2558 IFileSaveDialog_fnQueryInterface,
2559 IFileSaveDialog_fnAddRef,
2560 IFileSaveDialog_fnRelease,
2561 IFileSaveDialog_fnShow,
2562 IFileSaveDialog_fnSetFileTypes,
2563 IFileSaveDialog_fnSetFileTypeIndex,
2564 IFileSaveDialog_fnGetFileTypeIndex,
2565 IFileSaveDialog_fnAdvise,
2566 IFileSaveDialog_fnUnadvise,
2567 IFileSaveDialog_fnSetOptions,
2568 IFileSaveDialog_fnGetOptions,
2569 IFileSaveDialog_fnSetDefaultFolder,
2570 IFileSaveDialog_fnSetFolder,
2571 IFileSaveDialog_fnGetFolder,
2572 IFileSaveDialog_fnGetCurrentSelection,
2573 IFileSaveDialog_fnSetFileName,
2574 IFileSaveDialog_fnGetFileName,
2575 IFileSaveDialog_fnSetTitle,
2576 IFileSaveDialog_fnSetOkButtonLabel,
2577 IFileSaveDialog_fnSetFileNameLabel,
2578 IFileSaveDialog_fnGetResult,
2579 IFileSaveDialog_fnAddPlace,
2580 IFileSaveDialog_fnSetDefaultExtension,
2581 IFileSaveDialog_fnClose,
2582 IFileSaveDialog_fnSetClientGuid,
2583 IFileSaveDialog_fnClearClientData,
2584 IFileSaveDialog_fnSetFilter,
2585 IFileSaveDialog_fnSetSaveAsItem,
2586 IFileSaveDialog_fnSetProperties,
2587 IFileSaveDialog_fnSetCollectedProperties,
2588 IFileSaveDialog_fnGetProperties,
2589 IFileSaveDialog_fnApplyProperties
2592 /**************************************************************************
2593 * IExplorerBrowserEvents implementation
2595 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
2597 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
2600 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
2601 REFIID riid, void **ppvObject)
2603 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2604 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2606 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2609 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
2611 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2612 TRACE("%p\n", This);
2613 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2616 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
2618 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2619 TRACE("%p\n", This);
2620 return IFileDialog2_Release(&This->IFileDialog2_iface);
2623 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
2624 PCIDLIST_ABSOLUTE pidlFolder)
2626 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2627 IShellItem *psi;
2628 HRESULT hr;
2629 TRACE("%p (%p)\n", This, pidlFolder);
2631 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
2632 if(SUCCEEDED(hr))
2634 hr = events_OnFolderChanging(This, psi);
2635 IShellItem_Release(psi);
2637 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
2638 if(hr == S_FALSE)
2639 hr = E_FAIL;
2641 return hr;
2643 else
2644 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
2646 return S_OK;
2649 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
2650 IShellView *psv)
2652 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2653 TRACE("%p (%p)\n", This, psv);
2654 return S_OK;
2657 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
2658 PCIDLIST_ABSOLUTE pidlFolder)
2660 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2661 HRESULT hr;
2662 TRACE("%p (%p)\n", This, pidlFolder);
2664 if(This->psi_folder)
2665 IShellItem_Release(This->psi_folder);
2667 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
2668 if(FAILED(hr))
2670 ERR("Failed to get the current folder.\n");
2671 This->psi_folder = NULL;
2674 events_OnFolderChange(This);
2676 return S_OK;
2679 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
2680 PCIDLIST_ABSOLUTE pidlFolder)
2682 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2683 TRACE("%p (%p)\n", This, pidlFolder);
2684 return S_OK;
2687 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
2688 IExplorerBrowserEvents_fnQueryInterface,
2689 IExplorerBrowserEvents_fnAddRef,
2690 IExplorerBrowserEvents_fnRelease,
2691 IExplorerBrowserEvents_fnOnNavigationPending,
2692 IExplorerBrowserEvents_fnOnViewCreated,
2693 IExplorerBrowserEvents_fnOnNavigationComplete,
2694 IExplorerBrowserEvents_fnOnNavigationFailed
2697 /**************************************************************************
2698 * IServiceProvider implementation
2700 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2702 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
2705 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
2706 REFIID riid, void **ppvObject)
2708 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2709 TRACE("%p\n", This);
2710 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2713 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
2715 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2716 TRACE("%p\n", This);
2717 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2720 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
2722 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2723 TRACE("%p\n", This);
2724 return IFileDialog2_Release(&This->IFileDialog2_iface);
2727 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
2728 REFGUID guidService,
2729 REFIID riid, void **ppv)
2731 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2732 HRESULT hr = E_NOTIMPL;
2733 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
2735 *ppv = NULL;
2736 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
2737 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
2738 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
2739 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
2740 else
2741 FIXME("Interface %s requested from unknown service %s\n",
2742 debugstr_guid(riid), debugstr_guid(guidService));
2744 return hr;
2747 static const IServiceProviderVtbl vt_IServiceProvider = {
2748 IServiceProvider_fnQueryInterface,
2749 IServiceProvider_fnAddRef,
2750 IServiceProvider_fnRelease,
2751 IServiceProvider_fnQueryService
2754 /**************************************************************************
2755 * ICommDlgBrowser3 implementation
2757 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
2759 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
2762 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
2763 REFIID riid, void **ppvObject)
2765 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2766 TRACE("%p\n", This);
2767 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2770 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
2772 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2773 TRACE("%p\n", This);
2774 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2777 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
2779 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2780 TRACE("%p\n", This);
2781 return IFileDialog2_Release(&This->IFileDialog2_iface);
2784 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
2785 IShellView *shv)
2787 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2788 HRESULT hr;
2789 TRACE("%p (%p)\n", This, shv);
2791 hr = on_default_action(This);
2793 if(SUCCEEDED(hr))
2794 EndDialog(This->dlg_hwnd, S_OK);
2796 return S_OK;
2799 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
2800 IShellView *shv, ULONG uChange )
2802 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2803 IDataObject *new_selection;
2804 HRESULT hr;
2805 TRACE("%p (%p, %x)\n", This, shv, uChange);
2807 switch(uChange)
2809 case CDBOSC_SELCHANGE:
2810 if(This->psia_selection)
2812 IShellItemArray_Release(This->psia_selection);
2813 This->psia_selection = NULL;
2816 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
2817 if(SUCCEEDED(hr))
2819 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
2820 (void**)&This->psia_selection);
2821 if(SUCCEEDED(hr))
2823 fill_filename_from_selection(This);
2824 events_OnSelectionChange(This);
2827 IDataObject_Release(new_selection);
2829 break;
2830 default:
2831 TRACE("Unhandled state change\n");
2833 return S_OK;
2836 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
2837 IShellView *shv, LPCITEMIDLIST pidl)
2839 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2840 IShellItem *psi;
2841 LPWSTR filename;
2842 LPITEMIDLIST parent_pidl;
2843 HRESULT hr;
2844 ULONG attr;
2845 TRACE("%p (%p, %p)\n", This, shv, pidl);
2847 if(!This->filterspec_count)
2848 return S_OK;
2850 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
2851 if(SUCCEEDED(hr))
2853 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
2854 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
2855 ILFree(parent_pidl);
2856 ILFree(full_pidl);
2858 if(FAILED(hr))
2860 ERR("Failed to get shellitem (%08x).\n", hr);
2861 return S_OK;
2864 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
2865 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
2867 IShellItem_Release(psi);
2868 return S_OK;
2871 hr = S_OK;
2872 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
2874 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
2875 hr = S_FALSE;
2876 CoTaskMemFree(filename);
2879 IShellItem_Release(psi);
2880 return hr;
2883 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
2884 IShellView *ppshv, DWORD dwNotifyType)
2886 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2887 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
2888 return E_NOTIMPL;
2891 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
2892 IShellView *pshv,
2893 LPWSTR pszText, int cchMax)
2895 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2896 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
2897 return E_NOTIMPL;
2900 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
2902 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2903 FIXME("Stub: %p (%p)\n", This, pdwFlags);
2904 return E_NOTIMPL;
2907 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
2908 IShellView *pshv, int iColumn)
2910 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2911 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
2912 return E_NOTIMPL;
2915 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
2916 LPWSTR pszFileSpec, int cchFileSpec)
2918 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2919 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
2920 return E_NOTIMPL;
2923 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
2924 IShellView *pshv)
2926 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2927 FIXME("Stub: %p (%p)\n", This, pshv);
2928 return E_NOTIMPL;
2931 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
2932 ICommDlgBrowser3_fnQueryInterface,
2933 ICommDlgBrowser3_fnAddRef,
2934 ICommDlgBrowser3_fnRelease,
2935 ICommDlgBrowser3_fnOnDefaultCommand,
2936 ICommDlgBrowser3_fnOnStateChange,
2937 ICommDlgBrowser3_fnIncludeObject,
2938 ICommDlgBrowser3_fnNotify,
2939 ICommDlgBrowser3_fnGetDefaultMenuText,
2940 ICommDlgBrowser3_fnGetViewFlags,
2941 ICommDlgBrowser3_fnOnColumnClicked,
2942 ICommDlgBrowser3_fnGetCurrentFilter,
2943 ICommDlgBrowser3_fnOnPreviewCreated
2946 /**************************************************************************
2947 * IOleWindow implementation
2949 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
2951 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
2954 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
2956 FileDialogImpl *This = impl_from_IOleWindow(iface);
2957 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2960 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
2962 FileDialogImpl *This = impl_from_IOleWindow(iface);
2963 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2966 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
2968 FileDialogImpl *This = impl_from_IOleWindow(iface);
2969 return IFileDialog2_Release(&This->IFileDialog2_iface);
2972 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
2974 FileDialogImpl *This = impl_from_IOleWindow(iface);
2975 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
2976 return E_NOTIMPL;
2979 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
2981 FileDialogImpl *This = impl_from_IOleWindow(iface);
2982 TRACE("%p (%p)\n", This, phwnd);
2983 *phwnd = This->dlg_hwnd;
2984 return S_OK;
2987 static const IOleWindowVtbl vt_IOleWindow = {
2988 IOleWindow_fnQueryInterface,
2989 IOleWindow_fnAddRef,
2990 IOleWindow_fnRelease,
2991 IOleWindow_fnGetWindow,
2992 IOleWindow_fnContextSensitiveHelp
2995 /**************************************************************************
2996 * IFileDialogCustomize implementation
2998 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3000 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3003 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3004 REFIID riid, void **ppvObject)
3006 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3007 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3010 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3012 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3013 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3016 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3018 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3019 return IFileDialog2_Release(&This->IFileDialog2_iface);
3022 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3023 DWORD dwIDCtl)
3025 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3026 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3027 return E_NOTIMPL;
3030 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3031 DWORD dwIDCtl,
3032 LPCWSTR pszLabel)
3034 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3035 customctrl *ctrl;
3036 TBBUTTON tbb;
3037 HRESULT hr;
3038 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3040 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3041 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3042 This->cctrl_def_height, &ctrl);
3043 if(SUCCEEDED(hr))
3045 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3046 ctrl->type = IDLG_CCTRL_MENU;
3048 /* Add the actual button with a popup menu. */
3049 tbb.iBitmap = I_IMAGENONE;
3050 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3051 tbb.iString = (DWORD_PTR)pszLabel;
3052 tbb.fsState = TBSTATE_ENABLED;
3053 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3054 tbb.idCommand = 1;
3056 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3059 return hr;
3062 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3063 DWORD dwIDCtl,
3064 LPCWSTR pszLabel)
3066 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3067 customctrl *ctrl;
3068 HRESULT hr;
3069 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3071 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3072 This->cctrl_def_height, &ctrl);
3073 if(SUCCEEDED(hr))
3074 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3076 return hr;
3079 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3080 DWORD dwIDCtl)
3082 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3083 customctrl *ctrl;
3084 HRESULT hr;
3085 TRACE("%p (%d)\n", This, dwIDCtl);
3087 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3088 This->cctrl_def_height, &ctrl);
3089 if(SUCCEEDED(hr))
3090 ctrl->type = IDLG_CCTRL_COMBOBOX;
3092 return hr;
3095 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3096 DWORD dwIDCtl)
3098 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3099 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3100 return E_NOTIMPL;
3103 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3104 DWORD dwIDCtl,
3105 LPCWSTR pszLabel,
3106 BOOL bChecked)
3108 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3109 customctrl *ctrl;
3110 HRESULT hr;
3111 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3113 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX, 0,
3114 This->cctrl_def_height, &ctrl);
3115 if(SUCCEEDED(hr))
3117 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3118 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3121 return hr;
3124 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3125 DWORD dwIDCtl,
3126 LPCWSTR pszText)
3128 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3129 customctrl *ctrl;
3130 HRESULT hr;
3131 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3133 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3134 This->cctrl_def_height, &ctrl);
3135 if(SUCCEEDED(hr))
3136 ctrl->type = IDLG_CCTRL_EDITBOX;
3138 return hr;
3141 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3142 DWORD dwIDCtl)
3144 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3145 customctrl *ctrl;
3146 HRESULT hr;
3147 TRACE("%p (%d)\n", This, dwIDCtl);
3149 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3150 GetSystemMetrics(SM_CYEDGE), &ctrl);
3151 if(SUCCEEDED(hr))
3152 ctrl->type = IDLG_CCTRL_SEPARATOR;
3154 return hr;
3157 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3158 DWORD dwIDCtl,
3159 LPCWSTR pszText)
3161 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3162 customctrl *ctrl;
3163 HRESULT hr;
3164 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3166 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3167 This->cctrl_def_height, &ctrl);
3168 if(SUCCEEDED(hr))
3169 ctrl->type = IDLG_CCTRL_TEXT;
3171 return hr;
3174 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3175 DWORD dwIDCtl,
3176 LPCWSTR pszLabel)
3178 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3179 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3180 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3182 if(!ctrl) return E_INVALIDARG;
3184 switch(ctrl->type)
3186 case IDLG_CCTRL_MENU:
3187 case IDLG_CCTRL_PUSHBUTTON:
3188 case IDLG_CCTRL_CHECKBUTTON:
3189 case IDLG_CCTRL_TEXT:
3190 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3191 break;
3192 default:
3193 break;
3196 return S_OK;
3199 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3200 DWORD dwIDCtl,
3201 CDCONTROLSTATEF *pdwState)
3203 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3204 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3205 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3207 if(!ctrl) return E_NOTIMPL;
3209 *pdwState = ctrl->cdcstate;
3210 return S_OK;
3213 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3214 DWORD dwIDCtl,
3215 CDCONTROLSTATEF dwState)
3217 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3218 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3219 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3221 if(ctrl)
3223 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3225 if(dwState & CDCS_ENABLED)
3226 wndstyle &= ~(WS_DISABLED);
3227 else
3228 wndstyle |= WS_DISABLED;
3230 if(dwState & CDCS_VISIBLE)
3231 wndstyle |= WS_VISIBLE;
3232 else
3233 wndstyle &= ~(WS_VISIBLE);
3235 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3237 /* We save the state separately since at least one application
3238 * relies on being able to hide a control. */
3239 ctrl->cdcstate = dwState;
3242 return S_OK;
3245 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3246 DWORD dwIDCtl,
3247 WCHAR **ppszText)
3249 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3250 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3251 WCHAR len, *text;
3252 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
3254 if(!ctrl || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3255 return E_FAIL;
3257 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3258 if(!text) return E_FAIL;
3260 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3261 *ppszText = text;
3262 return S_OK;
3265 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
3266 DWORD dwIDCtl,
3267 LPCWSTR pszText)
3269 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3270 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3271 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
3273 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
3274 return E_FAIL;
3276 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
3277 return S_OK;
3280 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
3281 DWORD dwIDCtl,
3282 BOOL *pbChecked)
3284 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3285 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3286 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
3288 if(ctrl)
3289 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
3291 return S_OK;
3294 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
3295 DWORD dwIDCtl,
3296 BOOL bChecked)
3298 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3299 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3300 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
3302 if(ctrl)
3303 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
3305 return S_OK;
3308 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
3310 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
3311 UINT i;
3312 if(!count || (count == CB_ERR))
3313 return -1;
3315 for(i = 0; i < count; i++)
3316 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3317 return i;
3319 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
3320 return -1;
3323 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
3324 DWORD dwIDCtl,
3325 DWORD dwIDItem,
3326 LPCWSTR pszLabel)
3328 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3329 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3330 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3332 if(!ctrl) return E_FAIL;
3334 switch(ctrl->type)
3336 case IDLG_CCTRL_COMBOBOX:
3338 UINT index;
3340 if(get_combobox_index_from_id(ctrl->hwnd, dwIDItem) != -1)
3341 return E_INVALIDARG;
3343 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
3344 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
3346 return S_OK;
3348 case IDLG_CCTRL_MENU:
3350 TBBUTTON tbb;
3351 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3353 if(GetMenuState((HMENU)tbb.dwData, dwIDItem, MF_BYCOMMAND) != -1)
3354 return E_INVALIDARG;
3356 AppendMenuW((HMENU)tbb.dwData, MF_STRING, dwIDItem, pszLabel);
3357 return S_OK;
3359 default:
3360 break;
3363 return E_NOINTERFACE; /* win7 */
3366 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
3367 DWORD dwIDCtl,
3368 DWORD dwIDItem)
3370 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3371 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3372 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3374 if(!ctrl) return E_FAIL;
3376 switch(ctrl->type)
3378 case IDLG_CCTRL_COMBOBOX:
3380 UINT i, count = SendMessageW(ctrl->hwnd, CB_GETCOUNT, 0, 0);
3381 if(!count || (count == CB_ERR))
3382 return E_FAIL;
3384 for(i = 0; i < count; i++)
3385 if(SendMessageW(ctrl->hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3387 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, i, 0) == CB_ERR)
3388 return E_FAIL;
3389 return S_OK;
3392 return E_UNEXPECTED;
3394 case IDLG_CCTRL_MENU:
3396 TBBUTTON tbb;
3397 HMENU hmenu;
3398 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3399 hmenu = (HMENU)tbb.dwData;
3401 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
3402 return E_UNEXPECTED;
3404 return S_OK;
3406 default:
3407 break;
3410 return E_FAIL;
3413 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
3414 DWORD dwIDCtl)
3416 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3417 TRACE("%p (%d)\n", This, dwIDCtl);
3419 /* Not implemented by native */
3420 return E_NOTIMPL;
3423 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
3424 DWORD dwIDCtl,
3425 DWORD dwIDItem,
3426 CDCONTROLSTATEF *pdwState)
3428 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3429 FIXME("stub - %p\n", This);
3430 return E_NOTIMPL;
3433 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
3434 DWORD dwIDCtl,
3435 DWORD dwIDItem,
3436 CDCONTROLSTATEF dwState)
3438 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3439 FIXME("stub - %p\n", This);
3440 return E_NOTIMPL;
3443 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
3444 DWORD dwIDCtl,
3445 DWORD *pdwIDItem)
3447 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3448 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3449 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
3451 if(!ctrl) return E_FAIL;
3453 switch(ctrl->type)
3455 case IDLG_CCTRL_COMBOBOX:
3457 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
3458 if(index == CB_ERR)
3459 return E_FAIL;
3461 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
3462 return S_OK;
3464 default:
3465 FIXME("Unsupported control type %d\n", ctrl->type);
3468 return E_NOTIMPL;
3471 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
3472 DWORD dwIDCtl,
3473 DWORD dwIDItem)
3475 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3476 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3477 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3479 if(!ctrl) return E_INVALIDARG;
3481 switch(ctrl->type)
3483 case IDLG_CCTRL_COMBOBOX:
3485 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
3487 if(index == -1)
3488 return E_INVALIDARG;
3490 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
3491 return E_FAIL;
3493 return S_OK;
3495 default:
3496 FIXME("Unsupported control type %d\n", ctrl->type);
3499 return E_INVALIDARG;
3502 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
3503 DWORD dwIDCtl,
3504 LPCWSTR pszLabel)
3506 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3507 FIXME("stub - %p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
3508 return E_NOTIMPL;
3511 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
3513 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3514 FIXME("stub - %p\n", This);
3515 return E_NOTIMPL;
3518 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
3519 DWORD dwIDCtl)
3521 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3522 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3523 return E_NOTIMPL;
3526 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
3527 DWORD dwIDCtl,
3528 DWORD dwIDItem,
3529 LPCWSTR pszLabel)
3531 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3532 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3533 return E_NOTIMPL;
3536 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
3537 IFileDialogCustomize_fnQueryInterface,
3538 IFileDialogCustomize_fnAddRef,
3539 IFileDialogCustomize_fnRelease,
3540 IFileDialogCustomize_fnEnableOpenDropDown,
3541 IFileDialogCustomize_fnAddMenu,
3542 IFileDialogCustomize_fnAddPushButton,
3543 IFileDialogCustomize_fnAddComboBox,
3544 IFileDialogCustomize_fnAddRadioButtonList,
3545 IFileDialogCustomize_fnAddCheckButton,
3546 IFileDialogCustomize_fnAddEditBox,
3547 IFileDialogCustomize_fnAddSeparator,
3548 IFileDialogCustomize_fnAddText,
3549 IFileDialogCustomize_fnSetControlLabel,
3550 IFileDialogCustomize_fnGetControlState,
3551 IFileDialogCustomize_fnSetControlState,
3552 IFileDialogCustomize_fnGetEditBoxText,
3553 IFileDialogCustomize_fnSetEditBoxText,
3554 IFileDialogCustomize_fnGetCheckButtonState,
3555 IFileDialogCustomize_fnSetCheckButtonState,
3556 IFileDialogCustomize_fnAddControlItem,
3557 IFileDialogCustomize_fnRemoveControlItem,
3558 IFileDialogCustomize_fnRemoveAllControlItems,
3559 IFileDialogCustomize_fnGetControlItemState,
3560 IFileDialogCustomize_fnSetControlItemState,
3561 IFileDialogCustomize_fnGetSelectedControlItem,
3562 IFileDialogCustomize_fnSetSelectedControlItem,
3563 IFileDialogCustomize_fnStartVisualGroup,
3564 IFileDialogCustomize_fnEndVisualGroup,
3565 IFileDialogCustomize_fnMakeProminent,
3566 IFileDialogCustomize_fnSetControlItemText
3569 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
3571 FileDialogImpl *fdimpl;
3572 HRESULT hr;
3573 IShellFolder *psf;
3574 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
3576 if(!ppv)
3577 return E_POINTER;
3578 if(pUnkOuter)
3579 return CLASS_E_NOAGGREGATION;
3581 fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
3582 if(!fdimpl)
3583 return E_OUTOFMEMORY;
3585 fdimpl->ref = 1;
3586 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
3587 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
3588 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
3589 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
3590 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
3591 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
3593 if(type == ITEMDLG_TYPE_OPEN)
3595 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
3596 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
3597 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
3598 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
3600 else
3602 WCHAR buf[16];
3603 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
3604 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
3605 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
3607 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
3608 fdimpl->custom_title = StrDupW(buf);
3609 fdimpl->custom_okbutton = StrDupW(buf);
3612 fdimpl->filterspecs = NULL;
3613 fdimpl->filterspec_count = 0;
3614 fdimpl->filetypeindex = 0;
3616 fdimpl->psia_selection = fdimpl->psia_results = NULL;
3617 fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
3619 list_init(&fdimpl->events_clients);
3620 fdimpl->events_next_cookie = 0;
3622 fdimpl->dlg_hwnd = NULL;
3623 fdimpl->peb = NULL;
3625 fdimpl->set_filename = NULL;
3626 fdimpl->default_ext = NULL;
3627 fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL;
3629 /* FIXME: The default folder setting should be restored for the
3630 * application if it was previously set. */
3631 SHGetDesktopFolder(&psf);
3632 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
3633 IShellFolder_Release(psf);
3635 hr = init_custom_controls(fdimpl);
3636 if(FAILED(hr))
3638 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
3639 IUnknown_Release((IUnknown*)fdimpl);
3640 return E_FAIL;
3643 hr = IUnknown_QueryInterface((IUnknown*)fdimpl, riid, ppv);
3644 IUnknown_Release((IUnknown*)fdimpl);
3645 return hr;
3648 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3650 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
3653 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3655 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);