msvcp60: Synchronize the spec file.
[wine/multimedia.git] / dlls / comdlg32 / itemdlg.c
blob354e9527e4156c6d036780a825d20332947ce252
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);
421 if(!file_count) return E_FAIL;
423 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
424 if(FAILED(hr))
426 ERR("Failed to get pidl for current directory.\n");
427 return hr;
430 TRACE("Acting on %d file(s).\n", file_count);
432 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
433 open_action = ONOPEN_OPEN;
434 fn_iter = files;
436 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
438 WCHAR canon_filename[MAX_PATH];
439 psf_parent = NULL;
441 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
443 if( (This->options & FOS_NOVALIDATE) &&
444 !(This->options & FOS_FILEMUSTEXIST) )
445 open_action = ONOPEN_OPEN;
446 else
447 open_action = ONOPEN_BROWSE;
449 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
450 This->options & ~FOS_FILEMUSTEXIST,
451 (This->dlg_type == ITEMDLG_TYPE_SAVE),
452 open_action);
454 /* Add the proper extension */
455 if(open_action == ONOPEN_OPEN)
457 static const WCHAR dotW[] = {'.',0};
459 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
461 WCHAR extbuf[MAX_PATH], *newext = NULL;
463 if(This->filterspec_count)
465 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
467 else if(This->default_ext)
469 lstrcpyW(extbuf, dotW);
470 lstrcatW(extbuf, This->default_ext);
471 newext = extbuf;
474 if(newext)
476 WCHAR *ext = PathFindExtensionW(canon_filename);
477 if(lstrcmpW(ext, newext))
478 lstrcatW(canon_filename, newext);
481 else
483 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
484 !PathFileExistsW(canon_filename))
486 if(This->default_ext)
488 lstrcatW(canon_filename, dotW);
489 lstrcatW(canon_filename, This->default_ext);
491 if(!PathFileExistsW(canon_filename))
493 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
494 open_action = ONOPEN_BROWSE;
497 else
499 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
500 open_action = ONOPEN_BROWSE;
506 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
508 if(psf_parent && !(open_action == ONOPEN_BROWSE))
509 IShellItem_Release(psf_parent);
511 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
514 HeapFree(GetProcessHeap(), 0, files);
515 ILFree(current_folder);
517 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
518 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
520 switch(open_action)
522 case ONOPEN_SEARCH:
523 FIXME("Filtering not implemented.\n");
524 break;
526 case ONOPEN_BROWSE:
527 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
528 if(FAILED(hr))
529 ERR("Failed to browse to directory: %08x\n", hr);
531 IShellItem_Release(psf_parent);
532 break;
534 case ONOPEN_OPEN:
535 if(events_OnFileOk(This) != S_OK)
536 break;
538 hr = SHGetDesktopFolder(&psf_desktop);
539 if(SUCCEEDED(hr))
541 if(This->psia_results)
542 IShellItemArray_Release(This->psia_results);
544 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
545 &This->psia_results);
546 if(SUCCEEDED(hr))
547 ret = S_OK;
549 IShellFolder_Release(psf_desktop);
551 break;
553 default:
554 ERR("Failed.\n");
555 break;
558 /* Clean up */
559 for(i = 0; i < file_count; i++)
560 ILFree(pidla[i]);
561 HeapFree(GetProcessHeap(), 0, pidla);
563 /* Success closes the dialog */
564 return ret;
567 /**************************************************************************
568 * Control functions.
570 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
572 customctrl *ctrl;
574 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
575 if(ctrl->dlgid == dlgid)
576 return ctrl;
578 ERR("Failed to find control with dialog id %d\n", dlgid);
579 return NULL;
582 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
584 customctrl *ctrl;
586 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
587 if(ctrl->id == ctlid)
588 return ctrl;
590 ERR("Failed to find control with control id %d\n", ctlid);
591 return NULL;
594 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
596 LPWSTR text;
597 UINT len, final_width;
598 UINT lines, final_height;
599 SIZE size;
600 RECT rc;
601 HDC hdc;
602 WCHAR *c;
604 TRACE("\n");
606 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
607 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
608 if(!text) return;
609 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
611 hdc = GetDC(hctrl);
612 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
613 ReleaseDC(hctrl, hdc);
615 if(len && multiline)
617 /* FIXME: line-wrap */
618 for(lines = 1, c = text; *c != '\0'; c++)
619 if(*c == '\n') lines++;
621 final_height = size.cy*lines + 2*4;
623 else
625 GetWindowRect(hctrl, &rc);
626 final_height = rc.bottom - rc.top;
629 final_width = min(max(size.cx, min_width) + 4, max_width);
630 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
631 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
633 HeapFree(GetProcessHeap(), 0, text);
636 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
638 RECT rc;
640 switch(ctrl->type)
642 case IDLG_CCTRL_PUSHBUTTON:
643 case IDLG_CCTRL_COMBOBOX:
644 case IDLG_CCTRL_CHECKBUTTON:
645 case IDLG_CCTRL_TEXT:
646 ctrl_resize(ctrl->hwnd, 160, 160, TRUE);
647 GetWindowRect(ctrl->hwnd, &rc);
648 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
649 SWP_NOZORDER|SWP_NOMOVE|SWP_NOZORDER);
650 case IDLG_CCTRL_RADIOBUTTONLIST:
651 case IDLG_CCTRL_EDITBOX:
652 case IDLG_CCTRL_SEPARATOR:
653 case IDLG_CCTRL_MENU:
654 /* Nothing */
655 break;
659 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
661 FileDialogImpl *This = crs->lpCreateParams;
662 TRACE("%p\n", This);
664 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
665 return TRUE;
668 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
670 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
672 TRACE("%p, %lx\n", This, wparam);
674 if(ctrl)
676 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
678 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
679 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
681 else
682 cctrl_event_OnButtonClicked(This, ctrl->id);
685 return TRUE;
688 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
690 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
691 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
693 if(ctrl)
695 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
696 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
698 cctrl_event_OnItemSelected(This, ctrl->id, selid);
700 return TRUE;
703 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
705 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
706 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
707 POINT pt = { 0, nmtb->rcButton.bottom };
708 TBBUTTON tbb;
709 UINT idcmd;
711 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
713 if(ctrl)
715 cctrl_event_OnControlActivating(This,ctrl->id);
717 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
718 ClientToScreen(ctrl->hwnd, &pt);
719 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
720 if(idcmd)
721 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
724 return TBDDRET_DEFAULT;
727 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
729 switch(HIWORD(wparam))
731 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
732 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
735 return FALSE;
738 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
740 NMHDR *nmhdr = (NMHDR*)lparam;
742 switch(nmhdr->code)
744 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
747 return FALSE;
750 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
752 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
753 HWND hwnd_child;
754 RECT rc;
756 switch(message)
758 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
759 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
760 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
761 case WM_SIZE:
762 hwnd_child = GetPropW(hwnd, notifysink_childW);
763 GetClientRect(hwnd, &rc);
764 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
765 return TRUE;
768 return DefWindowProcW(hwnd, message, wparam, lparam);
771 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
772 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
773 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
775 HWND ns_hwnd, control_hwnd;
776 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
777 customctrl *ctrl;
779 if(get_cctrl(This, id))
780 return E_UNEXPECTED; /* Duplicate id */
782 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
783 0, 0, This->cctrl_width, height, This->cctrls_hwnd,
784 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
785 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
786 0, 0, This->cctrl_width, height, ns_hwnd,
787 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
789 if(!ns_hwnd || !control_hwnd)
791 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
792 DestroyWindow(ns_hwnd);
793 DestroyWindow(control_hwnd);
795 return E_FAIL;
798 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
800 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
801 if(!ctrl)
802 return E_OUTOFMEMORY;
804 ctrl->hwnd = control_hwnd;
805 ctrl->wrapper_hwnd = ns_hwnd;
806 ctrl->id = id;
807 ctrl->dlgid = This->cctrl_next_dlgid;
808 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
809 list_add_tail(&This->cctrls, &ctrl->entry);
810 if(ppctrl) *ppctrl = ctrl;
812 This->cctrl_next_dlgid++;
813 return S_OK;
816 /**************************************************************************
817 * Container functions.
819 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
821 UINT container_height;
822 UINT column_width;
823 UINT nr_of_cols;
824 UINT max_control_height, total_height = 0;
825 UINT cur_col_pos, cur_row_pos;
826 customctrl *ctrl;
827 BOOL fits_height;
828 static const UINT col_indent = 100; /* The first column is indented 100px */
829 static const UINT cspacing = 90; /* Columns are spaced with 90px */
830 static const UINT rspacing = 4; /* Rows are spaced with 4 px. */
832 /* Given the new width of the container, this function determines the
833 * needed height of the container and places the controls according to
834 * the new layout. Returns the new height.
837 TRACE("%p\n", This);
839 column_width = This->cctrl_width + cspacing;
840 nr_of_cols = (container_width - col_indent + cspacing) / column_width;
842 /* We don't need to do anything unless the number of visible columns has changed. */
843 if(nr_of_cols == This->cctrls_cols)
845 RECT rc;
846 GetWindowRect(This->cctrls_hwnd, &rc);
847 return rc.bottom - rc.top;
850 This->cctrls_cols = nr_of_cols;
852 /* Get the size of the tallest control, and the total size of
853 * all the controls to figure out the number of slots we need.
855 max_control_height = 0;
856 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
858 if(ctrl->cdcstate & CDCS_VISIBLE)
860 RECT rc;
861 UINT control_height;
862 GetWindowRect(ctrl->wrapper_hwnd, &rc);
863 control_height = rc.bottom - rc.top;
864 max_control_height = max(max_control_height, control_height);
866 total_height += control_height + rspacing;
870 if(!total_height)
871 return 0;
873 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
874 TRACE("Guess: container_height: %d\n",container_height);
876 /* Incrementally increase container_height until all the controls
877 * fit.
879 do {
880 UINT columns_needed = 1;
881 cur_row_pos = 0;
883 fits_height = TRUE;
884 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
886 if(ctrl->cdcstate & CDCS_VISIBLE)
888 RECT rc;
889 UINT control_height;
890 GetWindowRect(ctrl->wrapper_hwnd, &rc);
891 control_height = rc.bottom - rc.top;
893 if(cur_row_pos + control_height > container_height)
895 if(++columns_needed > nr_of_cols)
897 container_height += 1;
898 fits_height = FALSE;
899 break;
901 cur_row_pos = 0;
904 cur_row_pos += control_height + rspacing;
907 } while(!fits_height);
909 TRACE("Final container height: %d\n", container_height);
911 /* Move the controls to their final destination
913 cur_col_pos = col_indent, cur_row_pos = 0;
914 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
916 if(ctrl->cdcstate & CDCS_VISIBLE)
918 RECT rc;
919 UINT control_height;
920 GetWindowRect(ctrl->wrapper_hwnd, &rc);
921 control_height = rc.bottom - rc.top;
923 if(cur_row_pos + control_height > container_height)
925 cur_row_pos = 0;
926 cur_col_pos += This->cctrl_width + cspacing;
929 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos, cur_row_pos, 0, 0,
930 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
932 cur_row_pos += control_height + rspacing;
936 /* Sanity check */
937 if(cur_row_pos + This->cctrl_width > container_width)
938 ERR("-- Failed to place controls properly.\n");
940 return container_height;
943 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
945 LONG wndstyle;
947 if(parent)
949 customctrl *ctrl;
950 HFONT font;
952 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
953 wndstyle &= ~(WS_POPUP);
954 wndstyle |= WS_CHILD;
955 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
957 SetParent(This->cctrls_hwnd, parent);
958 ShowWindow(This->cctrls_hwnd, TRUE);
960 /* Set the fonts to match the dialog font. */
961 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
962 if(!font)
963 ERR("Failed to get font handle from dialog.\n");
965 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
967 if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
968 customctrl_resize(This, ctrl);
971 else
973 ShowWindow(This->cctrls_hwnd, FALSE);
975 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
976 wndstyle &= ~(WS_CHILD);
977 wndstyle |= WS_POPUP;
978 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
980 SetParent(This->cctrls_hwnd, NULL);
984 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
986 FileDialogImpl *This = crs->lpCreateParams;
987 TRACE("%p\n", This);
989 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
990 return TRUE;
993 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
995 customctrl *cur1, *cur2;
996 TRACE("%p", This);
998 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1000 TRACE("Freeing control %p\n", cur1);
1001 list_remove(&cur1->entry);
1003 if(cur1->type == IDLG_CCTRL_MENU)
1005 TBBUTTON tbb;
1006 SendMessageW(cur1->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1007 DestroyMenu((HMENU)tbb.dwData);
1010 DestroyWindow(cur1->hwnd);
1011 HeapFree(GetProcessHeap(), 0, cur1);
1014 return TRUE;
1017 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1019 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1021 switch(umessage)
1023 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1024 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1025 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1028 return FALSE;
1031 static HRESULT init_custom_controls(FileDialogImpl *This)
1033 WNDCLASSW wc;
1034 static const WCHAR ctrl_container_classname[] =
1035 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1037 InitCommonControlsEx(NULL);
1039 This->cctrl_width = 160; /* Controls have a fixed width */
1040 This->cctrl_def_height = 23;
1041 This->cctrls_cols = 0;
1043 This->cctrl_next_dlgid = 0x2000;
1044 list_init(&This->cctrls);
1046 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1048 wc.style = CS_HREDRAW | CS_VREDRAW;
1049 wc.lpfnWndProc = ctrl_container_wndproc;
1050 wc.cbClsExtra = 0;
1051 wc.cbWndExtra = 0;
1052 wc.hInstance = COMDLG32_hInstance;
1053 wc.hIcon = 0;
1054 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1055 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1056 wc.lpszMenuName = NULL;
1057 wc.lpszClassName = ctrl_container_classname;
1059 if(!RegisterClassW(&wc)) return E_FAIL;
1062 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1063 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1064 0, 0, 0, 0, NULL, 0,
1065 COMDLG32_hInstance, (void*)This);
1066 if(!This->cctrls_hwnd)
1067 return E_FAIL;
1069 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1071 /* Register class for */
1072 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1073 wc.hInstance != COMDLG32_hInstance)
1075 wc.style = CS_HREDRAW | CS_VREDRAW;
1076 wc.lpfnWndProc = notifysink_proc;
1077 wc.cbClsExtra = 0;
1078 wc.cbWndExtra = 0;
1079 wc.hInstance = COMDLG32_hInstance;
1080 wc.hIcon = 0;
1081 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1082 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1083 wc.lpszMenuName = NULL;
1084 wc.lpszClassName = floatnotifysinkW;
1086 if (!RegisterClassW(&wc))
1087 ERR("Failed to register FloatNotifySink window class.\n");
1090 return S_OK;
1093 /**************************************************************************
1094 * Window related functions.
1096 static SIZE update_layout(FileDialogImpl *This)
1098 HDWP hdwp;
1099 HWND hwnd;
1100 RECT dialog_rc;
1101 RECT cancel_rc, open_rc;
1102 RECT filetype_rc, filename_rc, filenamelabel_rc;
1103 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1104 int missing_width, missing_height;
1105 static const UINT vspacing = 4, hspacing = 4;
1106 SIZE ret;
1108 GetClientRect(This->dlg_hwnd, &dialog_rc);
1110 missing_width = max(0, 320 - dialog_rc.right);
1111 missing_height = max(0, 200 - dialog_rc.bottom);
1113 if(missing_width || missing_height)
1115 TRACE("Missing (%d, %d)\n", missing_width, missing_height);
1116 ret.cx = missing_width;
1117 ret.cy = missing_height;
1118 return ret;
1121 /****
1122 * Calculate the size of the dialog and all the parts.
1125 /* Cancel button */
1126 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1127 if(hwnd)
1129 int cancel_width, cancel_height;
1130 GetWindowRect(hwnd, &cancel_rc);
1131 cancel_width = cancel_rc.right - cancel_rc.left;
1132 cancel_height = cancel_rc.bottom - cancel_rc.top;
1134 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1135 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1136 cancel_rc.right = cancel_rc.left + cancel_width;
1137 cancel_rc.bottom = cancel_rc.top + cancel_height;
1140 /* Open/Save button */
1141 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1142 if(hwnd)
1144 int open_width, open_height;
1145 GetWindowRect(hwnd, &open_rc);
1146 open_width = open_rc.right - open_rc.left;
1147 open_height = open_rc.bottom - open_rc.top;
1149 open_rc.left = cancel_rc.left - open_width - hspacing;
1150 open_rc.top = cancel_rc.top;
1151 open_rc.right = open_rc.left + open_width;
1152 open_rc.bottom = open_rc.top + open_height;
1155 /* The filetype combobox. */
1156 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1157 if(hwnd)
1159 int filetype_width, filetype_height;
1160 GetWindowRect(hwnd, &filetype_rc);
1162 filetype_width = filetype_rc.right - filetype_rc.left;
1163 filetype_height = filetype_rc.bottom - filetype_rc.top;
1165 filetype_rc.right = cancel_rc.right;
1167 filetype_rc.left = filetype_rc.right - filetype_width;
1168 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1169 filetype_rc.bottom = filetype_rc.top + filetype_height;
1171 if(!This->filterspec_count)
1172 filetype_rc.left = filetype_rc.right;
1175 /* Filename label. */
1176 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1177 if(hwnd)
1179 int filetypelabel_width, filetypelabel_height;
1180 GetWindowRect(hwnd, &filenamelabel_rc);
1182 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1183 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1185 filenamelabel_rc.left = 160; /* FIXME */
1186 filenamelabel_rc.top = filetype_rc.top;
1187 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1188 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1191 /* Filename edit box. */
1192 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1193 if(hwnd)
1195 int filename_width, filename_height;
1196 GetWindowRect(hwnd, &filename_rc);
1198 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1199 filename_height = filename_rc.bottom - filename_rc.top;
1201 filename_rc.left = filenamelabel_rc.right + hspacing;
1202 filename_rc.top = filetype_rc.top;
1203 filename_rc.right = filename_rc.left + filename_width;
1204 filename_rc.bottom = filename_rc.top + filename_height;
1207 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1208 if(hwnd)
1210 GetWindowRect(hwnd, &toolbar_rc);
1211 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1214 /* The custom controls */
1215 customctrls_rc.left = dialog_rc.left + vspacing;
1216 customctrls_rc.right = dialog_rc.right - vspacing;
1217 customctrls_rc.bottom = filename_rc.top - hspacing;
1218 customctrls_rc.top = customctrls_rc.bottom -
1219 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1221 /* The ExplorerBrowser control. */
1222 ebrowser_rc.left = dialog_rc.left + vspacing;
1223 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1224 ebrowser_rc.right = dialog_rc.right - hspacing;
1225 ebrowser_rc.bottom = customctrls_rc.top - hspacing;
1227 /****
1228 * Move everything to the right place.
1231 /* FIXME: The Save Dialog uses a slightly different layout. */
1232 hdwp = BeginDeferWindowPos(7);
1234 if(hdwp && This->peb)
1235 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1237 if(hdwp && This->cctrls_hwnd)
1238 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1239 customctrls_rc.left, customctrls_rc.top,
1240 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1241 SWP_NOZORDER | SWP_NOACTIVATE);
1243 /* The default controls */
1244 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1245 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1246 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1248 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1249 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1250 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1251 SWP_NOZORDER | SWP_NOACTIVATE);
1253 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1254 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1255 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1257 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1258 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1259 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1261 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1262 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1263 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1265 if(hdwp)
1266 EndDeferWindowPos(hdwp);
1267 else
1268 ERR("Failed to position dialog controls.\n");
1270 ret.cx = 0; ret.cy = 0;
1271 return ret;
1274 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1276 IShellItem *psi_folder;
1277 FOLDERSETTINGS fos;
1278 RECT rc = {0};
1279 HRESULT hr;
1281 /* Create ExplorerBrowser instance */
1282 OleInitialize(NULL);
1284 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1285 &IID_IExplorerBrowser, (void**)&This->peb);
1286 if(FAILED(hr))
1288 ERR("Failed to instantiate ExplorerBrowser control.\n");
1289 return hr;
1292 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES);
1294 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1295 if(FAILED(hr))
1297 ERR("Failed to initialize the ExplorerBrowser control.\n");
1298 IExplorerBrowser_Release(This->peb);
1299 This->peb = NULL;
1300 return hr;
1302 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1303 if(FAILED(hr))
1304 ERR("Advise (ExplorerBrowser) failed.\n");
1306 /* Get previous options? */
1307 fos.ViewMode = fos.fFlags = 0;
1308 if(!(This->options & FOS_ALLOWMULTISELECT))
1309 fos.fFlags |= FWF_SINGLESEL;
1311 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1313 hr = IUnknown_SetSite((IUnknown*)This->peb, (IUnknown*)This);
1314 if(FAILED(hr))
1315 ERR("SetSite (ExplorerBrowser) failed.\n");
1317 /* Browse somewhere */
1318 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1319 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1321 return S_OK;
1324 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1326 HWND htoolbar;
1327 TBADDBITMAP tbab;
1328 TBBUTTON button[2];
1330 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1331 0, 0, 0, 0,
1332 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1334 tbab.hInst = HINST_COMMCTRL;
1335 tbab.nID = IDB_HIST_LARGE_COLOR;
1336 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1338 button[0].iBitmap = HIST_BACK;
1339 button[0].idCommand = IDC_NAVBACK;
1340 button[0].fsState = TBSTATE_ENABLED;
1341 button[0].fsStyle = BTNS_BUTTON;
1342 button[0].dwData = 0;
1343 button[0].iString = 0;
1345 button[1].iBitmap = HIST_FORWARD;
1346 button[1].idCommand = IDC_NAVFORWARD;
1347 button[1].fsState = TBSTATE_ENABLED;
1348 button[1].fsStyle = BTNS_BUTTON;
1349 button[1].dwData = 0;
1350 button[1].iString = 0;
1352 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)&button);
1353 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1354 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1357 static void update_control_text(FileDialogImpl *This)
1359 HWND hitem;
1360 if(This->custom_title)
1361 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1363 if(This->custom_okbutton &&
1364 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1366 SetWindowTextW(hitem, This->custom_okbutton);
1367 ctrl_resize(hitem, 50, 250, FALSE);
1370 if(This->custom_cancelbutton &&
1371 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1373 SetWindowTextW(hitem, This->custom_cancelbutton);
1374 ctrl_resize(hitem, 50, 250, FALSE);
1377 if(This->custom_filenamelabel &&
1378 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1380 SetWindowTextW(hitem, This->custom_filenamelabel);
1381 ctrl_resize(hitem, 50, 250, FALSE);
1385 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1387 FileDialogImpl *This = (FileDialogImpl*)lParam;
1388 HWND hitem;
1390 TRACE("(%p, %p)\n", This, hwnd);
1392 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1393 This->dlg_hwnd = hwnd;
1395 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1396 if(hitem) ShowWindow(hitem, SW_HIDE);
1398 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1399 if(hitem) ShowWindow(hitem, SW_HIDE);
1401 /* Fill filetypes combobox, or hide it. */
1402 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1403 if(This->filterspec_count)
1405 UINT i;
1406 for(i = 0; i < This->filterspec_count; i++)
1407 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
1409 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
1411 else
1412 ShowWindow(hitem, SW_HIDE);
1414 if(This->set_filename &&
1415 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1416 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
1418 ctrl_container_reparent(This, This->dlg_hwnd);
1419 init_explorerbrowser(This);
1420 init_toolbar(This, hwnd);
1421 update_control_text(This);
1422 update_layout(This);
1424 return TRUE;
1427 static LRESULT on_wm_size(FileDialogImpl *This)
1429 update_layout(This);
1430 return FALSE;
1433 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
1435 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
1436 TRACE("%p (%p)\n", This, mmi);
1438 /* FIXME */
1439 mmi->ptMinTrackSize.x = 640;
1440 mmi->ptMinTrackSize.y = 480;
1442 return FALSE;
1445 static LRESULT on_wm_destroy(FileDialogImpl *This)
1447 TRACE("%p\n", This);
1449 if(This->peb)
1451 IExplorerBrowser_Destroy(This->peb);
1452 IExplorerBrowser_Release(This->peb);
1453 This->peb = NULL;
1456 ctrl_container_reparent(This, NULL);
1457 This->dlg_hwnd = NULL;
1459 return TRUE;
1462 static LRESULT on_idok(FileDialogImpl *This)
1464 TRACE("%p\n", This);
1466 if(SUCCEEDED(on_default_action(This)))
1467 EndDialog(This->dlg_hwnd, S_OK);
1469 return FALSE;
1472 static LRESULT on_idcancel(FileDialogImpl *This)
1474 TRACE("%p\n", This);
1476 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
1478 return FALSE;
1481 static LRESULT on_browse_back(FileDialogImpl *This)
1483 TRACE("%p\n", This);
1484 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
1485 return FALSE;
1488 static LRESULT on_browse_forward(FileDialogImpl *This)
1490 TRACE("%p\n", This);
1491 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
1492 return FALSE;
1495 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1497 if(HIWORD(wparam) == CBN_SELCHANGE)
1499 IShellView *psv;
1500 HRESULT hr;
1501 LPWSTR filename;
1502 UINT prev_index = This->filetypeindex;
1504 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
1505 TRACE("File type selection changed to %d.\n", This->filetypeindex);
1507 if(prev_index == This->filetypeindex)
1508 return FALSE;
1510 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
1511 if(SUCCEEDED(hr))
1513 IShellView_Refresh(psv);
1514 IShellView_Release(psv);
1517 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
1519 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
1521 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
1522 if(ext)
1524 lstrcpyW(buf, filename);
1526 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
1527 PathRemoveExtensionW(buf);
1529 lstrcatW(buf, ext);
1530 set_file_name(This, buf);
1532 CoTaskMemFree(filename);
1536 return FALSE;
1539 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1541 switch(LOWORD(wparam))
1543 case IDOK: return on_idok(This);
1544 case IDCANCEL: return on_idcancel(This);
1545 case IDC_NAVBACK: return on_browse_back(This);
1546 case IDC_NAVFORWARD: return on_browse_forward(This);
1547 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
1548 default: TRACE("Unknown command.\n");
1550 return FALSE;
1553 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1555 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1557 switch(umessage)
1559 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
1560 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
1561 case WM_SIZE: return on_wm_size(This);
1562 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
1563 case WM_DESTROY: return on_wm_destroy(This);
1566 return FALSE;
1569 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
1571 INT_PTR res;
1573 SetLastError(0);
1574 res = DialogBoxParamW(COMDLG32_hInstance,
1575 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
1576 parent, itemdlg_dlgproc, (LPARAM)This);
1577 This->dlg_hwnd = NULL;
1578 if(res == -1)
1580 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
1581 return E_FAIL;
1584 TRACE("Returning 0x%08x\n", (HRESULT)res);
1585 return (HRESULT)res;
1588 /**************************************************************************
1589 * IFileDialog implementation
1591 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
1593 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
1596 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
1597 REFIID riid,
1598 void **ppvObject)
1600 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1601 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1603 *ppvObject = NULL;
1604 if(IsEqualGUID(riid, &IID_IUnknown) ||
1605 IsEqualGUID(riid, &IID_IFileDialog) ||
1606 IsEqualGUID(riid, &IID_IFileDialog2))
1608 *ppvObject = iface;
1610 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
1612 *ppvObject = &This->u.IFileOpenDialog_iface;
1614 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
1616 *ppvObject = &This->u.IFileSaveDialog_iface;
1618 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
1620 *ppvObject = &This->IExplorerBrowserEvents_iface;
1622 else if(IsEqualGUID(riid, &IID_IServiceProvider))
1624 *ppvObject = &This->IServiceProvider_iface;
1626 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
1627 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
1628 IsEqualGUID(&IID_ICommDlgBrowser, riid))
1630 *ppvObject = &This->ICommDlgBrowser3_iface;
1632 else if(IsEqualGUID(&IID_IOleWindow, riid))
1634 *ppvObject = &This->IOleWindow_iface;
1636 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
1637 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
1639 *ppvObject = &This->IFileDialogCustomize_iface;
1641 else
1642 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
1644 if(*ppvObject)
1646 IUnknown_AddRef((IUnknown*)*ppvObject);
1647 return S_OK;
1650 return E_NOINTERFACE;
1653 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
1655 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1656 LONG ref = InterlockedIncrement(&This->ref);
1657 TRACE("%p - ref %d\n", This, ref);
1659 return ref;
1662 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
1664 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1665 LONG ref = InterlockedDecrement(&This->ref);
1666 TRACE("%p - ref %d\n", This, ref);
1668 if(!ref)
1670 UINT i;
1671 for(i = 0; i < This->filterspec_count; i++)
1673 LocalFree((void*)This->filterspecs[i].pszName);
1674 LocalFree((void*)This->filterspecs[i].pszSpec);
1676 HeapFree(GetProcessHeap(), 0, This->filterspecs);
1678 DestroyWindow(This->cctrls_hwnd);
1680 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
1681 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
1682 if(This->psi_folder) IShellItem_Release(This->psi_folder);
1683 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
1684 if(This->psia_results) IShellItemArray_Release(This->psia_results);
1686 LocalFree(This->set_filename);
1687 LocalFree(This->default_ext);
1688 LocalFree(This->custom_title);
1689 LocalFree(This->custom_okbutton);
1690 LocalFree(This->custom_cancelbutton);
1691 LocalFree(This->custom_filenamelabel);
1693 HeapFree(GetProcessHeap(), 0, This);
1696 return ref;
1699 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
1701 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1702 TRACE("%p (%p)\n", iface, hwndOwner);
1704 return create_dialog(This, hwndOwner);
1707 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
1708 const COMDLG_FILTERSPEC *rgFilterSpec)
1710 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1711 UINT i;
1712 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
1714 if(This->filterspecs)
1715 return E_UNEXPECTED;
1717 if(!rgFilterSpec)
1718 return E_INVALIDARG;
1720 if(!cFileTypes)
1721 return S_OK;
1723 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
1724 for(i = 0; i < cFileTypes; i++)
1726 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
1727 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
1729 This->filterspec_count = cFileTypes;
1731 return S_OK;
1734 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
1736 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1737 TRACE("%p (%d)\n", This, iFileType);
1739 if(!This->filterspecs)
1740 return E_FAIL;
1742 if(iFileType >= This->filterspec_count)
1743 This->filetypeindex = This->filterspec_count - 1;
1744 else
1745 This->filetypeindex = iFileType;
1747 return S_OK;
1750 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
1752 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1753 TRACE("%p (%p)\n", This, piFileType);
1755 if(!piFileType)
1756 return E_INVALIDARG;
1758 *piFileType = This->filetypeindex;
1760 return S_OK;
1763 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
1765 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1766 events_client *client;
1767 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
1769 if(!pfde || !pdwCookie)
1770 return E_INVALIDARG;
1772 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
1773 client->pfde = pfde;
1774 client->cookie = ++This->events_next_cookie;
1776 IFileDialogEvents_AddRef(pfde);
1777 *pdwCookie = client->cookie;
1779 list_add_tail(&This->events_clients, &client->entry);
1781 return S_OK;
1784 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
1786 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1787 events_client *client, *found = NULL;
1788 TRACE("%p (%d)\n", This, dwCookie);
1790 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
1792 if(client->cookie == dwCookie)
1794 found = client;
1795 break;
1799 if(found)
1801 list_remove(&found->entry);
1802 IFileDialogEvents_Release(found->pfde);
1803 HeapFree(GetProcessHeap(), 0, found);
1804 return S_OK;
1807 return E_INVALIDARG;
1810 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
1812 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1813 TRACE("%p (0x%x)\n", This, fos);
1815 This->options = fos;
1817 return S_OK;
1820 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
1822 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1823 TRACE("%p (%p)\n", This, pfos);
1825 if(!pfos)
1826 return E_INVALIDARG;
1828 *pfos = This->options;
1830 return S_OK;
1833 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
1835 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1836 TRACE("%p (%p)\n", This, psi);
1837 if(This->psi_defaultfolder)
1838 IShellItem_Release(This->psi_defaultfolder);
1840 This->psi_defaultfolder = psi;
1842 if(This->psi_defaultfolder)
1843 IShellItem_AddRef(This->psi_defaultfolder);
1845 return S_OK;
1848 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
1850 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1851 TRACE("%p (%p)\n", This, psi);
1852 if(This->psi_setfolder)
1853 IShellItem_Release(This->psi_setfolder);
1855 This->psi_setfolder = psi;
1857 if(This->psi_setfolder)
1858 IShellItem_AddRef(This->psi_setfolder);
1860 return S_OK;
1863 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
1865 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1866 TRACE("%p (%p)\n", This, ppsi);
1867 if(!ppsi)
1868 return E_INVALIDARG;
1870 /* FIXME:
1871 If the dialog is shown, return the current(ly selected) folder. */
1873 *ppsi = NULL;
1874 if(This->psi_folder)
1875 *ppsi = This->psi_folder;
1876 else if(This->psi_setfolder)
1877 *ppsi = This->psi_setfolder;
1878 else if(This->psi_defaultfolder)
1879 *ppsi = This->psi_defaultfolder;
1881 if(*ppsi)
1883 IShellItem_AddRef(*ppsi);
1884 return S_OK;
1887 return E_FAIL;
1890 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
1892 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1893 HRESULT hr;
1894 TRACE("%p (%p)\n", This, ppsi);
1896 if(!ppsi)
1897 return E_INVALIDARG;
1899 if(This->psia_selection)
1901 /* FIXME: Check filename edit box */
1902 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
1903 return hr;
1906 return E_FAIL;
1909 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
1911 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1912 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
1914 set_file_name(This, pszName);
1916 return S_OK;
1919 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
1921 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1922 TRACE("%p (%p)\n", iface, pszName);
1924 if(!pszName)
1925 return E_INVALIDARG;
1927 *pszName = NULL;
1928 if(get_file_name(This, pszName))
1929 return S_OK;
1930 else
1931 return E_FAIL;
1934 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
1936 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1937 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
1939 LocalFree(This->custom_title);
1940 This->custom_title = StrDupW(pszTitle);
1941 update_control_text(This);
1943 return S_OK;
1946 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
1948 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1949 TRACE("%p (%s)\n", This, debugstr_w(pszText));
1951 LocalFree(This->custom_okbutton);
1952 This->custom_okbutton = StrDupW(pszText);
1953 update_control_text(This);
1954 update_layout(This);
1956 return S_OK;
1959 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
1961 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1962 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
1964 LocalFree(This->custom_filenamelabel);
1965 This->custom_filenamelabel = StrDupW(pszLabel);
1966 update_control_text(This);
1967 update_layout(This);
1969 return S_OK;
1972 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
1974 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1975 HRESULT hr;
1976 TRACE("%p (%p)\n", This, ppsi);
1978 if(!ppsi)
1979 return E_INVALIDARG;
1981 if(This->psia_results)
1983 UINT item_count;
1984 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
1985 if(SUCCEEDED(hr))
1987 if(item_count != 1)
1988 return E_FAIL;
1990 /* Adds a reference. */
1991 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
1994 return hr;
1997 return E_UNEXPECTED;
2000 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2002 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2003 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2004 return E_NOTIMPL;
2007 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2009 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2010 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2012 LocalFree(This->default_ext);
2013 This->default_ext = StrDupW(pszDefaultExtension);
2015 return S_OK;
2018 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2020 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2021 TRACE("%p (0x%08x)\n", This, hr);
2023 if(This->dlg_hwnd)
2024 EndDialog(This->dlg_hwnd, hr);
2026 return S_OK;
2029 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2031 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2032 FIXME("stub - %p (%s)\n", This, debugstr_guid(guid));
2033 return E_NOTIMPL;
2036 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2038 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2039 FIXME("stub - %p\n", This);
2040 return E_NOTIMPL;
2043 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2045 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2046 FIXME("stub - %p (%p)\n", This, pFilter);
2047 return E_NOTIMPL;
2050 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2052 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2053 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2055 LocalFree(This->custom_cancelbutton);
2056 This->custom_cancelbutton = StrDupW(pszLabel);
2057 update_control_text(This);
2058 update_layout(This);
2060 return S_OK;
2063 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2065 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2066 FIXME("stub - %p (%p)\n", This, psi);
2067 return E_NOTIMPL;
2070 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2071 IFileDialog2_fnQueryInterface,
2072 IFileDialog2_fnAddRef,
2073 IFileDialog2_fnRelease,
2074 IFileDialog2_fnShow,
2075 IFileDialog2_fnSetFileTypes,
2076 IFileDialog2_fnSetFileTypeIndex,
2077 IFileDialog2_fnGetFileTypeIndex,
2078 IFileDialog2_fnAdvise,
2079 IFileDialog2_fnUnadvise,
2080 IFileDialog2_fnSetOptions,
2081 IFileDialog2_fnGetOptions,
2082 IFileDialog2_fnSetDefaultFolder,
2083 IFileDialog2_fnSetFolder,
2084 IFileDialog2_fnGetFolder,
2085 IFileDialog2_fnGetCurrentSelection,
2086 IFileDialog2_fnSetFileName,
2087 IFileDialog2_fnGetFileName,
2088 IFileDialog2_fnSetTitle,
2089 IFileDialog2_fnSetOkButtonLabel,
2090 IFileDialog2_fnSetFileNameLabel,
2091 IFileDialog2_fnGetResult,
2092 IFileDialog2_fnAddPlace,
2093 IFileDialog2_fnSetDefaultExtension,
2094 IFileDialog2_fnClose,
2095 IFileDialog2_fnSetClientGuid,
2096 IFileDialog2_fnClearClientData,
2097 IFileDialog2_fnSetFilter,
2098 IFileDialog2_fnSetCancelButtonLabel,
2099 IFileDialog2_fnSetNavigationRoot
2102 /**************************************************************************
2103 * IFileOpenDialog
2105 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2107 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2110 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2111 REFIID riid, void **ppvObject)
2113 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2114 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2117 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2119 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2120 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2123 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2125 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2126 return IFileDialog2_Release(&This->IFileDialog2_iface);
2129 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2131 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2132 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2135 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2136 const COMDLG_FILTERSPEC *rgFilterSpec)
2138 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2139 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2142 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2144 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2145 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2148 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2150 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2151 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2154 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2155 DWORD *pdwCookie)
2157 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2158 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2161 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2163 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2164 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2167 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2169 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2170 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2173 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2175 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2176 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2179 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2181 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2182 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2185 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2187 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2188 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2191 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2193 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2194 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2197 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2199 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2200 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2203 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2205 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2206 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2209 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2211 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2212 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2215 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2217 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2218 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2221 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2223 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2224 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2227 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2229 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2230 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2233 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2235 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2236 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2239 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2241 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2242 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2245 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2246 LPCWSTR pszDefaultExtension)
2248 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2249 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2252 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2254 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2255 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2258 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2260 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2261 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2264 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2266 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2267 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2270 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2272 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2273 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2276 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2278 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2279 TRACE("%p (%p)\n", This, ppenum);
2281 *ppenum = This->psia_results;
2283 if(*ppenum)
2285 IShellItemArray_AddRef(*ppenum);
2286 return S_OK;
2289 return E_FAIL;
2292 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2294 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2295 TRACE("%p (%p)\n", This, ppsai);
2297 if(This->psia_selection)
2299 *ppsai = This->psia_selection;
2300 IShellItemArray_AddRef(*ppsai);
2301 return S_OK;
2304 return E_FAIL;
2307 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2308 IFileOpenDialog_fnQueryInterface,
2309 IFileOpenDialog_fnAddRef,
2310 IFileOpenDialog_fnRelease,
2311 IFileOpenDialog_fnShow,
2312 IFileOpenDialog_fnSetFileTypes,
2313 IFileOpenDialog_fnSetFileTypeIndex,
2314 IFileOpenDialog_fnGetFileTypeIndex,
2315 IFileOpenDialog_fnAdvise,
2316 IFileOpenDialog_fnUnadvise,
2317 IFileOpenDialog_fnSetOptions,
2318 IFileOpenDialog_fnGetOptions,
2319 IFileOpenDialog_fnSetDefaultFolder,
2320 IFileOpenDialog_fnSetFolder,
2321 IFileOpenDialog_fnGetFolder,
2322 IFileOpenDialog_fnGetCurrentSelection,
2323 IFileOpenDialog_fnSetFileName,
2324 IFileOpenDialog_fnGetFileName,
2325 IFileOpenDialog_fnSetTitle,
2326 IFileOpenDialog_fnSetOkButtonLabel,
2327 IFileOpenDialog_fnSetFileNameLabel,
2328 IFileOpenDialog_fnGetResult,
2329 IFileOpenDialog_fnAddPlace,
2330 IFileOpenDialog_fnSetDefaultExtension,
2331 IFileOpenDialog_fnClose,
2332 IFileOpenDialog_fnSetClientGuid,
2333 IFileOpenDialog_fnClearClientData,
2334 IFileOpenDialog_fnSetFilter,
2335 IFileOpenDialog_fnGetResults,
2336 IFileOpenDialog_fnGetSelectedItems
2339 /**************************************************************************
2340 * IFileSaveDialog
2342 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
2344 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
2347 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
2348 REFIID riid,
2349 void **ppvObject)
2351 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2352 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2355 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
2357 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2358 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2361 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
2363 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2364 return IFileDialog2_Release(&This->IFileDialog2_iface);
2367 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
2369 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2370 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2373 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
2374 const COMDLG_FILTERSPEC *rgFilterSpec)
2376 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2377 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2380 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
2382 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2383 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2386 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
2388 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2389 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2392 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
2393 DWORD *pdwCookie)
2395 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2396 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2399 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
2401 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2402 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2405 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
2407 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2408 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2411 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2413 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2414 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2417 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
2419 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2420 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2423 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
2425 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2426 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2429 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
2431 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2432 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2435 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
2437 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2438 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2441 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
2443 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2444 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2447 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
2449 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2450 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2453 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
2455 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2456 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2459 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
2461 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2462 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2465 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
2467 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2468 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2471 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
2473 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2474 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2477 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
2479 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2480 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2483 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
2484 LPCWSTR pszDefaultExtension)
2486 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2487 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2490 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
2492 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2493 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2496 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
2498 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2499 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2502 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
2504 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2505 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2508 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
2510 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2511 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2514 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
2516 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2517 FIXME("stub - %p (%p)\n", This, psi);
2518 return E_NOTIMPL;
2521 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
2523 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2524 FIXME("stub - %p (%p)\n", This, pStore);
2525 return E_NOTIMPL;
2528 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
2529 IPropertyDescriptionList *pList,
2530 BOOL fAppendDefault)
2532 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2533 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
2534 return E_NOTIMPL;
2537 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
2539 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2540 FIXME("stub - %p (%p)\n", This, ppStore);
2541 return E_NOTIMPL;
2544 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
2545 IShellItem *psi,
2546 IPropertyStore *pStore,
2547 HWND hwnd,
2548 IFileOperationProgressSink *pSink)
2550 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2551 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
2552 return E_NOTIMPL;
2555 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
2556 IFileSaveDialog_fnQueryInterface,
2557 IFileSaveDialog_fnAddRef,
2558 IFileSaveDialog_fnRelease,
2559 IFileSaveDialog_fnShow,
2560 IFileSaveDialog_fnSetFileTypes,
2561 IFileSaveDialog_fnSetFileTypeIndex,
2562 IFileSaveDialog_fnGetFileTypeIndex,
2563 IFileSaveDialog_fnAdvise,
2564 IFileSaveDialog_fnUnadvise,
2565 IFileSaveDialog_fnSetOptions,
2566 IFileSaveDialog_fnGetOptions,
2567 IFileSaveDialog_fnSetDefaultFolder,
2568 IFileSaveDialog_fnSetFolder,
2569 IFileSaveDialog_fnGetFolder,
2570 IFileSaveDialog_fnGetCurrentSelection,
2571 IFileSaveDialog_fnSetFileName,
2572 IFileSaveDialog_fnGetFileName,
2573 IFileSaveDialog_fnSetTitle,
2574 IFileSaveDialog_fnSetOkButtonLabel,
2575 IFileSaveDialog_fnSetFileNameLabel,
2576 IFileSaveDialog_fnGetResult,
2577 IFileSaveDialog_fnAddPlace,
2578 IFileSaveDialog_fnSetDefaultExtension,
2579 IFileSaveDialog_fnClose,
2580 IFileSaveDialog_fnSetClientGuid,
2581 IFileSaveDialog_fnClearClientData,
2582 IFileSaveDialog_fnSetFilter,
2583 IFileSaveDialog_fnSetSaveAsItem,
2584 IFileSaveDialog_fnSetProperties,
2585 IFileSaveDialog_fnSetCollectedProperties,
2586 IFileSaveDialog_fnGetProperties,
2587 IFileSaveDialog_fnApplyProperties
2590 /**************************************************************************
2591 * IExplorerBrowserEvents implementation
2593 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
2595 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
2598 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
2599 REFIID riid, void **ppvObject)
2601 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2602 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2604 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2607 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
2609 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2610 TRACE("%p\n", This);
2611 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2614 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
2616 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2617 TRACE("%p\n", This);
2618 return IFileDialog2_Release(&This->IFileDialog2_iface);
2621 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
2622 PCIDLIST_ABSOLUTE pidlFolder)
2624 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2625 IShellItem *psi;
2626 HRESULT hr;
2627 TRACE("%p (%p)\n", This, pidlFolder);
2629 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
2630 if(SUCCEEDED(hr))
2632 hr = events_OnFolderChanging(This, psi);
2633 IShellItem_Release(psi);
2635 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
2636 if(hr == S_FALSE)
2637 hr = E_FAIL;
2639 return hr;
2641 else
2642 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
2644 return S_OK;
2647 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
2648 IShellView *psv)
2650 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2651 TRACE("%p (%p)\n", This, psv);
2652 return S_OK;
2655 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
2656 PCIDLIST_ABSOLUTE pidlFolder)
2658 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2659 HRESULT hr;
2660 TRACE("%p (%p)\n", This, pidlFolder);
2662 if(This->psi_folder)
2663 IShellItem_Release(This->psi_folder);
2665 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
2666 if(FAILED(hr))
2668 ERR("Failed to get the current folder.\n");
2669 This->psi_folder = NULL;
2672 events_OnFolderChange(This);
2674 return S_OK;
2677 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
2678 PCIDLIST_ABSOLUTE pidlFolder)
2680 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2681 TRACE("%p (%p)\n", This, pidlFolder);
2682 return S_OK;
2685 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
2686 IExplorerBrowserEvents_fnQueryInterface,
2687 IExplorerBrowserEvents_fnAddRef,
2688 IExplorerBrowserEvents_fnRelease,
2689 IExplorerBrowserEvents_fnOnNavigationPending,
2690 IExplorerBrowserEvents_fnOnViewCreated,
2691 IExplorerBrowserEvents_fnOnNavigationComplete,
2692 IExplorerBrowserEvents_fnOnNavigationFailed
2695 /**************************************************************************
2696 * IServiceProvider implementation
2698 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2700 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
2703 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
2704 REFIID riid, void **ppvObject)
2706 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2707 TRACE("%p\n", This);
2708 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2711 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
2713 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2714 TRACE("%p\n", This);
2715 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2718 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
2720 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2721 TRACE("%p\n", This);
2722 return IFileDialog2_Release(&This->IFileDialog2_iface);
2725 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
2726 REFGUID guidService,
2727 REFIID riid, void **ppv)
2729 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2730 HRESULT hr = E_FAIL;
2731 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
2733 *ppv = NULL;
2734 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
2735 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
2736 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
2737 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
2738 else
2739 FIXME("Interface %s requested from unknown service %s\n",
2740 debugstr_guid(riid), debugstr_guid(guidService));
2742 return hr;
2745 static const IServiceProviderVtbl vt_IServiceProvider = {
2746 IServiceProvider_fnQueryInterface,
2747 IServiceProvider_fnAddRef,
2748 IServiceProvider_fnRelease,
2749 IServiceProvider_fnQueryService
2752 /**************************************************************************
2753 * ICommDlgBrowser3 implementation
2755 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
2757 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
2760 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
2761 REFIID riid, void **ppvObject)
2763 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2764 TRACE("%p\n", This);
2765 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2768 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
2770 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2771 TRACE("%p\n", This);
2772 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2775 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
2777 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2778 TRACE("%p\n", This);
2779 return IFileDialog2_Release(&This->IFileDialog2_iface);
2782 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
2783 IShellView *shv)
2785 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2786 HRESULT hr;
2787 TRACE("%p (%p)\n", This, shv);
2789 hr = on_default_action(This);
2791 if(SUCCEEDED(hr))
2792 EndDialog(This->dlg_hwnd, S_OK);
2794 return S_OK;
2797 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
2798 IShellView *shv, ULONG uChange )
2800 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2801 IDataObject *new_selection;
2802 HRESULT hr;
2803 TRACE("%p (%p, %x)\n", This, shv, uChange);
2805 switch(uChange)
2807 case CDBOSC_SELCHANGE:
2808 if(This->psia_selection)
2810 IShellItemArray_Release(This->psia_selection);
2811 This->psia_selection = NULL;
2814 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
2815 if(SUCCEEDED(hr))
2817 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
2818 (void**)&This->psia_selection);
2819 if(SUCCEEDED(hr))
2821 fill_filename_from_selection(This);
2822 events_OnSelectionChange(This);
2825 IDataObject_Release(new_selection);
2827 break;
2828 default:
2829 TRACE("Unhandled state change\n");
2831 return S_OK;
2834 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
2835 IShellView *shv, LPCITEMIDLIST pidl)
2837 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2838 IShellItem *psi;
2839 LPWSTR filename;
2840 LPITEMIDLIST parent_pidl;
2841 HRESULT hr;
2842 ULONG attr;
2843 TRACE("%p (%p, %p)\n", This, shv, pidl);
2845 if(!This->filterspec_count)
2846 return S_OK;
2848 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
2849 if(SUCCEEDED(hr))
2851 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
2852 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
2853 ILFree(parent_pidl);
2854 ILFree(full_pidl);
2856 if(FAILED(hr))
2858 ERR("Failed to get shellitem (%08x).\n", hr);
2859 return S_OK;
2862 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
2863 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
2865 IShellItem_Release(psi);
2866 return S_OK;
2869 hr = S_OK;
2870 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
2872 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
2873 hr = S_FALSE;
2874 CoTaskMemFree(filename);
2877 IShellItem_Release(psi);
2878 return hr;
2881 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
2882 IShellView *ppshv, DWORD dwNotifyType)
2884 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2885 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
2886 return E_NOTIMPL;
2889 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
2890 IShellView *pshv,
2891 LPWSTR pszText, int cchMax)
2893 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2894 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
2895 return E_NOTIMPL;
2898 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
2900 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2901 FIXME("Stub: %p (%p)\n", This, pdwFlags);
2902 return E_NOTIMPL;
2905 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
2906 IShellView *pshv, int iColumn)
2908 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2909 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
2910 return E_NOTIMPL;
2913 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
2914 LPWSTR pszFileSpec, int cchFileSpec)
2916 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2917 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
2918 return E_NOTIMPL;
2921 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
2922 IShellView *pshv)
2924 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2925 FIXME("Stub: %p (%p)\n", This, pshv);
2926 return E_NOTIMPL;
2929 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
2930 ICommDlgBrowser3_fnQueryInterface,
2931 ICommDlgBrowser3_fnAddRef,
2932 ICommDlgBrowser3_fnRelease,
2933 ICommDlgBrowser3_fnOnDefaultCommand,
2934 ICommDlgBrowser3_fnOnStateChange,
2935 ICommDlgBrowser3_fnIncludeObject,
2936 ICommDlgBrowser3_fnNotify,
2937 ICommDlgBrowser3_fnGetDefaultMenuText,
2938 ICommDlgBrowser3_fnGetViewFlags,
2939 ICommDlgBrowser3_fnOnColumnClicked,
2940 ICommDlgBrowser3_fnGetCurrentFilter,
2941 ICommDlgBrowser3_fnOnPreviewCreated
2944 /**************************************************************************
2945 * IOleWindow implementation
2947 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
2949 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
2952 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
2954 FileDialogImpl *This = impl_from_IOleWindow(iface);
2955 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2958 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
2960 FileDialogImpl *This = impl_from_IOleWindow(iface);
2961 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2964 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
2966 FileDialogImpl *This = impl_from_IOleWindow(iface);
2967 return IFileDialog2_Release(&This->IFileDialog2_iface);
2970 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
2972 FileDialogImpl *This = impl_from_IOleWindow(iface);
2973 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
2974 return E_NOTIMPL;
2977 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
2979 FileDialogImpl *This = impl_from_IOleWindow(iface);
2980 TRACE("%p (%p)\n", This, phwnd);
2981 *phwnd = This->dlg_hwnd;
2982 return S_OK;
2985 static const IOleWindowVtbl vt_IOleWindow = {
2986 IOleWindow_fnQueryInterface,
2987 IOleWindow_fnAddRef,
2988 IOleWindow_fnRelease,
2989 IOleWindow_fnGetWindow,
2990 IOleWindow_fnContextSensitiveHelp
2993 /**************************************************************************
2994 * IFileDialogCustomize implementation
2996 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
2998 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3001 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3002 REFIID riid, void **ppvObject)
3004 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3005 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3008 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3010 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3011 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3014 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3016 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3017 return IFileDialog2_Release(&This->IFileDialog2_iface);
3020 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3021 DWORD dwIDCtl)
3023 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3024 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3025 return E_NOTIMPL;
3028 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3029 DWORD dwIDCtl,
3030 LPCWSTR pszLabel)
3032 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3033 customctrl *ctrl;
3034 TBBUTTON tbb;
3035 HRESULT hr;
3036 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3038 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3039 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3040 This->cctrl_def_height, &ctrl);
3041 if(SUCCEEDED(hr))
3043 ctrl->type = IDLG_CCTRL_MENU;
3045 /* Add the actual button with a popup menu. */
3046 tbb.iBitmap = I_IMAGENONE;
3047 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3048 tbb.iString = (DWORD_PTR)pszLabel;
3049 tbb.fsState = TBSTATE_ENABLED;
3050 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3051 tbb.idCommand = 1;
3053 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3056 return hr;
3059 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3060 DWORD dwIDCtl,
3061 LPCWSTR pszLabel)
3063 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3064 customctrl *ctrl;
3065 HRESULT hr;
3066 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3068 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3069 This->cctrl_def_height, &ctrl);
3070 if(SUCCEEDED(hr))
3071 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3073 return hr;
3076 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3077 DWORD dwIDCtl)
3079 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3080 customctrl *ctrl;
3081 HRESULT hr;
3082 TRACE("%p (%d)\n", This, dwIDCtl);
3084 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3085 This->cctrl_def_height, &ctrl);
3086 if(SUCCEEDED(hr))
3087 ctrl->type = IDLG_CCTRL_COMBOBOX;
3089 return hr;
3092 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3093 DWORD dwIDCtl)
3095 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3096 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3097 return E_NOTIMPL;
3100 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3101 DWORD dwIDCtl,
3102 LPCWSTR pszLabel,
3103 BOOL bChecked)
3105 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3106 customctrl *ctrl;
3107 HRESULT hr;
3108 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3110 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX, 0,
3111 This->cctrl_def_height, &ctrl);
3112 if(SUCCEEDED(hr))
3114 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3115 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3118 return hr;
3121 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3122 DWORD dwIDCtl,
3123 LPCWSTR pszText)
3125 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3126 customctrl *ctrl;
3127 HRESULT hr;
3128 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3130 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3131 This->cctrl_def_height, &ctrl);
3132 if(SUCCEEDED(hr))
3133 ctrl->type = IDLG_CCTRL_EDITBOX;
3135 return hr;
3138 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3139 DWORD dwIDCtl)
3141 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3142 customctrl *ctrl;
3143 HRESULT hr;
3144 TRACE("%p (%d)\n", This, dwIDCtl);
3146 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3147 GetSystemMetrics(SM_CYEDGE), &ctrl);
3148 if(SUCCEEDED(hr))
3149 ctrl->type = IDLG_CCTRL_SEPARATOR;
3151 return hr;
3154 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3155 DWORD dwIDCtl,
3156 LPCWSTR pszText)
3158 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3159 customctrl *ctrl;
3160 HRESULT hr;
3161 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3163 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3164 This->cctrl_def_height, &ctrl);
3165 if(SUCCEEDED(hr))
3166 ctrl->type = IDLG_CCTRL_TEXT;
3168 return hr;
3171 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3172 DWORD dwIDCtl,
3173 LPCWSTR pszLabel)
3175 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3176 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3177 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3179 if(!ctrl) return E_INVALIDARG;
3181 switch(ctrl->type)
3183 case IDLG_CCTRL_MENU:
3184 case IDLG_CCTRL_PUSHBUTTON:
3185 case IDLG_CCTRL_CHECKBUTTON:
3186 case IDLG_CCTRL_TEXT:
3187 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3188 break;
3189 default:
3190 break;
3193 return S_OK;
3196 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3197 DWORD dwIDCtl,
3198 CDCONTROLSTATEF *pdwState)
3200 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3201 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3202 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3204 if(!ctrl) return E_NOTIMPL;
3206 *pdwState = ctrl->cdcstate;
3207 return S_OK;
3210 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3211 DWORD dwIDCtl,
3212 CDCONTROLSTATEF dwState)
3214 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3215 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3216 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3218 if(ctrl)
3220 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3222 if(dwState & CDCS_ENABLED)
3223 wndstyle &= ~(WS_DISABLED);
3224 else
3225 wndstyle |= WS_DISABLED;
3227 if(dwState & CDCS_VISIBLE)
3228 wndstyle |= WS_VISIBLE;
3229 else
3230 wndstyle &= ~(WS_VISIBLE);
3232 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3234 /* We save the state separately since at least one application
3235 * relies on being able to hide a control. */
3236 ctrl->cdcstate = dwState;
3239 return S_OK;
3242 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3243 DWORD dwIDCtl,
3244 WCHAR **ppszText)
3246 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3247 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3248 WCHAR len, *text;
3249 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
3251 if(!ctrl || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3252 return E_FAIL;
3254 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3255 if(!text) return E_FAIL;
3257 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3258 *ppszText = text;
3259 return S_OK;
3262 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
3263 DWORD dwIDCtl,
3264 LPCWSTR pszText)
3266 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3267 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3268 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
3270 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
3271 return E_FAIL;
3273 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
3274 return S_OK;
3277 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
3278 DWORD dwIDCtl,
3279 BOOL *pbChecked)
3281 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3282 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3283 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
3285 if(ctrl)
3286 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
3288 return S_OK;
3291 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
3292 DWORD dwIDCtl,
3293 BOOL bChecked)
3295 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3296 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3297 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
3299 if(ctrl)
3300 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
3302 return S_OK;
3305 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
3307 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
3308 UINT i;
3309 if(!count || (count == CB_ERR))
3310 return -1;
3312 for(i = 0; i < count; i++)
3313 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3314 return i;
3316 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
3317 return -1;
3320 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
3321 DWORD dwIDCtl,
3322 DWORD dwIDItem,
3323 LPCWSTR pszLabel)
3325 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3326 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3327 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3329 if(!ctrl) return E_FAIL;
3331 switch(ctrl->type)
3333 case IDLG_CCTRL_COMBOBOX:
3335 UINT index;
3337 if(get_combobox_index_from_id(ctrl->hwnd, dwIDItem) != -1)
3338 return E_INVALIDARG;
3340 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
3341 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
3343 return S_OK;
3345 case IDLG_CCTRL_MENU:
3347 TBBUTTON tbb;
3348 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3350 if(GetMenuState((HMENU)tbb.dwData, dwIDItem, MF_BYCOMMAND) != -1)
3351 return E_INVALIDARG;
3353 AppendMenuW((HMENU)tbb.dwData, MF_STRING, dwIDItem, pszLabel);
3354 return S_OK;
3356 default:
3357 break;
3360 return E_NOINTERFACE; /* win7 */
3363 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
3364 DWORD dwIDCtl,
3365 DWORD dwIDItem)
3367 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3368 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3369 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3371 if(!ctrl) return E_FAIL;
3373 switch(ctrl->type)
3375 case IDLG_CCTRL_COMBOBOX:
3377 UINT i, count = SendMessageW(ctrl->hwnd, CB_GETCOUNT, 0, 0);
3378 if(!count || (count == CB_ERR))
3379 return E_FAIL;
3381 for(i = 0; i < count; i++)
3382 if(SendMessageW(ctrl->hwnd, CB_GETITEMDATA, 0, 0) == dwIDItem)
3384 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, i, 0) == CB_ERR)
3385 return E_FAIL;
3386 return S_OK;
3389 return E_UNEXPECTED;
3391 case IDLG_CCTRL_MENU:
3393 TBBUTTON tbb;
3394 HMENU hmenu;
3395 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3396 hmenu = (HMENU)tbb.dwData;
3398 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
3399 return E_UNEXPECTED;
3401 return S_OK;
3403 default:
3404 break;
3407 return E_FAIL;
3410 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
3411 DWORD dwIDCtl)
3413 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3414 TRACE("%p (%d)\n", This, dwIDCtl);
3416 /* Not implemented by native */
3417 return E_NOTIMPL;
3420 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
3421 DWORD dwIDCtl,
3422 DWORD dwIDItem,
3423 CDCONTROLSTATEF *pdwState)
3425 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3426 FIXME("stub - %p\n", This);
3427 return E_NOTIMPL;
3430 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
3431 DWORD dwIDCtl,
3432 DWORD dwIDItem,
3433 CDCONTROLSTATEF dwState)
3435 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3436 FIXME("stub - %p\n", This);
3437 return E_NOTIMPL;
3440 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
3441 DWORD dwIDCtl,
3442 DWORD *pdwIDItem)
3444 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3445 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3446 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
3448 if(!ctrl) return E_FAIL;
3450 switch(ctrl->type)
3452 case IDLG_CCTRL_COMBOBOX:
3454 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
3455 if(index == CB_ERR)
3456 return E_FAIL;
3458 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
3459 return S_OK;
3461 default:
3462 FIXME("Unsupported control type %d\n", ctrl->type);
3465 return E_NOTIMPL;
3468 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
3469 DWORD dwIDCtl,
3470 DWORD dwIDItem)
3472 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3473 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3474 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3476 if(!ctrl) return E_INVALIDARG;
3478 switch(ctrl->type)
3480 case IDLG_CCTRL_COMBOBOX:
3482 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
3484 if(index == -1)
3485 return E_INVALIDARG;
3487 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
3488 return E_FAIL;
3490 return S_OK;
3492 default:
3493 FIXME("Unsupported control type %d\n", ctrl->type);
3496 return E_INVALIDARG;
3499 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
3500 DWORD dwIDCtl,
3501 LPCWSTR pszLabel)
3503 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3504 FIXME("stub - %p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
3505 return E_NOTIMPL;
3508 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
3510 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3511 FIXME("stub - %p\n", This);
3512 return E_NOTIMPL;
3515 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
3516 DWORD dwIDCtl)
3518 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3519 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3520 return E_NOTIMPL;
3523 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
3524 DWORD dwIDCtl,
3525 DWORD dwIDItem,
3526 LPCWSTR pszLabel)
3528 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3529 FIXME("stub - %p (%d, %d, %p)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3530 return E_NOTIMPL;
3533 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
3534 IFileDialogCustomize_fnQueryInterface,
3535 IFileDialogCustomize_fnAddRef,
3536 IFileDialogCustomize_fnRelease,
3537 IFileDialogCustomize_fnEnableOpenDropDown,
3538 IFileDialogCustomize_fnAddMenu,
3539 IFileDialogCustomize_fnAddPushButton,
3540 IFileDialogCustomize_fnAddComboBox,
3541 IFileDialogCustomize_fnAddRadioButtonList,
3542 IFileDialogCustomize_fnAddCheckButton,
3543 IFileDialogCustomize_fnAddEditBox,
3544 IFileDialogCustomize_fnAddSeparator,
3545 IFileDialogCustomize_fnAddText,
3546 IFileDialogCustomize_fnSetControlLabel,
3547 IFileDialogCustomize_fnGetControlState,
3548 IFileDialogCustomize_fnSetControlState,
3549 IFileDialogCustomize_fnGetEditBoxText,
3550 IFileDialogCustomize_fnSetEditBoxText,
3551 IFileDialogCustomize_fnGetCheckButtonState,
3552 IFileDialogCustomize_fnSetCheckButtonState,
3553 IFileDialogCustomize_fnAddControlItem,
3554 IFileDialogCustomize_fnRemoveControlItem,
3555 IFileDialogCustomize_fnRemoveAllControlItems,
3556 IFileDialogCustomize_fnGetControlItemState,
3557 IFileDialogCustomize_fnSetControlItemState,
3558 IFileDialogCustomize_fnGetSelectedControlItem,
3559 IFileDialogCustomize_fnSetSelectedControlItem,
3560 IFileDialogCustomize_fnStartVisualGroup,
3561 IFileDialogCustomize_fnEndVisualGroup,
3562 IFileDialogCustomize_fnMakeProminent,
3563 IFileDialogCustomize_fnSetControlItemText
3566 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
3568 FileDialogImpl *fdimpl;
3569 HRESULT hr;
3570 IShellFolder *psf;
3571 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
3573 if(!ppv)
3574 return E_POINTER;
3575 if(pUnkOuter)
3576 return CLASS_E_NOAGGREGATION;
3578 fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
3579 if(!fdimpl)
3580 return E_OUTOFMEMORY;
3582 fdimpl->ref = 1;
3583 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
3584 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
3585 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
3586 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
3587 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
3588 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
3590 if(type == ITEMDLG_TYPE_OPEN)
3592 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
3593 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
3594 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
3595 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
3597 else
3599 WCHAR buf[16];
3600 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
3601 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
3602 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
3604 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
3605 fdimpl->custom_title = StrDupW(buf);
3606 fdimpl->custom_okbutton = StrDupW(buf);
3609 fdimpl->filterspecs = NULL;
3610 fdimpl->filterspec_count = 0;
3611 fdimpl->filetypeindex = 0;
3613 fdimpl->psia_selection = fdimpl->psia_results = NULL;
3614 fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
3616 list_init(&fdimpl->events_clients);
3617 fdimpl->events_next_cookie = 0;
3619 fdimpl->dlg_hwnd = NULL;
3620 fdimpl->peb = NULL;
3622 fdimpl->set_filename = NULL;
3623 fdimpl->default_ext = NULL;
3624 fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL;
3626 /* FIXME: The default folder setting should be restored for the
3627 * application if it was previously set. */
3628 SHGetDesktopFolder(&psf);
3629 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
3630 IShellFolder_Release(psf);
3632 hr = init_custom_controls(fdimpl);
3633 if(FAILED(hr))
3635 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
3636 IUnknown_Release((IUnknown*)fdimpl);
3637 return E_FAIL;
3640 hr = IUnknown_QueryInterface((IUnknown*)fdimpl, riid, ppv);
3641 IUnknown_Release((IUnknown*)fdimpl);
3642 return hr;
3645 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3647 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
3650 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3652 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);