shell32: Remove redundant loop to count already known value.
[wine/multimedia.git] / dlls / comdlg32 / itemdlg.c
blobf700891bb62cb444dab4b1d21b940d48f7dc1a01
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 break;
651 case IDLG_CCTRL_RADIOBUTTONLIST:
652 case IDLG_CCTRL_EDITBOX:
653 case IDLG_CCTRL_SEPARATOR:
654 case IDLG_CCTRL_MENU:
655 /* Nothing */
656 break;
660 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
662 FileDialogImpl *This = crs->lpCreateParams;
663 TRACE("%p\n", This);
665 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
666 return TRUE;
669 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
671 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
673 TRACE("%p, %lx\n", This, wparam);
675 if(ctrl)
677 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
679 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
680 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
682 else
683 cctrl_event_OnButtonClicked(This, ctrl->id);
686 return TRUE;
689 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
691 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
692 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
694 if(ctrl)
696 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
697 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
699 cctrl_event_OnItemSelected(This, ctrl->id, selid);
701 return TRUE;
704 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
706 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
707 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
708 POINT pt = { 0, nmtb->rcButton.bottom };
709 TBBUTTON tbb;
710 UINT idcmd;
712 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
714 if(ctrl)
716 cctrl_event_OnControlActivating(This,ctrl->id);
718 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
719 ClientToScreen(ctrl->hwnd, &pt);
720 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
721 if(idcmd)
722 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
725 return TBDDRET_DEFAULT;
728 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
730 switch(HIWORD(wparam))
732 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
733 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
736 return FALSE;
739 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
741 NMHDR *nmhdr = (NMHDR*)lparam;
743 switch(nmhdr->code)
745 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
748 return FALSE;
751 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
753 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
754 HWND hwnd_child;
755 RECT rc;
757 switch(message)
759 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
760 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
761 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
762 case WM_SIZE:
763 hwnd_child = GetPropW(hwnd, notifysink_childW);
764 GetClientRect(hwnd, &rc);
765 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
766 return TRUE;
769 return DefWindowProcW(hwnd, message, wparam, lparam);
772 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
773 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
774 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
776 HWND ns_hwnd, control_hwnd;
777 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
778 customctrl *ctrl;
780 if(get_cctrl(This, id))
781 return E_UNEXPECTED; /* Duplicate id */
783 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
784 0, 0, This->cctrl_width, height, This->cctrls_hwnd,
785 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
786 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
787 0, 0, This->cctrl_width, height, ns_hwnd,
788 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
790 if(!ns_hwnd || !control_hwnd)
792 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
793 DestroyWindow(ns_hwnd);
794 DestroyWindow(control_hwnd);
796 return E_FAIL;
799 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
801 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
802 if(!ctrl)
803 return E_OUTOFMEMORY;
805 ctrl->hwnd = control_hwnd;
806 ctrl->wrapper_hwnd = ns_hwnd;
807 ctrl->id = id;
808 ctrl->dlgid = This->cctrl_next_dlgid;
809 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
810 list_add_tail(&This->cctrls, &ctrl->entry);
811 if(ppctrl) *ppctrl = ctrl;
813 This->cctrl_next_dlgid++;
814 return S_OK;
817 /**************************************************************************
818 * Container functions.
820 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
822 UINT container_height;
823 UINT column_width;
824 UINT nr_of_cols;
825 UINT max_control_height, total_height = 0;
826 UINT cur_col_pos, cur_row_pos;
827 customctrl *ctrl;
828 BOOL fits_height;
829 static const UINT col_indent = 100; /* The first column is indented 100px */
830 static const UINT cspacing = 90; /* Columns are spaced with 90px */
831 static const UINT rspacing = 4; /* Rows are spaced with 4 px. */
833 /* Given the new width of the container, this function determines the
834 * needed height of the container and places the controls according to
835 * the new layout. Returns the new height.
838 TRACE("%p\n", This);
840 column_width = This->cctrl_width + cspacing;
841 nr_of_cols = (container_width - col_indent + cspacing) / column_width;
843 /* We don't need to do anything unless the number of visible columns has changed. */
844 if(nr_of_cols == This->cctrls_cols)
846 RECT rc;
847 GetWindowRect(This->cctrls_hwnd, &rc);
848 return rc.bottom - rc.top;
851 This->cctrls_cols = nr_of_cols;
853 /* Get the size of the tallest control, and the total size of
854 * all the controls to figure out the number of slots we need.
856 max_control_height = 0;
857 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
859 if(ctrl->cdcstate & CDCS_VISIBLE)
861 RECT rc;
862 UINT control_height;
863 GetWindowRect(ctrl->wrapper_hwnd, &rc);
864 control_height = rc.bottom - rc.top;
865 max_control_height = max(max_control_height, control_height);
867 total_height += control_height + rspacing;
871 if(!total_height)
872 return 0;
874 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
875 TRACE("Guess: container_height: %d\n",container_height);
877 /* Incrementally increase container_height until all the controls
878 * fit.
880 do {
881 UINT columns_needed = 1;
882 cur_row_pos = 0;
884 fits_height = TRUE;
885 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
887 if(ctrl->cdcstate & CDCS_VISIBLE)
889 RECT rc;
890 UINT control_height;
891 GetWindowRect(ctrl->wrapper_hwnd, &rc);
892 control_height = rc.bottom - rc.top;
894 if(cur_row_pos + control_height > container_height)
896 if(++columns_needed > nr_of_cols)
898 container_height += 1;
899 fits_height = FALSE;
900 break;
902 cur_row_pos = 0;
905 cur_row_pos += control_height + rspacing;
908 } while(!fits_height);
910 TRACE("Final container height: %d\n", container_height);
912 /* Move the controls to their final destination
914 cur_col_pos = col_indent, cur_row_pos = 0;
915 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
917 if(ctrl->cdcstate & CDCS_VISIBLE)
919 RECT rc;
920 UINT control_height;
921 GetWindowRect(ctrl->wrapper_hwnd, &rc);
922 control_height = rc.bottom - rc.top;
924 if(cur_row_pos + control_height > container_height)
926 cur_row_pos = 0;
927 cur_col_pos += This->cctrl_width + cspacing;
930 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos, cur_row_pos, 0, 0,
931 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
933 cur_row_pos += control_height + rspacing;
937 /* Sanity check */
938 if(cur_row_pos + This->cctrl_width > container_width)
939 ERR("-- Failed to place controls properly.\n");
941 return container_height;
944 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
946 LONG wndstyle;
948 if(parent)
950 customctrl *ctrl;
951 HFONT font;
953 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
954 wndstyle &= ~(WS_POPUP);
955 wndstyle |= WS_CHILD;
956 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
958 SetParent(This->cctrls_hwnd, parent);
959 ShowWindow(This->cctrls_hwnd, TRUE);
961 /* Set the fonts to match the dialog font. */
962 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
963 if(!font)
964 ERR("Failed to get font handle from dialog.\n");
966 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
968 if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
969 customctrl_resize(This, ctrl);
972 else
974 ShowWindow(This->cctrls_hwnd, FALSE);
976 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
977 wndstyle &= ~(WS_CHILD);
978 wndstyle |= WS_POPUP;
979 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
981 SetParent(This->cctrls_hwnd, NULL);
985 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
987 FileDialogImpl *This = crs->lpCreateParams;
988 TRACE("%p\n", This);
990 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
991 return TRUE;
994 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
996 customctrl *cur1, *cur2;
997 TRACE("%p\n", This);
999 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1001 TRACE("Freeing control %p\n", cur1);
1002 list_remove(&cur1->entry);
1004 if(cur1->type == IDLG_CCTRL_MENU)
1006 TBBUTTON tbb;
1007 SendMessageW(cur1->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1008 DestroyMenu((HMENU)tbb.dwData);
1011 DestroyWindow(cur1->hwnd);
1012 HeapFree(GetProcessHeap(), 0, cur1);
1015 return TRUE;
1018 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1020 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1022 switch(umessage)
1024 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1025 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1026 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1029 return FALSE;
1032 static HRESULT init_custom_controls(FileDialogImpl *This)
1034 WNDCLASSW wc;
1035 static const WCHAR ctrl_container_classname[] =
1036 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1038 InitCommonControlsEx(NULL);
1040 This->cctrl_width = 160; /* Controls have a fixed width */
1041 This->cctrl_def_height = 23;
1042 This->cctrls_cols = 0;
1044 This->cctrl_next_dlgid = 0x2000;
1045 list_init(&This->cctrls);
1047 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1049 wc.style = CS_HREDRAW | CS_VREDRAW;
1050 wc.lpfnWndProc = ctrl_container_wndproc;
1051 wc.cbClsExtra = 0;
1052 wc.cbWndExtra = 0;
1053 wc.hInstance = COMDLG32_hInstance;
1054 wc.hIcon = 0;
1055 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1056 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1057 wc.lpszMenuName = NULL;
1058 wc.lpszClassName = ctrl_container_classname;
1060 if(!RegisterClassW(&wc)) return E_FAIL;
1063 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1064 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1065 0, 0, 0, 0, NULL, 0,
1066 COMDLG32_hInstance, (void*)This);
1067 if(!This->cctrls_hwnd)
1068 return E_FAIL;
1070 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1072 /* Register class for */
1073 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1074 wc.hInstance != COMDLG32_hInstance)
1076 wc.style = CS_HREDRAW | CS_VREDRAW;
1077 wc.lpfnWndProc = notifysink_proc;
1078 wc.cbClsExtra = 0;
1079 wc.cbWndExtra = 0;
1080 wc.hInstance = COMDLG32_hInstance;
1081 wc.hIcon = 0;
1082 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1083 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1084 wc.lpszMenuName = NULL;
1085 wc.lpszClassName = floatnotifysinkW;
1087 if (!RegisterClassW(&wc))
1088 ERR("Failed to register FloatNotifySink window class.\n");
1091 return S_OK;
1094 /**************************************************************************
1095 * Window related functions.
1097 static SIZE update_layout(FileDialogImpl *This)
1099 HDWP hdwp;
1100 HWND hwnd;
1101 RECT dialog_rc;
1102 RECT cancel_rc, open_rc;
1103 RECT filetype_rc, filename_rc, filenamelabel_rc;
1104 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1105 int missing_width, missing_height;
1106 static const UINT vspacing = 4, hspacing = 4;
1107 SIZE ret;
1109 GetClientRect(This->dlg_hwnd, &dialog_rc);
1111 missing_width = max(0, 320 - dialog_rc.right);
1112 missing_height = max(0, 200 - dialog_rc.bottom);
1114 if(missing_width || missing_height)
1116 TRACE("Missing (%d, %d)\n", missing_width, missing_height);
1117 ret.cx = missing_width;
1118 ret.cy = missing_height;
1119 return ret;
1122 /****
1123 * Calculate the size of the dialog and all the parts.
1126 /* Cancel button */
1127 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1128 if(hwnd)
1130 int cancel_width, cancel_height;
1131 GetWindowRect(hwnd, &cancel_rc);
1132 cancel_width = cancel_rc.right - cancel_rc.left;
1133 cancel_height = cancel_rc.bottom - cancel_rc.top;
1135 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1136 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1137 cancel_rc.right = cancel_rc.left + cancel_width;
1138 cancel_rc.bottom = cancel_rc.top + cancel_height;
1141 /* Open/Save button */
1142 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1143 if(hwnd)
1145 int open_width, open_height;
1146 GetWindowRect(hwnd, &open_rc);
1147 open_width = open_rc.right - open_rc.left;
1148 open_height = open_rc.bottom - open_rc.top;
1150 open_rc.left = cancel_rc.left - open_width - hspacing;
1151 open_rc.top = cancel_rc.top;
1152 open_rc.right = open_rc.left + open_width;
1153 open_rc.bottom = open_rc.top + open_height;
1156 /* The filetype combobox. */
1157 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1158 if(hwnd)
1160 int filetype_width, filetype_height;
1161 GetWindowRect(hwnd, &filetype_rc);
1163 filetype_width = filetype_rc.right - filetype_rc.left;
1164 filetype_height = filetype_rc.bottom - filetype_rc.top;
1166 filetype_rc.right = cancel_rc.right;
1168 filetype_rc.left = filetype_rc.right - filetype_width;
1169 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1170 filetype_rc.bottom = filetype_rc.top + filetype_height;
1172 if(!This->filterspec_count)
1173 filetype_rc.left = filetype_rc.right;
1176 /* Filename label. */
1177 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1178 if(hwnd)
1180 int filetypelabel_width, filetypelabel_height;
1181 GetWindowRect(hwnd, &filenamelabel_rc);
1183 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1184 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1186 filenamelabel_rc.left = 160; /* FIXME */
1187 filenamelabel_rc.top = filetype_rc.top;
1188 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1189 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1192 /* Filename edit box. */
1193 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1194 if(hwnd)
1196 int filename_width, filename_height;
1197 GetWindowRect(hwnd, &filename_rc);
1199 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1200 filename_height = filename_rc.bottom - filename_rc.top;
1202 filename_rc.left = filenamelabel_rc.right + hspacing;
1203 filename_rc.top = filetype_rc.top;
1204 filename_rc.right = filename_rc.left + filename_width;
1205 filename_rc.bottom = filename_rc.top + filename_height;
1208 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1209 if(hwnd)
1211 GetWindowRect(hwnd, &toolbar_rc);
1212 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1215 /* The custom controls */
1216 customctrls_rc.left = dialog_rc.left + vspacing;
1217 customctrls_rc.right = dialog_rc.right - vspacing;
1218 customctrls_rc.bottom = filename_rc.top - hspacing;
1219 customctrls_rc.top = customctrls_rc.bottom -
1220 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1222 /* The ExplorerBrowser control. */
1223 ebrowser_rc.left = dialog_rc.left + vspacing;
1224 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1225 ebrowser_rc.right = dialog_rc.right - hspacing;
1226 ebrowser_rc.bottom = customctrls_rc.top - hspacing;
1228 /****
1229 * Move everything to the right place.
1232 /* FIXME: The Save Dialog uses a slightly different layout. */
1233 hdwp = BeginDeferWindowPos(7);
1235 if(hdwp && This->peb)
1236 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1238 if(hdwp && This->cctrls_hwnd)
1239 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1240 customctrls_rc.left, customctrls_rc.top,
1241 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1242 SWP_NOZORDER | SWP_NOACTIVATE);
1244 /* The default controls */
1245 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1246 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1247 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1249 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1250 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1251 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1252 SWP_NOZORDER | SWP_NOACTIVATE);
1254 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1255 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1256 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1258 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1259 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1260 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1262 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1263 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1264 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1266 if(hdwp)
1267 EndDeferWindowPos(hdwp);
1268 else
1269 ERR("Failed to position dialog controls.\n");
1271 ret.cx = 0; ret.cy = 0;
1272 return ret;
1275 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1277 IShellItem *psi_folder;
1278 FOLDERSETTINGS fos;
1279 RECT rc = {0};
1280 HRESULT hr;
1282 /* Create ExplorerBrowser instance */
1283 OleInitialize(NULL);
1285 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1286 &IID_IExplorerBrowser, (void**)&This->peb);
1287 if(FAILED(hr))
1289 ERR("Failed to instantiate ExplorerBrowser control.\n");
1290 return hr;
1293 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES);
1295 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1296 if(FAILED(hr))
1298 ERR("Failed to initialize the ExplorerBrowser control.\n");
1299 IExplorerBrowser_Release(This->peb);
1300 This->peb = NULL;
1301 return hr;
1303 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1304 if(FAILED(hr))
1305 ERR("Advise (ExplorerBrowser) failed.\n");
1307 /* Get previous options? */
1308 fos.ViewMode = fos.fFlags = 0;
1309 if(!(This->options & FOS_ALLOWMULTISELECT))
1310 fos.fFlags |= FWF_SINGLESEL;
1312 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1314 hr = IUnknown_SetSite((IUnknown*)This->peb, (IUnknown*)This);
1315 if(FAILED(hr))
1316 ERR("SetSite (ExplorerBrowser) failed.\n");
1318 /* Browse somewhere */
1319 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1320 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1322 return S_OK;
1325 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1327 HWND htoolbar;
1328 TBADDBITMAP tbab;
1329 TBBUTTON button[2];
1331 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1332 0, 0, 0, 0,
1333 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1335 tbab.hInst = HINST_COMMCTRL;
1336 tbab.nID = IDB_HIST_LARGE_COLOR;
1337 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1339 button[0].iBitmap = HIST_BACK;
1340 button[0].idCommand = IDC_NAVBACK;
1341 button[0].fsState = TBSTATE_ENABLED;
1342 button[0].fsStyle = BTNS_BUTTON;
1343 button[0].dwData = 0;
1344 button[0].iString = 0;
1346 button[1].iBitmap = HIST_FORWARD;
1347 button[1].idCommand = IDC_NAVFORWARD;
1348 button[1].fsState = TBSTATE_ENABLED;
1349 button[1].fsStyle = BTNS_BUTTON;
1350 button[1].dwData = 0;
1351 button[1].iString = 0;
1353 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1354 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1355 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1358 static void update_control_text(FileDialogImpl *This)
1360 HWND hitem;
1361 if(This->custom_title)
1362 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1364 if(This->custom_okbutton &&
1365 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1367 SetWindowTextW(hitem, This->custom_okbutton);
1368 ctrl_resize(hitem, 50, 250, FALSE);
1371 if(This->custom_cancelbutton &&
1372 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1374 SetWindowTextW(hitem, This->custom_cancelbutton);
1375 ctrl_resize(hitem, 50, 250, FALSE);
1378 if(This->custom_filenamelabel &&
1379 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1381 SetWindowTextW(hitem, This->custom_filenamelabel);
1382 ctrl_resize(hitem, 50, 250, FALSE);
1386 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1388 FileDialogImpl *This = (FileDialogImpl*)lParam;
1389 HWND hitem;
1391 TRACE("(%p, %p)\n", This, hwnd);
1393 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1394 This->dlg_hwnd = hwnd;
1396 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1397 if(hitem) ShowWindow(hitem, SW_HIDE);
1399 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1400 if(hitem) ShowWindow(hitem, SW_HIDE);
1402 /* Fill filetypes combobox, or hide it. */
1403 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1404 if(This->filterspec_count)
1406 UINT i;
1407 for(i = 0; i < This->filterspec_count; i++)
1408 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
1410 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
1412 else
1413 ShowWindow(hitem, SW_HIDE);
1415 if(This->set_filename &&
1416 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1417 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
1419 ctrl_container_reparent(This, This->dlg_hwnd);
1420 init_explorerbrowser(This);
1421 init_toolbar(This, hwnd);
1422 update_control_text(This);
1423 update_layout(This);
1425 return TRUE;
1428 static LRESULT on_wm_size(FileDialogImpl *This)
1430 update_layout(This);
1431 return FALSE;
1434 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
1436 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
1437 TRACE("%p (%p)\n", This, mmi);
1439 /* FIXME */
1440 mmi->ptMinTrackSize.x = 640;
1441 mmi->ptMinTrackSize.y = 480;
1443 return FALSE;
1446 static LRESULT on_wm_destroy(FileDialogImpl *This)
1448 TRACE("%p\n", This);
1450 if(This->peb)
1452 IExplorerBrowser_Destroy(This->peb);
1453 IExplorerBrowser_Release(This->peb);
1454 This->peb = NULL;
1457 ctrl_container_reparent(This, NULL);
1458 This->dlg_hwnd = NULL;
1460 return TRUE;
1463 static LRESULT on_idok(FileDialogImpl *This)
1465 TRACE("%p\n", This);
1467 if(SUCCEEDED(on_default_action(This)))
1468 EndDialog(This->dlg_hwnd, S_OK);
1470 return FALSE;
1473 static LRESULT on_idcancel(FileDialogImpl *This)
1475 TRACE("%p\n", This);
1477 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
1479 return FALSE;
1482 static LRESULT on_browse_back(FileDialogImpl *This)
1484 TRACE("%p\n", This);
1485 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
1486 return FALSE;
1489 static LRESULT on_browse_forward(FileDialogImpl *This)
1491 TRACE("%p\n", This);
1492 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
1493 return FALSE;
1496 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1498 if(HIWORD(wparam) == CBN_SELCHANGE)
1500 IShellView *psv;
1501 HRESULT hr;
1502 LPWSTR filename;
1503 UINT prev_index = This->filetypeindex;
1505 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
1506 TRACE("File type selection changed to %d.\n", This->filetypeindex);
1508 if(prev_index == This->filetypeindex)
1509 return FALSE;
1511 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
1512 if(SUCCEEDED(hr))
1514 IShellView_Refresh(psv);
1515 IShellView_Release(psv);
1518 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
1520 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
1522 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
1523 if(ext)
1525 lstrcpyW(buf, filename);
1527 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
1528 PathRemoveExtensionW(buf);
1530 lstrcatW(buf, ext);
1531 set_file_name(This, buf);
1533 CoTaskMemFree(filename);
1537 return FALSE;
1540 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1542 switch(LOWORD(wparam))
1544 case IDOK: return on_idok(This);
1545 case IDCANCEL: return on_idcancel(This);
1546 case IDC_NAVBACK: return on_browse_back(This);
1547 case IDC_NAVFORWARD: return on_browse_forward(This);
1548 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
1549 default: TRACE("Unknown command.\n");
1551 return FALSE;
1554 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1556 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1558 switch(umessage)
1560 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
1561 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
1562 case WM_SIZE: return on_wm_size(This);
1563 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
1564 case WM_DESTROY: return on_wm_destroy(This);
1567 return FALSE;
1570 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
1572 INT_PTR res;
1574 SetLastError(0);
1575 res = DialogBoxParamW(COMDLG32_hInstance,
1576 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
1577 parent, itemdlg_dlgproc, (LPARAM)This);
1578 This->dlg_hwnd = NULL;
1579 if(res == -1)
1581 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
1582 return E_FAIL;
1585 TRACE("Returning 0x%08x\n", (HRESULT)res);
1586 return (HRESULT)res;
1589 /**************************************************************************
1590 * IFileDialog implementation
1592 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
1594 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
1597 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
1598 REFIID riid,
1599 void **ppvObject)
1601 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1602 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1604 *ppvObject = NULL;
1605 if(IsEqualGUID(riid, &IID_IUnknown) ||
1606 IsEqualGUID(riid, &IID_IFileDialog) ||
1607 IsEqualGUID(riid, &IID_IFileDialog2))
1609 *ppvObject = iface;
1611 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
1613 *ppvObject = &This->u.IFileOpenDialog_iface;
1615 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
1617 *ppvObject = &This->u.IFileSaveDialog_iface;
1619 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
1621 *ppvObject = &This->IExplorerBrowserEvents_iface;
1623 else if(IsEqualGUID(riid, &IID_IServiceProvider))
1625 *ppvObject = &This->IServiceProvider_iface;
1627 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
1628 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
1629 IsEqualGUID(&IID_ICommDlgBrowser, riid))
1631 *ppvObject = &This->ICommDlgBrowser3_iface;
1633 else if(IsEqualGUID(&IID_IOleWindow, riid))
1635 *ppvObject = &This->IOleWindow_iface;
1637 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
1638 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
1640 *ppvObject = &This->IFileDialogCustomize_iface;
1642 else
1643 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
1645 if(*ppvObject)
1647 IUnknown_AddRef((IUnknown*)*ppvObject);
1648 return S_OK;
1651 return E_NOINTERFACE;
1654 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
1656 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1657 LONG ref = InterlockedIncrement(&This->ref);
1658 TRACE("%p - ref %d\n", This, ref);
1660 return ref;
1663 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
1665 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1666 LONG ref = InterlockedDecrement(&This->ref);
1667 TRACE("%p - ref %d\n", This, ref);
1669 if(!ref)
1671 UINT i;
1672 for(i = 0; i < This->filterspec_count; i++)
1674 LocalFree((void*)This->filterspecs[i].pszName);
1675 LocalFree((void*)This->filterspecs[i].pszSpec);
1677 HeapFree(GetProcessHeap(), 0, This->filterspecs);
1679 DestroyWindow(This->cctrls_hwnd);
1681 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
1682 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
1683 if(This->psi_folder) IShellItem_Release(This->psi_folder);
1684 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
1685 if(This->psia_results) IShellItemArray_Release(This->psia_results);
1687 LocalFree(This->set_filename);
1688 LocalFree(This->default_ext);
1689 LocalFree(This->custom_title);
1690 LocalFree(This->custom_okbutton);
1691 LocalFree(This->custom_cancelbutton);
1692 LocalFree(This->custom_filenamelabel);
1694 HeapFree(GetProcessHeap(), 0, This);
1697 return ref;
1700 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
1702 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1703 TRACE("%p (%p)\n", iface, hwndOwner);
1705 return create_dialog(This, hwndOwner);
1708 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
1709 const COMDLG_FILTERSPEC *rgFilterSpec)
1711 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1712 UINT i;
1713 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
1715 if(This->filterspecs)
1716 return E_UNEXPECTED;
1718 if(!rgFilterSpec)
1719 return E_INVALIDARG;
1721 if(!cFileTypes)
1722 return S_OK;
1724 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
1725 for(i = 0; i < cFileTypes; i++)
1727 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
1728 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
1730 This->filterspec_count = cFileTypes;
1732 return S_OK;
1735 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
1737 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1738 TRACE("%p (%d)\n", This, iFileType);
1740 if(!This->filterspecs)
1741 return E_FAIL;
1743 if(iFileType >= This->filterspec_count)
1744 This->filetypeindex = This->filterspec_count - 1;
1745 else
1746 This->filetypeindex = iFileType;
1748 return S_OK;
1751 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
1753 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1754 TRACE("%p (%p)\n", This, piFileType);
1756 if(!piFileType)
1757 return E_INVALIDARG;
1759 *piFileType = This->filetypeindex;
1761 return S_OK;
1764 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
1766 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1767 events_client *client;
1768 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
1770 if(!pfde || !pdwCookie)
1771 return E_INVALIDARG;
1773 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
1774 client->pfde = pfde;
1775 client->cookie = ++This->events_next_cookie;
1777 IFileDialogEvents_AddRef(pfde);
1778 *pdwCookie = client->cookie;
1780 list_add_tail(&This->events_clients, &client->entry);
1782 return S_OK;
1785 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
1787 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1788 events_client *client, *found = NULL;
1789 TRACE("%p (%d)\n", This, dwCookie);
1791 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
1793 if(client->cookie == dwCookie)
1795 found = client;
1796 break;
1800 if(found)
1802 list_remove(&found->entry);
1803 IFileDialogEvents_Release(found->pfde);
1804 HeapFree(GetProcessHeap(), 0, found);
1805 return S_OK;
1808 return E_INVALIDARG;
1811 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
1813 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1814 TRACE("%p (0x%x)\n", This, fos);
1816 This->options = fos;
1818 return S_OK;
1821 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
1823 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1824 TRACE("%p (%p)\n", This, pfos);
1826 if(!pfos)
1827 return E_INVALIDARG;
1829 *pfos = This->options;
1831 return S_OK;
1834 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
1836 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1837 TRACE("%p (%p)\n", This, psi);
1838 if(This->psi_defaultfolder)
1839 IShellItem_Release(This->psi_defaultfolder);
1841 This->psi_defaultfolder = psi;
1843 if(This->psi_defaultfolder)
1844 IShellItem_AddRef(This->psi_defaultfolder);
1846 return S_OK;
1849 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
1851 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1852 TRACE("%p (%p)\n", This, psi);
1853 if(This->psi_setfolder)
1854 IShellItem_Release(This->psi_setfolder);
1856 This->psi_setfolder = psi;
1858 if(This->psi_setfolder)
1859 IShellItem_AddRef(This->psi_setfolder);
1861 return S_OK;
1864 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
1866 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1867 TRACE("%p (%p)\n", This, ppsi);
1868 if(!ppsi)
1869 return E_INVALIDARG;
1871 /* FIXME:
1872 If the dialog is shown, return the current(ly selected) folder. */
1874 *ppsi = NULL;
1875 if(This->psi_folder)
1876 *ppsi = This->psi_folder;
1877 else if(This->psi_setfolder)
1878 *ppsi = This->psi_setfolder;
1879 else if(This->psi_defaultfolder)
1880 *ppsi = This->psi_defaultfolder;
1882 if(*ppsi)
1884 IShellItem_AddRef(*ppsi);
1885 return S_OK;
1888 return E_FAIL;
1891 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
1893 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1894 HRESULT hr;
1895 TRACE("%p (%p)\n", This, ppsi);
1897 if(!ppsi)
1898 return E_INVALIDARG;
1900 if(This->psia_selection)
1902 /* FIXME: Check filename edit box */
1903 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
1904 return hr;
1907 return E_FAIL;
1910 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
1912 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1913 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
1915 set_file_name(This, pszName);
1917 return S_OK;
1920 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
1922 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1923 TRACE("%p (%p)\n", iface, pszName);
1925 if(!pszName)
1926 return E_INVALIDARG;
1928 *pszName = NULL;
1929 if(get_file_name(This, pszName))
1930 return S_OK;
1931 else
1932 return E_FAIL;
1935 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
1937 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1938 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
1940 LocalFree(This->custom_title);
1941 This->custom_title = StrDupW(pszTitle);
1942 update_control_text(This);
1944 return S_OK;
1947 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
1949 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1950 TRACE("%p (%s)\n", This, debugstr_w(pszText));
1952 LocalFree(This->custom_okbutton);
1953 This->custom_okbutton = StrDupW(pszText);
1954 update_control_text(This);
1955 update_layout(This);
1957 return S_OK;
1960 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
1962 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1963 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
1965 LocalFree(This->custom_filenamelabel);
1966 This->custom_filenamelabel = StrDupW(pszLabel);
1967 update_control_text(This);
1968 update_layout(This);
1970 return S_OK;
1973 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
1975 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1976 HRESULT hr;
1977 TRACE("%p (%p)\n", This, ppsi);
1979 if(!ppsi)
1980 return E_INVALIDARG;
1982 if(This->psia_results)
1984 UINT item_count;
1985 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
1986 if(SUCCEEDED(hr))
1988 if(item_count != 1)
1989 return E_FAIL;
1991 /* Adds a reference. */
1992 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
1995 return hr;
1998 return E_UNEXPECTED;
2001 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2003 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2004 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2005 return E_NOTIMPL;
2008 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2010 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2011 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2013 LocalFree(This->default_ext);
2014 This->default_ext = StrDupW(pszDefaultExtension);
2016 return S_OK;
2019 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2021 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2022 TRACE("%p (0x%08x)\n", This, hr);
2024 if(This->dlg_hwnd)
2025 EndDialog(This->dlg_hwnd, hr);
2027 return S_OK;
2030 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2032 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2033 FIXME("stub - %p (%s)\n", This, debugstr_guid(guid));
2034 return E_NOTIMPL;
2037 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2039 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2040 FIXME("stub - %p\n", This);
2041 return E_NOTIMPL;
2044 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2046 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2047 FIXME("stub - %p (%p)\n", This, pFilter);
2048 return E_NOTIMPL;
2051 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2053 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2054 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2056 LocalFree(This->custom_cancelbutton);
2057 This->custom_cancelbutton = StrDupW(pszLabel);
2058 update_control_text(This);
2059 update_layout(This);
2061 return S_OK;
2064 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2066 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2067 FIXME("stub - %p (%p)\n", This, psi);
2068 return E_NOTIMPL;
2071 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2072 IFileDialog2_fnQueryInterface,
2073 IFileDialog2_fnAddRef,
2074 IFileDialog2_fnRelease,
2075 IFileDialog2_fnShow,
2076 IFileDialog2_fnSetFileTypes,
2077 IFileDialog2_fnSetFileTypeIndex,
2078 IFileDialog2_fnGetFileTypeIndex,
2079 IFileDialog2_fnAdvise,
2080 IFileDialog2_fnUnadvise,
2081 IFileDialog2_fnSetOptions,
2082 IFileDialog2_fnGetOptions,
2083 IFileDialog2_fnSetDefaultFolder,
2084 IFileDialog2_fnSetFolder,
2085 IFileDialog2_fnGetFolder,
2086 IFileDialog2_fnGetCurrentSelection,
2087 IFileDialog2_fnSetFileName,
2088 IFileDialog2_fnGetFileName,
2089 IFileDialog2_fnSetTitle,
2090 IFileDialog2_fnSetOkButtonLabel,
2091 IFileDialog2_fnSetFileNameLabel,
2092 IFileDialog2_fnGetResult,
2093 IFileDialog2_fnAddPlace,
2094 IFileDialog2_fnSetDefaultExtension,
2095 IFileDialog2_fnClose,
2096 IFileDialog2_fnSetClientGuid,
2097 IFileDialog2_fnClearClientData,
2098 IFileDialog2_fnSetFilter,
2099 IFileDialog2_fnSetCancelButtonLabel,
2100 IFileDialog2_fnSetNavigationRoot
2103 /**************************************************************************
2104 * IFileOpenDialog
2106 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2108 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2111 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2112 REFIID riid, void **ppvObject)
2114 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2115 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2118 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2120 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2121 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2124 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2126 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2127 return IFileDialog2_Release(&This->IFileDialog2_iface);
2130 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2132 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2133 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2136 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2137 const COMDLG_FILTERSPEC *rgFilterSpec)
2139 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2140 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2143 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2145 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2146 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2149 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2151 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2152 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2155 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2156 DWORD *pdwCookie)
2158 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2159 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2162 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2164 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2165 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2168 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2170 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2171 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2174 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2176 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2177 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2180 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2182 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2183 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2186 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2188 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2189 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2192 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2194 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2195 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2198 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2200 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2201 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2204 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2206 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2207 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2210 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2212 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2213 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2216 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2218 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2219 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2222 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2224 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2225 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2228 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2230 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2231 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2234 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2236 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2237 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2240 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2242 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2243 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2246 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2247 LPCWSTR pszDefaultExtension)
2249 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2250 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2253 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2255 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2256 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2259 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2261 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2262 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2265 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2267 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2268 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2271 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2273 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2274 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2277 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2279 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2280 TRACE("%p (%p)\n", This, ppenum);
2282 *ppenum = This->psia_results;
2284 if(*ppenum)
2286 IShellItemArray_AddRef(*ppenum);
2287 return S_OK;
2290 return E_FAIL;
2293 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2295 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2296 TRACE("%p (%p)\n", This, ppsai);
2298 if(This->psia_selection)
2300 *ppsai = This->psia_selection;
2301 IShellItemArray_AddRef(*ppsai);
2302 return S_OK;
2305 return E_FAIL;
2308 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2309 IFileOpenDialog_fnQueryInterface,
2310 IFileOpenDialog_fnAddRef,
2311 IFileOpenDialog_fnRelease,
2312 IFileOpenDialog_fnShow,
2313 IFileOpenDialog_fnSetFileTypes,
2314 IFileOpenDialog_fnSetFileTypeIndex,
2315 IFileOpenDialog_fnGetFileTypeIndex,
2316 IFileOpenDialog_fnAdvise,
2317 IFileOpenDialog_fnUnadvise,
2318 IFileOpenDialog_fnSetOptions,
2319 IFileOpenDialog_fnGetOptions,
2320 IFileOpenDialog_fnSetDefaultFolder,
2321 IFileOpenDialog_fnSetFolder,
2322 IFileOpenDialog_fnGetFolder,
2323 IFileOpenDialog_fnGetCurrentSelection,
2324 IFileOpenDialog_fnSetFileName,
2325 IFileOpenDialog_fnGetFileName,
2326 IFileOpenDialog_fnSetTitle,
2327 IFileOpenDialog_fnSetOkButtonLabel,
2328 IFileOpenDialog_fnSetFileNameLabel,
2329 IFileOpenDialog_fnGetResult,
2330 IFileOpenDialog_fnAddPlace,
2331 IFileOpenDialog_fnSetDefaultExtension,
2332 IFileOpenDialog_fnClose,
2333 IFileOpenDialog_fnSetClientGuid,
2334 IFileOpenDialog_fnClearClientData,
2335 IFileOpenDialog_fnSetFilter,
2336 IFileOpenDialog_fnGetResults,
2337 IFileOpenDialog_fnGetSelectedItems
2340 /**************************************************************************
2341 * IFileSaveDialog
2343 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
2345 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
2348 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
2349 REFIID riid,
2350 void **ppvObject)
2352 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2353 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2356 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
2358 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2359 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2362 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
2364 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2365 return IFileDialog2_Release(&This->IFileDialog2_iface);
2368 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
2370 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2371 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2374 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
2375 const COMDLG_FILTERSPEC *rgFilterSpec)
2377 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2378 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2381 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
2383 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2384 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2387 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
2389 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2390 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2393 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
2394 DWORD *pdwCookie)
2396 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2397 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2400 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
2402 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2403 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2406 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
2408 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2409 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2412 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2414 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2415 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2418 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
2420 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2421 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2424 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
2426 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2427 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2430 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
2432 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2433 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2436 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
2438 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2439 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2442 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
2444 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2445 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2448 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
2450 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2451 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2454 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
2456 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2457 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2460 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
2462 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2463 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2466 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
2468 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2469 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2472 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
2474 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2475 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2478 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
2480 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2481 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2484 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
2485 LPCWSTR pszDefaultExtension)
2487 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2488 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2491 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
2493 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2494 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2497 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
2499 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2500 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2503 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
2505 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2506 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2509 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
2511 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2512 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2515 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
2517 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2518 FIXME("stub - %p (%p)\n", This, psi);
2519 return E_NOTIMPL;
2522 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
2524 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2525 FIXME("stub - %p (%p)\n", This, pStore);
2526 return E_NOTIMPL;
2529 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
2530 IPropertyDescriptionList *pList,
2531 BOOL fAppendDefault)
2533 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2534 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
2535 return E_NOTIMPL;
2538 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
2540 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2541 FIXME("stub - %p (%p)\n", This, ppStore);
2542 return E_NOTIMPL;
2545 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
2546 IShellItem *psi,
2547 IPropertyStore *pStore,
2548 HWND hwnd,
2549 IFileOperationProgressSink *pSink)
2551 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2552 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
2553 return E_NOTIMPL;
2556 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
2557 IFileSaveDialog_fnQueryInterface,
2558 IFileSaveDialog_fnAddRef,
2559 IFileSaveDialog_fnRelease,
2560 IFileSaveDialog_fnShow,
2561 IFileSaveDialog_fnSetFileTypes,
2562 IFileSaveDialog_fnSetFileTypeIndex,
2563 IFileSaveDialog_fnGetFileTypeIndex,
2564 IFileSaveDialog_fnAdvise,
2565 IFileSaveDialog_fnUnadvise,
2566 IFileSaveDialog_fnSetOptions,
2567 IFileSaveDialog_fnGetOptions,
2568 IFileSaveDialog_fnSetDefaultFolder,
2569 IFileSaveDialog_fnSetFolder,
2570 IFileSaveDialog_fnGetFolder,
2571 IFileSaveDialog_fnGetCurrentSelection,
2572 IFileSaveDialog_fnSetFileName,
2573 IFileSaveDialog_fnGetFileName,
2574 IFileSaveDialog_fnSetTitle,
2575 IFileSaveDialog_fnSetOkButtonLabel,
2576 IFileSaveDialog_fnSetFileNameLabel,
2577 IFileSaveDialog_fnGetResult,
2578 IFileSaveDialog_fnAddPlace,
2579 IFileSaveDialog_fnSetDefaultExtension,
2580 IFileSaveDialog_fnClose,
2581 IFileSaveDialog_fnSetClientGuid,
2582 IFileSaveDialog_fnClearClientData,
2583 IFileSaveDialog_fnSetFilter,
2584 IFileSaveDialog_fnSetSaveAsItem,
2585 IFileSaveDialog_fnSetProperties,
2586 IFileSaveDialog_fnSetCollectedProperties,
2587 IFileSaveDialog_fnGetProperties,
2588 IFileSaveDialog_fnApplyProperties
2591 /**************************************************************************
2592 * IExplorerBrowserEvents implementation
2594 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
2596 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
2599 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
2600 REFIID riid, void **ppvObject)
2602 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2603 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2605 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2608 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
2610 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2611 TRACE("%p\n", This);
2612 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2615 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
2617 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2618 TRACE("%p\n", This);
2619 return IFileDialog2_Release(&This->IFileDialog2_iface);
2622 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
2623 PCIDLIST_ABSOLUTE pidlFolder)
2625 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2626 IShellItem *psi;
2627 HRESULT hr;
2628 TRACE("%p (%p)\n", This, pidlFolder);
2630 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
2631 if(SUCCEEDED(hr))
2633 hr = events_OnFolderChanging(This, psi);
2634 IShellItem_Release(psi);
2636 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
2637 if(hr == S_FALSE)
2638 hr = E_FAIL;
2640 return hr;
2642 else
2643 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
2645 return S_OK;
2648 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
2649 IShellView *psv)
2651 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2652 TRACE("%p (%p)\n", This, psv);
2653 return S_OK;
2656 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
2657 PCIDLIST_ABSOLUTE pidlFolder)
2659 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2660 HRESULT hr;
2661 TRACE("%p (%p)\n", This, pidlFolder);
2663 if(This->psi_folder)
2664 IShellItem_Release(This->psi_folder);
2666 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
2667 if(FAILED(hr))
2669 ERR("Failed to get the current folder.\n");
2670 This->psi_folder = NULL;
2673 events_OnFolderChange(This);
2675 return S_OK;
2678 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
2679 PCIDLIST_ABSOLUTE pidlFolder)
2681 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2682 TRACE("%p (%p)\n", This, pidlFolder);
2683 return S_OK;
2686 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
2687 IExplorerBrowserEvents_fnQueryInterface,
2688 IExplorerBrowserEvents_fnAddRef,
2689 IExplorerBrowserEvents_fnRelease,
2690 IExplorerBrowserEvents_fnOnNavigationPending,
2691 IExplorerBrowserEvents_fnOnViewCreated,
2692 IExplorerBrowserEvents_fnOnNavigationComplete,
2693 IExplorerBrowserEvents_fnOnNavigationFailed
2696 /**************************************************************************
2697 * IServiceProvider implementation
2699 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2701 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
2704 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
2705 REFIID riid, void **ppvObject)
2707 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2708 TRACE("%p\n", This);
2709 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2712 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
2714 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2715 TRACE("%p\n", This);
2716 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2719 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
2721 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2722 TRACE("%p\n", This);
2723 return IFileDialog2_Release(&This->IFileDialog2_iface);
2726 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
2727 REFGUID guidService,
2728 REFIID riid, void **ppv)
2730 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2731 HRESULT hr = E_FAIL;
2732 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
2734 *ppv = NULL;
2735 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
2736 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
2737 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
2738 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
2739 else
2740 FIXME("Interface %s requested from unknown service %s\n",
2741 debugstr_guid(riid), debugstr_guid(guidService));
2743 return hr;
2746 static const IServiceProviderVtbl vt_IServiceProvider = {
2747 IServiceProvider_fnQueryInterface,
2748 IServiceProvider_fnAddRef,
2749 IServiceProvider_fnRelease,
2750 IServiceProvider_fnQueryService
2753 /**************************************************************************
2754 * ICommDlgBrowser3 implementation
2756 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
2758 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
2761 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
2762 REFIID riid, void **ppvObject)
2764 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2765 TRACE("%p\n", This);
2766 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2769 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
2771 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2772 TRACE("%p\n", This);
2773 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2776 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
2778 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2779 TRACE("%p\n", This);
2780 return IFileDialog2_Release(&This->IFileDialog2_iface);
2783 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
2784 IShellView *shv)
2786 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2787 HRESULT hr;
2788 TRACE("%p (%p)\n", This, shv);
2790 hr = on_default_action(This);
2792 if(SUCCEEDED(hr))
2793 EndDialog(This->dlg_hwnd, S_OK);
2795 return S_OK;
2798 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
2799 IShellView *shv, ULONG uChange )
2801 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2802 IDataObject *new_selection;
2803 HRESULT hr;
2804 TRACE("%p (%p, %x)\n", This, shv, uChange);
2806 switch(uChange)
2808 case CDBOSC_SELCHANGE:
2809 if(This->psia_selection)
2811 IShellItemArray_Release(This->psia_selection);
2812 This->psia_selection = NULL;
2815 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
2816 if(SUCCEEDED(hr))
2818 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
2819 (void**)&This->psia_selection);
2820 if(SUCCEEDED(hr))
2822 fill_filename_from_selection(This);
2823 events_OnSelectionChange(This);
2826 IDataObject_Release(new_selection);
2828 break;
2829 default:
2830 TRACE("Unhandled state change\n");
2832 return S_OK;
2835 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
2836 IShellView *shv, LPCITEMIDLIST pidl)
2838 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2839 IShellItem *psi;
2840 LPWSTR filename;
2841 LPITEMIDLIST parent_pidl;
2842 HRESULT hr;
2843 ULONG attr;
2844 TRACE("%p (%p, %p)\n", This, shv, pidl);
2846 if(!This->filterspec_count)
2847 return S_OK;
2849 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
2850 if(SUCCEEDED(hr))
2852 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
2853 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
2854 ILFree(parent_pidl);
2855 ILFree(full_pidl);
2857 if(FAILED(hr))
2859 ERR("Failed to get shellitem (%08x).\n", hr);
2860 return S_OK;
2863 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
2864 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
2866 IShellItem_Release(psi);
2867 return S_OK;
2870 hr = S_OK;
2871 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
2873 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
2874 hr = S_FALSE;
2875 CoTaskMemFree(filename);
2878 IShellItem_Release(psi);
2879 return hr;
2882 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
2883 IShellView *ppshv, DWORD dwNotifyType)
2885 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2886 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
2887 return E_NOTIMPL;
2890 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
2891 IShellView *pshv,
2892 LPWSTR pszText, int cchMax)
2894 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2895 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
2896 return E_NOTIMPL;
2899 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
2901 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2902 FIXME("Stub: %p (%p)\n", This, pdwFlags);
2903 return E_NOTIMPL;
2906 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
2907 IShellView *pshv, int iColumn)
2909 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2910 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
2911 return E_NOTIMPL;
2914 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
2915 LPWSTR pszFileSpec, int cchFileSpec)
2917 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2918 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
2919 return E_NOTIMPL;
2922 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
2923 IShellView *pshv)
2925 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2926 FIXME("Stub: %p (%p)\n", This, pshv);
2927 return E_NOTIMPL;
2930 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
2931 ICommDlgBrowser3_fnQueryInterface,
2932 ICommDlgBrowser3_fnAddRef,
2933 ICommDlgBrowser3_fnRelease,
2934 ICommDlgBrowser3_fnOnDefaultCommand,
2935 ICommDlgBrowser3_fnOnStateChange,
2936 ICommDlgBrowser3_fnIncludeObject,
2937 ICommDlgBrowser3_fnNotify,
2938 ICommDlgBrowser3_fnGetDefaultMenuText,
2939 ICommDlgBrowser3_fnGetViewFlags,
2940 ICommDlgBrowser3_fnOnColumnClicked,
2941 ICommDlgBrowser3_fnGetCurrentFilter,
2942 ICommDlgBrowser3_fnOnPreviewCreated
2945 /**************************************************************************
2946 * IOleWindow implementation
2948 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
2950 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
2953 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
2955 FileDialogImpl *This = impl_from_IOleWindow(iface);
2956 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2959 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
2961 FileDialogImpl *This = impl_from_IOleWindow(iface);
2962 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2965 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
2967 FileDialogImpl *This = impl_from_IOleWindow(iface);
2968 return IFileDialog2_Release(&This->IFileDialog2_iface);
2971 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
2973 FileDialogImpl *This = impl_from_IOleWindow(iface);
2974 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
2975 return E_NOTIMPL;
2978 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
2980 FileDialogImpl *This = impl_from_IOleWindow(iface);
2981 TRACE("%p (%p)\n", This, phwnd);
2982 *phwnd = This->dlg_hwnd;
2983 return S_OK;
2986 static const IOleWindowVtbl vt_IOleWindow = {
2987 IOleWindow_fnQueryInterface,
2988 IOleWindow_fnAddRef,
2989 IOleWindow_fnRelease,
2990 IOleWindow_fnGetWindow,
2991 IOleWindow_fnContextSensitiveHelp
2994 /**************************************************************************
2995 * IFileDialogCustomize implementation
2997 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
2999 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3002 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3003 REFIID riid, void **ppvObject)
3005 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3006 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3009 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3011 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3012 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3015 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3017 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3018 return IFileDialog2_Release(&This->IFileDialog2_iface);
3021 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3022 DWORD dwIDCtl)
3024 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3025 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3026 return E_NOTIMPL;
3029 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3030 DWORD dwIDCtl,
3031 LPCWSTR pszLabel)
3033 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3034 customctrl *ctrl;
3035 TBBUTTON tbb;
3036 HRESULT hr;
3037 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3039 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3040 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3041 This->cctrl_def_height, &ctrl);
3042 if(SUCCEEDED(hr))
3044 ctrl->type = IDLG_CCTRL_MENU;
3046 /* Add the actual button with a popup menu. */
3047 tbb.iBitmap = I_IMAGENONE;
3048 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3049 tbb.iString = (DWORD_PTR)pszLabel;
3050 tbb.fsState = TBSTATE_ENABLED;
3051 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3052 tbb.idCommand = 1;
3054 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3057 return hr;
3060 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3061 DWORD dwIDCtl,
3062 LPCWSTR pszLabel)
3064 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3065 customctrl *ctrl;
3066 HRESULT hr;
3067 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3069 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3070 This->cctrl_def_height, &ctrl);
3071 if(SUCCEEDED(hr))
3072 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3074 return hr;
3077 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3078 DWORD dwIDCtl)
3080 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3081 customctrl *ctrl;
3082 HRESULT hr;
3083 TRACE("%p (%d)\n", This, dwIDCtl);
3085 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3086 This->cctrl_def_height, &ctrl);
3087 if(SUCCEEDED(hr))
3088 ctrl->type = IDLG_CCTRL_COMBOBOX;
3090 return hr;
3093 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3094 DWORD dwIDCtl)
3096 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3097 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3098 return E_NOTIMPL;
3101 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3102 DWORD dwIDCtl,
3103 LPCWSTR pszLabel,
3104 BOOL bChecked)
3106 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3107 customctrl *ctrl;
3108 HRESULT hr;
3109 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3111 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX, 0,
3112 This->cctrl_def_height, &ctrl);
3113 if(SUCCEEDED(hr))
3115 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3116 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3119 return hr;
3122 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3123 DWORD dwIDCtl,
3124 LPCWSTR pszText)
3126 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3127 customctrl *ctrl;
3128 HRESULT hr;
3129 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3131 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3132 This->cctrl_def_height, &ctrl);
3133 if(SUCCEEDED(hr))
3134 ctrl->type = IDLG_CCTRL_EDITBOX;
3136 return hr;
3139 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3140 DWORD dwIDCtl)
3142 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3143 customctrl *ctrl;
3144 HRESULT hr;
3145 TRACE("%p (%d)\n", This, dwIDCtl);
3147 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3148 GetSystemMetrics(SM_CYEDGE), &ctrl);
3149 if(SUCCEEDED(hr))
3150 ctrl->type = IDLG_CCTRL_SEPARATOR;
3152 return hr;
3155 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3156 DWORD dwIDCtl,
3157 LPCWSTR pszText)
3159 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3160 customctrl *ctrl;
3161 HRESULT hr;
3162 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3164 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3165 This->cctrl_def_height, &ctrl);
3166 if(SUCCEEDED(hr))
3167 ctrl->type = IDLG_CCTRL_TEXT;
3169 return hr;
3172 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3173 DWORD dwIDCtl,
3174 LPCWSTR pszLabel)
3176 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3177 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3178 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3180 if(!ctrl) return E_INVALIDARG;
3182 switch(ctrl->type)
3184 case IDLG_CCTRL_MENU:
3185 case IDLG_CCTRL_PUSHBUTTON:
3186 case IDLG_CCTRL_CHECKBUTTON:
3187 case IDLG_CCTRL_TEXT:
3188 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3189 break;
3190 default:
3191 break;
3194 return S_OK;
3197 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3198 DWORD dwIDCtl,
3199 CDCONTROLSTATEF *pdwState)
3201 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3202 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3203 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3205 if(!ctrl) return E_NOTIMPL;
3207 *pdwState = ctrl->cdcstate;
3208 return S_OK;
3211 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3212 DWORD dwIDCtl,
3213 CDCONTROLSTATEF dwState)
3215 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3216 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3217 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3219 if(ctrl)
3221 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3223 if(dwState & CDCS_ENABLED)
3224 wndstyle &= ~(WS_DISABLED);
3225 else
3226 wndstyle |= WS_DISABLED;
3228 if(dwState & CDCS_VISIBLE)
3229 wndstyle |= WS_VISIBLE;
3230 else
3231 wndstyle &= ~(WS_VISIBLE);
3233 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3235 /* We save the state separately since at least one application
3236 * relies on being able to hide a control. */
3237 ctrl->cdcstate = dwState;
3240 return S_OK;
3243 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3244 DWORD dwIDCtl,
3245 WCHAR **ppszText)
3247 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3248 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3249 WCHAR len, *text;
3250 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
3252 if(!ctrl || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3253 return E_FAIL;
3255 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3256 if(!text) return E_FAIL;
3258 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3259 *ppszText = text;
3260 return S_OK;
3263 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
3264 DWORD dwIDCtl,
3265 LPCWSTR pszText)
3267 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3268 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3269 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
3271 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
3272 return E_FAIL;
3274 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
3275 return S_OK;
3278 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
3279 DWORD dwIDCtl,
3280 BOOL *pbChecked)
3282 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3283 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3284 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
3286 if(ctrl)
3287 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
3289 return S_OK;
3292 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
3293 DWORD dwIDCtl,
3294 BOOL bChecked)
3296 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3297 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3298 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
3300 if(ctrl)
3301 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
3303 return S_OK;
3306 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
3308 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
3309 UINT i;
3310 if(!count || (count == CB_ERR))
3311 return -1;
3313 for(i = 0; i < count; i++)
3314 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3315 return i;
3317 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
3318 return -1;
3321 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
3322 DWORD dwIDCtl,
3323 DWORD dwIDItem,
3324 LPCWSTR pszLabel)
3326 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3327 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3328 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3330 if(!ctrl) return E_FAIL;
3332 switch(ctrl->type)
3334 case IDLG_CCTRL_COMBOBOX:
3336 UINT index;
3338 if(get_combobox_index_from_id(ctrl->hwnd, dwIDItem) != -1)
3339 return E_INVALIDARG;
3341 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
3342 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
3344 return S_OK;
3346 case IDLG_CCTRL_MENU:
3348 TBBUTTON tbb;
3349 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3351 if(GetMenuState((HMENU)tbb.dwData, dwIDItem, MF_BYCOMMAND) != -1)
3352 return E_INVALIDARG;
3354 AppendMenuW((HMENU)tbb.dwData, MF_STRING, dwIDItem, pszLabel);
3355 return S_OK;
3357 default:
3358 break;
3361 return E_NOINTERFACE; /* win7 */
3364 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
3365 DWORD dwIDCtl,
3366 DWORD dwIDItem)
3368 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3369 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3370 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3372 if(!ctrl) return E_FAIL;
3374 switch(ctrl->type)
3376 case IDLG_CCTRL_COMBOBOX:
3378 UINT i, count = SendMessageW(ctrl->hwnd, CB_GETCOUNT, 0, 0);
3379 if(!count || (count == CB_ERR))
3380 return E_FAIL;
3382 for(i = 0; i < count; i++)
3383 if(SendMessageW(ctrl->hwnd, CB_GETITEMDATA, 0, 0) == dwIDItem)
3385 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, i, 0) == CB_ERR)
3386 return E_FAIL;
3387 return S_OK;
3390 return E_UNEXPECTED;
3392 case IDLG_CCTRL_MENU:
3394 TBBUTTON tbb;
3395 HMENU hmenu;
3396 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3397 hmenu = (HMENU)tbb.dwData;
3399 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
3400 return E_UNEXPECTED;
3402 return S_OK;
3404 default:
3405 break;
3408 return E_FAIL;
3411 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
3412 DWORD dwIDCtl)
3414 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3415 TRACE("%p (%d)\n", This, dwIDCtl);
3417 /* Not implemented by native */
3418 return E_NOTIMPL;
3421 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
3422 DWORD dwIDCtl,
3423 DWORD dwIDItem,
3424 CDCONTROLSTATEF *pdwState)
3426 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3427 FIXME("stub - %p\n", This);
3428 return E_NOTIMPL;
3431 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
3432 DWORD dwIDCtl,
3433 DWORD dwIDItem,
3434 CDCONTROLSTATEF dwState)
3436 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3437 FIXME("stub - %p\n", This);
3438 return E_NOTIMPL;
3441 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
3442 DWORD dwIDCtl,
3443 DWORD *pdwIDItem)
3445 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3446 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3447 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
3449 if(!ctrl) return E_FAIL;
3451 switch(ctrl->type)
3453 case IDLG_CCTRL_COMBOBOX:
3455 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
3456 if(index == CB_ERR)
3457 return E_FAIL;
3459 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
3460 return S_OK;
3462 default:
3463 FIXME("Unsupported control type %d\n", ctrl->type);
3466 return E_NOTIMPL;
3469 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
3470 DWORD dwIDCtl,
3471 DWORD dwIDItem)
3473 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3474 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3475 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3477 if(!ctrl) return E_INVALIDARG;
3479 switch(ctrl->type)
3481 case IDLG_CCTRL_COMBOBOX:
3483 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
3485 if(index == -1)
3486 return E_INVALIDARG;
3488 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
3489 return E_FAIL;
3491 return S_OK;
3493 default:
3494 FIXME("Unsupported control type %d\n", ctrl->type);
3497 return E_INVALIDARG;
3500 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
3501 DWORD dwIDCtl,
3502 LPCWSTR pszLabel)
3504 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3505 FIXME("stub - %p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
3506 return E_NOTIMPL;
3509 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
3511 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3512 FIXME("stub - %p\n", This);
3513 return E_NOTIMPL;
3516 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
3517 DWORD dwIDCtl)
3519 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3520 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3521 return E_NOTIMPL;
3524 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
3525 DWORD dwIDCtl,
3526 DWORD dwIDItem,
3527 LPCWSTR pszLabel)
3529 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3530 FIXME("stub - %p (%d, %d, %p)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3531 return E_NOTIMPL;
3534 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
3535 IFileDialogCustomize_fnQueryInterface,
3536 IFileDialogCustomize_fnAddRef,
3537 IFileDialogCustomize_fnRelease,
3538 IFileDialogCustomize_fnEnableOpenDropDown,
3539 IFileDialogCustomize_fnAddMenu,
3540 IFileDialogCustomize_fnAddPushButton,
3541 IFileDialogCustomize_fnAddComboBox,
3542 IFileDialogCustomize_fnAddRadioButtonList,
3543 IFileDialogCustomize_fnAddCheckButton,
3544 IFileDialogCustomize_fnAddEditBox,
3545 IFileDialogCustomize_fnAddSeparator,
3546 IFileDialogCustomize_fnAddText,
3547 IFileDialogCustomize_fnSetControlLabel,
3548 IFileDialogCustomize_fnGetControlState,
3549 IFileDialogCustomize_fnSetControlState,
3550 IFileDialogCustomize_fnGetEditBoxText,
3551 IFileDialogCustomize_fnSetEditBoxText,
3552 IFileDialogCustomize_fnGetCheckButtonState,
3553 IFileDialogCustomize_fnSetCheckButtonState,
3554 IFileDialogCustomize_fnAddControlItem,
3555 IFileDialogCustomize_fnRemoveControlItem,
3556 IFileDialogCustomize_fnRemoveAllControlItems,
3557 IFileDialogCustomize_fnGetControlItemState,
3558 IFileDialogCustomize_fnSetControlItemState,
3559 IFileDialogCustomize_fnGetSelectedControlItem,
3560 IFileDialogCustomize_fnSetSelectedControlItem,
3561 IFileDialogCustomize_fnStartVisualGroup,
3562 IFileDialogCustomize_fnEndVisualGroup,
3563 IFileDialogCustomize_fnMakeProminent,
3564 IFileDialogCustomize_fnSetControlItemText
3567 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
3569 FileDialogImpl *fdimpl;
3570 HRESULT hr;
3571 IShellFolder *psf;
3572 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
3574 if(!ppv)
3575 return E_POINTER;
3576 if(pUnkOuter)
3577 return CLASS_E_NOAGGREGATION;
3579 fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
3580 if(!fdimpl)
3581 return E_OUTOFMEMORY;
3583 fdimpl->ref = 1;
3584 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
3585 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
3586 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
3587 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
3588 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
3589 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
3591 if(type == ITEMDLG_TYPE_OPEN)
3593 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
3594 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
3595 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
3596 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
3598 else
3600 WCHAR buf[16];
3601 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
3602 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
3603 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
3605 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
3606 fdimpl->custom_title = StrDupW(buf);
3607 fdimpl->custom_okbutton = StrDupW(buf);
3610 fdimpl->filterspecs = NULL;
3611 fdimpl->filterspec_count = 0;
3612 fdimpl->filetypeindex = 0;
3614 fdimpl->psia_selection = fdimpl->psia_results = NULL;
3615 fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
3617 list_init(&fdimpl->events_clients);
3618 fdimpl->events_next_cookie = 0;
3620 fdimpl->dlg_hwnd = NULL;
3621 fdimpl->peb = NULL;
3623 fdimpl->set_filename = NULL;
3624 fdimpl->default_ext = NULL;
3625 fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL;
3627 /* FIXME: The default folder setting should be restored for the
3628 * application if it was previously set. */
3629 SHGetDesktopFolder(&psf);
3630 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
3631 IShellFolder_Release(psf);
3633 hr = init_custom_controls(fdimpl);
3634 if(FAILED(hr))
3636 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
3637 IUnknown_Release((IUnknown*)fdimpl);
3638 return E_FAIL;
3641 hr = IUnknown_QueryInterface((IUnknown*)fdimpl, riid, ppv);
3642 IUnknown_Release((IUnknown*)fdimpl);
3643 return hr;
3646 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3648 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
3651 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3653 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);