gdiplus: Don't bother to free memory at process exit.
[wine/wine-gecko.git] / dlls / comdlg32 / itemdlg.c
blob33398b5741af69caf0f62c2b8e5bde4352df5a48
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 = NULL, tmp_files;
411 UINT file_count = 0, len, i;
412 int open_action;
413 HRESULT hr, ret = E_FAIL;
415 len = get_file_name(This, &tmp_files);
416 if(len)
418 UINT size_used;
419 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
420 CoTaskMemFree(tmp_files);
422 if(!file_count) return E_FAIL;
424 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
425 if(FAILED(hr))
427 ERR("Failed to get pidl for current directory.\n");
428 HeapFree(GetProcessHeap(), 0, files);
429 return hr;
432 TRACE("Acting on %d file(s).\n", file_count);
434 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
435 open_action = ONOPEN_OPEN;
436 fn_iter = files;
438 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
440 WCHAR canon_filename[MAX_PATH];
441 psf_parent = NULL;
443 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
445 if( (This->options & FOS_NOVALIDATE) &&
446 !(This->options & FOS_FILEMUSTEXIST) )
447 open_action = ONOPEN_OPEN;
448 else
449 open_action = ONOPEN_BROWSE;
451 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
452 This->options & ~FOS_FILEMUSTEXIST,
453 (This->dlg_type == ITEMDLG_TYPE_SAVE),
454 open_action);
456 /* Add the proper extension */
457 if(open_action == ONOPEN_OPEN)
459 static const WCHAR dotW[] = {'.',0};
461 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
463 WCHAR extbuf[MAX_PATH], *newext = NULL;
465 if(This->filterspec_count)
467 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
469 else if(This->default_ext)
471 lstrcpyW(extbuf, dotW);
472 lstrcatW(extbuf, This->default_ext);
473 newext = extbuf;
476 if(newext)
478 WCHAR *ext = PathFindExtensionW(canon_filename);
479 if(lstrcmpW(ext, newext))
480 lstrcatW(canon_filename, newext);
483 else
485 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
486 !PathFileExistsW(canon_filename))
488 if(This->default_ext)
490 lstrcatW(canon_filename, dotW);
491 lstrcatW(canon_filename, This->default_ext);
493 if(!PathFileExistsW(canon_filename))
495 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
496 open_action = ONOPEN_BROWSE;
499 else
501 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
502 open_action = ONOPEN_BROWSE;
508 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
510 if(psf_parent && !(open_action == ONOPEN_BROWSE))
511 IShellFolder_Release(psf_parent);
513 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
516 HeapFree(GetProcessHeap(), 0, files);
517 ILFree(current_folder);
519 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
520 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
522 switch(open_action)
524 case ONOPEN_SEARCH:
525 FIXME("Filtering not implemented.\n");
526 break;
528 case ONOPEN_BROWSE:
529 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
530 if(FAILED(hr))
531 ERR("Failed to browse to directory: %08x\n", hr);
533 IShellFolder_Release(psf_parent);
534 break;
536 case ONOPEN_OPEN:
537 if(events_OnFileOk(This) != S_OK)
538 break;
540 hr = SHGetDesktopFolder(&psf_desktop);
541 if(SUCCEEDED(hr))
543 if(This->psia_results)
544 IShellItemArray_Release(This->psia_results);
546 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
547 &This->psia_results);
548 if(SUCCEEDED(hr))
549 ret = S_OK;
551 IShellFolder_Release(psf_desktop);
553 break;
555 default:
556 ERR("Failed.\n");
557 break;
560 /* Clean up */
561 for(i = 0; i < file_count; i++)
562 ILFree(pidla[i]);
563 HeapFree(GetProcessHeap(), 0, pidla);
565 /* Success closes the dialog */
566 return ret;
569 /**************************************************************************
570 * Control functions.
572 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
574 customctrl *ctrl;
576 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
577 if(ctrl->dlgid == dlgid)
578 return ctrl;
580 ERR("Failed to find control with dialog id %d\n", dlgid);
581 return NULL;
584 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
586 customctrl *ctrl;
588 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
589 if(ctrl->id == ctlid)
590 return ctrl;
592 ERR("Failed to find control with control id %d\n", ctlid);
593 return NULL;
596 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
598 LPWSTR text;
599 UINT len, final_width;
600 UINT lines, final_height;
601 SIZE size;
602 RECT rc;
603 HDC hdc;
604 WCHAR *c;
606 TRACE("\n");
608 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
609 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
610 if(!text) return;
611 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
613 hdc = GetDC(hctrl);
614 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
615 ReleaseDC(hctrl, hdc);
617 if(len && multiline)
619 /* FIXME: line-wrap */
620 for(lines = 1, c = text; *c != '\0'; c++)
621 if(*c == '\n') lines++;
623 final_height = size.cy*lines + 2*4;
625 else
627 GetWindowRect(hctrl, &rc);
628 final_height = rc.bottom - rc.top;
631 final_width = min(max(size.cx, min_width) + 4, max_width);
632 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
633 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
635 HeapFree(GetProcessHeap(), 0, text);
638 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
640 RECT rc;
642 switch(ctrl->type)
644 case IDLG_CCTRL_PUSHBUTTON:
645 case IDLG_CCTRL_COMBOBOX:
646 case IDLG_CCTRL_CHECKBUTTON:
647 case IDLG_CCTRL_TEXT:
648 ctrl_resize(ctrl->hwnd, 160, 160, TRUE);
649 GetWindowRect(ctrl->hwnd, &rc);
650 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
651 SWP_NOZORDER|SWP_NOMOVE|SWP_NOZORDER);
652 break;
653 case IDLG_CCTRL_RADIOBUTTONLIST:
654 case IDLG_CCTRL_EDITBOX:
655 case IDLG_CCTRL_SEPARATOR:
656 case IDLG_CCTRL_MENU:
657 /* Nothing */
658 break;
662 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
664 FileDialogImpl *This = crs->lpCreateParams;
665 TRACE("%p\n", This);
667 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
668 return TRUE;
671 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
673 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
675 TRACE("%p, %lx\n", This, wparam);
677 if(ctrl)
679 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
681 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
682 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
684 else
685 cctrl_event_OnButtonClicked(This, ctrl->id);
688 return TRUE;
691 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
693 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
694 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
696 if(ctrl)
698 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
699 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
701 cctrl_event_OnItemSelected(This, ctrl->id, selid);
703 return TRUE;
706 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
708 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
709 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
710 POINT pt = { 0, nmtb->rcButton.bottom };
711 TBBUTTON tbb;
712 UINT idcmd;
714 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
716 if(ctrl)
718 cctrl_event_OnControlActivating(This,ctrl->id);
720 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
721 ClientToScreen(ctrl->hwnd, &pt);
722 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
723 if(idcmd)
724 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
727 return TBDDRET_DEFAULT;
730 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
732 switch(HIWORD(wparam))
734 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
735 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
738 return FALSE;
741 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
743 NMHDR *nmhdr = (NMHDR*)lparam;
745 switch(nmhdr->code)
747 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
750 return FALSE;
753 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
755 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
756 HWND hwnd_child;
757 RECT rc;
759 switch(message)
761 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
762 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
763 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
764 case WM_SIZE:
765 hwnd_child = GetPropW(hwnd, notifysink_childW);
766 GetClientRect(hwnd, &rc);
767 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
768 return TRUE;
771 return DefWindowProcW(hwnd, message, wparam, lparam);
774 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
775 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
776 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
778 HWND ns_hwnd, control_hwnd;
779 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
780 customctrl *ctrl;
782 if(get_cctrl(This, id))
783 return E_UNEXPECTED; /* Duplicate id */
785 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
786 0, 0, This->cctrl_width, height, This->cctrls_hwnd,
787 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
788 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
789 0, 0, This->cctrl_width, height, ns_hwnd,
790 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
792 if(!ns_hwnd || !control_hwnd)
794 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
795 DestroyWindow(ns_hwnd);
796 DestroyWindow(control_hwnd);
798 return E_FAIL;
801 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
803 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
804 if(!ctrl)
805 return E_OUTOFMEMORY;
807 ctrl->hwnd = control_hwnd;
808 ctrl->wrapper_hwnd = ns_hwnd;
809 ctrl->id = id;
810 ctrl->dlgid = This->cctrl_next_dlgid;
811 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
812 list_add_tail(&This->cctrls, &ctrl->entry);
813 if(ppctrl) *ppctrl = ctrl;
815 This->cctrl_next_dlgid++;
816 return S_OK;
819 /**************************************************************************
820 * Container functions.
822 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
824 UINT container_height;
825 UINT column_width;
826 UINT nr_of_cols;
827 UINT max_control_height, total_height = 0;
828 UINT cur_col_pos, cur_row_pos;
829 customctrl *ctrl;
830 BOOL fits_height;
831 static const UINT col_indent = 100; /* The first column is indented 100px */
832 static const UINT cspacing = 90; /* Columns are spaced with 90px */
833 static const UINT rspacing = 4; /* Rows are spaced with 4 px. */
835 /* Given the new width of the container, this function determines the
836 * needed height of the container and places the controls according to
837 * the new layout. Returns the new height.
840 TRACE("%p\n", This);
842 column_width = This->cctrl_width + cspacing;
843 nr_of_cols = (container_width - col_indent + cspacing) / column_width;
845 /* We don't need to do anything unless the number of visible columns has changed. */
846 if(nr_of_cols == This->cctrls_cols)
848 RECT rc;
849 GetWindowRect(This->cctrls_hwnd, &rc);
850 return rc.bottom - rc.top;
853 This->cctrls_cols = nr_of_cols;
855 /* Get the size of the tallest control, and the total size of
856 * all the controls to figure out the number of slots we need.
858 max_control_height = 0;
859 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
861 if(ctrl->cdcstate & CDCS_VISIBLE)
863 RECT rc;
864 UINT control_height;
865 GetWindowRect(ctrl->wrapper_hwnd, &rc);
866 control_height = rc.bottom - rc.top;
867 max_control_height = max(max_control_height, control_height);
869 total_height += control_height + rspacing;
873 if(!total_height)
874 return 0;
876 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
877 TRACE("Guess: container_height: %d\n",container_height);
879 /* Incrementally increase container_height until all the controls
880 * fit.
882 do {
883 UINT columns_needed = 1;
884 cur_row_pos = 0;
886 fits_height = TRUE;
887 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
889 if(ctrl->cdcstate & CDCS_VISIBLE)
891 RECT rc;
892 UINT control_height;
893 GetWindowRect(ctrl->wrapper_hwnd, &rc);
894 control_height = rc.bottom - rc.top;
896 if(cur_row_pos + control_height > container_height)
898 if(++columns_needed > nr_of_cols)
900 container_height += 1;
901 fits_height = FALSE;
902 break;
904 cur_row_pos = 0;
907 cur_row_pos += control_height + rspacing;
910 } while(!fits_height);
912 TRACE("Final container height: %d\n", container_height);
914 /* Move the controls to their final destination
916 cur_col_pos = col_indent, cur_row_pos = 0;
917 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
919 if(ctrl->cdcstate & CDCS_VISIBLE)
921 RECT rc;
922 UINT control_height;
923 GetWindowRect(ctrl->wrapper_hwnd, &rc);
924 control_height = rc.bottom - rc.top;
926 if(cur_row_pos + control_height > container_height)
928 cur_row_pos = 0;
929 cur_col_pos += This->cctrl_width + cspacing;
932 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos, cur_row_pos, 0, 0,
933 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
935 cur_row_pos += control_height + rspacing;
939 /* Sanity check */
940 if(cur_row_pos + This->cctrl_width > container_width)
941 ERR("-- Failed to place controls properly.\n");
943 return container_height;
946 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
948 LONG wndstyle;
950 if(parent)
952 customctrl *ctrl;
953 HFONT font;
955 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
956 wndstyle &= ~(WS_POPUP);
957 wndstyle |= WS_CHILD;
958 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
960 SetParent(This->cctrls_hwnd, parent);
961 ShowWindow(This->cctrls_hwnd, TRUE);
963 /* Set the fonts to match the dialog font. */
964 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
965 if(!font)
966 ERR("Failed to get font handle from dialog.\n");
968 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
970 if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
971 customctrl_resize(This, ctrl);
974 else
976 ShowWindow(This->cctrls_hwnd, FALSE);
978 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
979 wndstyle &= ~(WS_CHILD);
980 wndstyle |= WS_POPUP;
981 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
983 SetParent(This->cctrls_hwnd, NULL);
987 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
989 FileDialogImpl *This = crs->lpCreateParams;
990 TRACE("%p\n", This);
992 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
993 return TRUE;
996 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
998 customctrl *cur1, *cur2;
999 TRACE("%p\n", This);
1001 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1003 TRACE("Freeing control %p\n", cur1);
1004 list_remove(&cur1->entry);
1006 if(cur1->type == IDLG_CCTRL_MENU)
1008 TBBUTTON tbb;
1009 SendMessageW(cur1->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1010 DestroyMenu((HMENU)tbb.dwData);
1013 DestroyWindow(cur1->hwnd);
1014 HeapFree(GetProcessHeap(), 0, cur1);
1017 return TRUE;
1020 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1022 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1024 switch(umessage)
1026 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1027 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1028 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1031 return FALSE;
1034 static HRESULT init_custom_controls(FileDialogImpl *This)
1036 WNDCLASSW wc;
1037 static const WCHAR ctrl_container_classname[] =
1038 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1040 InitCommonControlsEx(NULL);
1042 This->cctrl_width = 160; /* Controls have a fixed width */
1043 This->cctrl_def_height = 23;
1044 This->cctrls_cols = 0;
1046 This->cctrl_next_dlgid = 0x2000;
1047 list_init(&This->cctrls);
1049 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1051 wc.style = CS_HREDRAW | CS_VREDRAW;
1052 wc.lpfnWndProc = ctrl_container_wndproc;
1053 wc.cbClsExtra = 0;
1054 wc.cbWndExtra = 0;
1055 wc.hInstance = COMDLG32_hInstance;
1056 wc.hIcon = 0;
1057 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1058 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1059 wc.lpszMenuName = NULL;
1060 wc.lpszClassName = ctrl_container_classname;
1062 if(!RegisterClassW(&wc)) return E_FAIL;
1065 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1066 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1067 0, 0, 0, 0, NULL, 0,
1068 COMDLG32_hInstance, (void*)This);
1069 if(!This->cctrls_hwnd)
1070 return E_FAIL;
1072 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1074 /* Register class for */
1075 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1076 wc.hInstance != COMDLG32_hInstance)
1078 wc.style = CS_HREDRAW | CS_VREDRAW;
1079 wc.lpfnWndProc = notifysink_proc;
1080 wc.cbClsExtra = 0;
1081 wc.cbWndExtra = 0;
1082 wc.hInstance = COMDLG32_hInstance;
1083 wc.hIcon = 0;
1084 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1085 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1086 wc.lpszMenuName = NULL;
1087 wc.lpszClassName = floatnotifysinkW;
1089 if (!RegisterClassW(&wc))
1090 ERR("Failed to register FloatNotifySink window class.\n");
1093 return S_OK;
1096 /**************************************************************************
1097 * Window related functions.
1099 static SIZE update_layout(FileDialogImpl *This)
1101 HDWP hdwp;
1102 HWND hwnd;
1103 RECT dialog_rc;
1104 RECT cancel_rc, open_rc;
1105 RECT filetype_rc, filename_rc, filenamelabel_rc;
1106 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1107 int missing_width, missing_height;
1108 static const UINT vspacing = 4, hspacing = 4;
1109 SIZE ret;
1111 GetClientRect(This->dlg_hwnd, &dialog_rc);
1113 missing_width = max(0, 320 - dialog_rc.right);
1114 missing_height = max(0, 200 - dialog_rc.bottom);
1116 if(missing_width || missing_height)
1118 TRACE("Missing (%d, %d)\n", missing_width, missing_height);
1119 ret.cx = missing_width;
1120 ret.cy = missing_height;
1121 return ret;
1124 /****
1125 * Calculate the size of the dialog and all the parts.
1128 /* Cancel button */
1129 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1130 if(hwnd)
1132 int cancel_width, cancel_height;
1133 GetWindowRect(hwnd, &cancel_rc);
1134 cancel_width = cancel_rc.right - cancel_rc.left;
1135 cancel_height = cancel_rc.bottom - cancel_rc.top;
1137 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1138 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1139 cancel_rc.right = cancel_rc.left + cancel_width;
1140 cancel_rc.bottom = cancel_rc.top + cancel_height;
1143 /* Open/Save button */
1144 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1145 if(hwnd)
1147 int open_width, open_height;
1148 GetWindowRect(hwnd, &open_rc);
1149 open_width = open_rc.right - open_rc.left;
1150 open_height = open_rc.bottom - open_rc.top;
1152 open_rc.left = cancel_rc.left - open_width - hspacing;
1153 open_rc.top = cancel_rc.top;
1154 open_rc.right = open_rc.left + open_width;
1155 open_rc.bottom = open_rc.top + open_height;
1158 /* The filetype combobox. */
1159 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1160 if(hwnd)
1162 int filetype_width, filetype_height;
1163 GetWindowRect(hwnd, &filetype_rc);
1165 filetype_width = filetype_rc.right - filetype_rc.left;
1166 filetype_height = filetype_rc.bottom - filetype_rc.top;
1168 filetype_rc.right = cancel_rc.right;
1170 filetype_rc.left = filetype_rc.right - filetype_width;
1171 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1172 filetype_rc.bottom = filetype_rc.top + filetype_height;
1174 if(!This->filterspec_count)
1175 filetype_rc.left = filetype_rc.right;
1178 /* Filename label. */
1179 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1180 if(hwnd)
1182 int filetypelabel_width, filetypelabel_height;
1183 GetWindowRect(hwnd, &filenamelabel_rc);
1185 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1186 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1188 filenamelabel_rc.left = 160; /* FIXME */
1189 filenamelabel_rc.top = filetype_rc.top;
1190 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1191 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1194 /* Filename edit box. */
1195 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1196 if(hwnd)
1198 int filename_width, filename_height;
1199 GetWindowRect(hwnd, &filename_rc);
1201 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1202 filename_height = filename_rc.bottom - filename_rc.top;
1204 filename_rc.left = filenamelabel_rc.right + hspacing;
1205 filename_rc.top = filetype_rc.top;
1206 filename_rc.right = filename_rc.left + filename_width;
1207 filename_rc.bottom = filename_rc.top + filename_height;
1210 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1211 if(hwnd)
1213 GetWindowRect(hwnd, &toolbar_rc);
1214 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1217 /* The custom controls */
1218 customctrls_rc.left = dialog_rc.left + hspacing;
1219 customctrls_rc.right = dialog_rc.right - hspacing;
1220 customctrls_rc.bottom = filename_rc.top - vspacing;
1221 customctrls_rc.top = customctrls_rc.bottom -
1222 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1224 /* The ExplorerBrowser control. */
1225 ebrowser_rc.left = dialog_rc.left + hspacing;
1226 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1227 ebrowser_rc.right = dialog_rc.right - hspacing;
1228 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1230 /****
1231 * Move everything to the right place.
1234 /* FIXME: The Save Dialog uses a slightly different layout. */
1235 hdwp = BeginDeferWindowPos(7);
1237 if(hdwp && This->peb)
1238 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1240 if(hdwp && This->cctrls_hwnd)
1241 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1242 customctrls_rc.left, customctrls_rc.top,
1243 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1244 SWP_NOZORDER | SWP_NOACTIVATE);
1246 /* The default controls */
1247 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1248 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1249 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1251 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1252 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1253 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1254 SWP_NOZORDER | SWP_NOACTIVATE);
1256 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1257 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1258 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1260 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1261 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1262 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1264 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1265 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1266 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1268 if(hdwp)
1269 EndDeferWindowPos(hdwp);
1270 else
1271 ERR("Failed to position dialog controls.\n");
1273 ret.cx = 0; ret.cy = 0;
1274 return ret;
1277 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1279 IShellItem *psi_folder;
1280 FOLDERSETTINGS fos;
1281 RECT rc = {0};
1282 HRESULT hr;
1284 /* Create ExplorerBrowser instance */
1285 OleInitialize(NULL);
1287 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1288 &IID_IExplorerBrowser, (void**)&This->peb);
1289 if(FAILED(hr))
1291 ERR("Failed to instantiate ExplorerBrowser control.\n");
1292 return hr;
1295 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES);
1297 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1298 if(FAILED(hr))
1300 ERR("Failed to initialize the ExplorerBrowser control.\n");
1301 IExplorerBrowser_Release(This->peb);
1302 This->peb = NULL;
1303 return hr;
1305 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1306 if(FAILED(hr))
1307 ERR("Advise (ExplorerBrowser) failed.\n");
1309 /* Get previous options? */
1310 fos.ViewMode = fos.fFlags = 0;
1311 if(!(This->options & FOS_ALLOWMULTISELECT))
1312 fos.fFlags |= FWF_SINGLESEL;
1314 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1316 hr = IUnknown_SetSite((IUnknown*)This->peb, (IUnknown*)This);
1317 if(FAILED(hr))
1318 ERR("SetSite (ExplorerBrowser) failed.\n");
1320 /* Browse somewhere */
1321 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1322 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1324 return S_OK;
1327 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1329 HWND htoolbar;
1330 TBADDBITMAP tbab;
1331 TBBUTTON button[2];
1333 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1334 0, 0, 0, 0,
1335 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1337 tbab.hInst = HINST_COMMCTRL;
1338 tbab.nID = IDB_HIST_LARGE_COLOR;
1339 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1341 button[0].iBitmap = HIST_BACK;
1342 button[0].idCommand = IDC_NAVBACK;
1343 button[0].fsState = TBSTATE_ENABLED;
1344 button[0].fsStyle = BTNS_BUTTON;
1345 button[0].dwData = 0;
1346 button[0].iString = 0;
1348 button[1].iBitmap = HIST_FORWARD;
1349 button[1].idCommand = IDC_NAVFORWARD;
1350 button[1].fsState = TBSTATE_ENABLED;
1351 button[1].fsStyle = BTNS_BUTTON;
1352 button[1].dwData = 0;
1353 button[1].iString = 0;
1355 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1356 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1357 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1360 static void update_control_text(FileDialogImpl *This)
1362 HWND hitem;
1363 if(This->custom_title)
1364 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1366 if(This->custom_okbutton &&
1367 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1369 SetWindowTextW(hitem, This->custom_okbutton);
1370 ctrl_resize(hitem, 50, 250, FALSE);
1373 if(This->custom_cancelbutton &&
1374 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1376 SetWindowTextW(hitem, This->custom_cancelbutton);
1377 ctrl_resize(hitem, 50, 250, FALSE);
1380 if(This->custom_filenamelabel &&
1381 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1383 SetWindowTextW(hitem, This->custom_filenamelabel);
1384 ctrl_resize(hitem, 50, 250, FALSE);
1388 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1390 FileDialogImpl *This = (FileDialogImpl*)lParam;
1391 HWND hitem;
1393 TRACE("(%p, %p)\n", This, hwnd);
1395 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1396 This->dlg_hwnd = hwnd;
1398 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1399 if(hitem) ShowWindow(hitem, SW_HIDE);
1401 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1402 if(hitem) ShowWindow(hitem, SW_HIDE);
1404 /* Fill filetypes combobox, or hide it. */
1405 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1406 if(This->filterspec_count)
1408 UINT i;
1409 for(i = 0; i < This->filterspec_count; i++)
1410 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
1412 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
1414 else
1415 ShowWindow(hitem, SW_HIDE);
1417 if(This->set_filename &&
1418 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1419 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
1421 ctrl_container_reparent(This, This->dlg_hwnd);
1422 init_explorerbrowser(This);
1423 init_toolbar(This, hwnd);
1424 update_control_text(This);
1425 update_layout(This);
1427 return TRUE;
1430 static LRESULT on_wm_size(FileDialogImpl *This)
1432 update_layout(This);
1433 return FALSE;
1436 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
1438 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
1439 TRACE("%p (%p)\n", This, mmi);
1441 /* FIXME */
1442 mmi->ptMinTrackSize.x = 640;
1443 mmi->ptMinTrackSize.y = 480;
1445 return FALSE;
1448 static LRESULT on_wm_destroy(FileDialogImpl *This)
1450 TRACE("%p\n", This);
1452 if(This->peb)
1454 IExplorerBrowser_Destroy(This->peb);
1455 IExplorerBrowser_Release(This->peb);
1456 This->peb = NULL;
1459 ctrl_container_reparent(This, NULL);
1460 This->dlg_hwnd = NULL;
1462 return TRUE;
1465 static LRESULT on_idok(FileDialogImpl *This)
1467 TRACE("%p\n", This);
1469 if(SUCCEEDED(on_default_action(This)))
1470 EndDialog(This->dlg_hwnd, S_OK);
1472 return FALSE;
1475 static LRESULT on_idcancel(FileDialogImpl *This)
1477 TRACE("%p\n", This);
1479 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
1481 return FALSE;
1484 static LRESULT on_browse_back(FileDialogImpl *This)
1486 TRACE("%p\n", This);
1487 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
1488 return FALSE;
1491 static LRESULT on_browse_forward(FileDialogImpl *This)
1493 TRACE("%p\n", This);
1494 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
1495 return FALSE;
1498 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1500 if(HIWORD(wparam) == CBN_SELCHANGE)
1502 IShellView *psv;
1503 HRESULT hr;
1504 LPWSTR filename;
1505 UINT prev_index = This->filetypeindex;
1507 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
1508 TRACE("File type selection changed to %d.\n", This->filetypeindex);
1510 if(prev_index == This->filetypeindex)
1511 return FALSE;
1513 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
1514 if(SUCCEEDED(hr))
1516 IShellView_Refresh(psv);
1517 IShellView_Release(psv);
1520 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
1522 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
1524 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
1525 if(ext)
1527 lstrcpyW(buf, filename);
1529 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
1530 PathRemoveExtensionW(buf);
1532 lstrcatW(buf, ext);
1533 set_file_name(This, buf);
1535 CoTaskMemFree(filename);
1539 return FALSE;
1542 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1544 switch(LOWORD(wparam))
1546 case IDOK: return on_idok(This);
1547 case IDCANCEL: return on_idcancel(This);
1548 case IDC_NAVBACK: return on_browse_back(This);
1549 case IDC_NAVFORWARD: return on_browse_forward(This);
1550 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
1551 default: TRACE("Unknown command.\n");
1553 return FALSE;
1556 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1558 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1560 switch(umessage)
1562 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
1563 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
1564 case WM_SIZE: return on_wm_size(This);
1565 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
1566 case WM_DESTROY: return on_wm_destroy(This);
1569 return FALSE;
1572 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
1574 INT_PTR res;
1576 SetLastError(0);
1577 res = DialogBoxParamW(COMDLG32_hInstance,
1578 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
1579 parent, itemdlg_dlgproc, (LPARAM)This);
1580 This->dlg_hwnd = NULL;
1581 if(res == -1)
1583 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
1584 return E_FAIL;
1587 TRACE("Returning 0x%08x\n", (HRESULT)res);
1588 return (HRESULT)res;
1591 /**************************************************************************
1592 * IFileDialog implementation
1594 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
1596 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
1599 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
1600 REFIID riid,
1601 void **ppvObject)
1603 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1604 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1606 *ppvObject = NULL;
1607 if(IsEqualGUID(riid, &IID_IUnknown) ||
1608 IsEqualGUID(riid, &IID_IFileDialog) ||
1609 IsEqualGUID(riid, &IID_IFileDialog2))
1611 *ppvObject = iface;
1613 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
1615 *ppvObject = &This->u.IFileOpenDialog_iface;
1617 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
1619 *ppvObject = &This->u.IFileSaveDialog_iface;
1621 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
1623 *ppvObject = &This->IExplorerBrowserEvents_iface;
1625 else if(IsEqualGUID(riid, &IID_IServiceProvider))
1627 *ppvObject = &This->IServiceProvider_iface;
1629 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
1630 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
1631 IsEqualGUID(&IID_ICommDlgBrowser, riid))
1633 *ppvObject = &This->ICommDlgBrowser3_iface;
1635 else if(IsEqualGUID(&IID_IOleWindow, riid))
1637 *ppvObject = &This->IOleWindow_iface;
1639 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
1640 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
1642 *ppvObject = &This->IFileDialogCustomize_iface;
1644 else
1645 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
1647 if(*ppvObject)
1649 IUnknown_AddRef((IUnknown*)*ppvObject);
1650 return S_OK;
1653 return E_NOINTERFACE;
1656 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
1658 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1659 LONG ref = InterlockedIncrement(&This->ref);
1660 TRACE("%p - ref %d\n", This, ref);
1662 return ref;
1665 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
1667 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1668 LONG ref = InterlockedDecrement(&This->ref);
1669 TRACE("%p - ref %d\n", This, ref);
1671 if(!ref)
1673 UINT i;
1674 for(i = 0; i < This->filterspec_count; i++)
1676 LocalFree((void*)This->filterspecs[i].pszName);
1677 LocalFree((void*)This->filterspecs[i].pszSpec);
1679 HeapFree(GetProcessHeap(), 0, This->filterspecs);
1681 DestroyWindow(This->cctrls_hwnd);
1683 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
1684 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
1685 if(This->psi_folder) IShellItem_Release(This->psi_folder);
1686 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
1687 if(This->psia_results) IShellItemArray_Release(This->psia_results);
1689 LocalFree(This->set_filename);
1690 LocalFree(This->default_ext);
1691 LocalFree(This->custom_title);
1692 LocalFree(This->custom_okbutton);
1693 LocalFree(This->custom_cancelbutton);
1694 LocalFree(This->custom_filenamelabel);
1696 HeapFree(GetProcessHeap(), 0, This);
1699 return ref;
1702 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
1704 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1705 TRACE("%p (%p)\n", iface, hwndOwner);
1707 return create_dialog(This, hwndOwner);
1710 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
1711 const COMDLG_FILTERSPEC *rgFilterSpec)
1713 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1714 UINT i;
1715 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
1717 if(This->filterspecs)
1718 return E_UNEXPECTED;
1720 if(!rgFilterSpec)
1721 return E_INVALIDARG;
1723 if(!cFileTypes)
1724 return S_OK;
1726 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
1727 for(i = 0; i < cFileTypes; i++)
1729 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
1730 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
1732 This->filterspec_count = cFileTypes;
1734 return S_OK;
1737 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
1739 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1740 TRACE("%p (%d)\n", This, iFileType);
1742 if(!This->filterspecs)
1743 return E_FAIL;
1745 if(iFileType >= This->filterspec_count)
1746 This->filetypeindex = This->filterspec_count - 1;
1747 else
1748 This->filetypeindex = iFileType;
1750 return S_OK;
1753 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
1755 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1756 TRACE("%p (%p)\n", This, piFileType);
1758 if(!piFileType)
1759 return E_INVALIDARG;
1761 *piFileType = This->filetypeindex;
1763 return S_OK;
1766 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
1768 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1769 events_client *client;
1770 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
1772 if(!pfde || !pdwCookie)
1773 return E_INVALIDARG;
1775 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
1776 client->pfde = pfde;
1777 client->cookie = ++This->events_next_cookie;
1779 IFileDialogEvents_AddRef(pfde);
1780 *pdwCookie = client->cookie;
1782 list_add_tail(&This->events_clients, &client->entry);
1784 return S_OK;
1787 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
1789 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1790 events_client *client, *found = NULL;
1791 TRACE("%p (%d)\n", This, dwCookie);
1793 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
1795 if(client->cookie == dwCookie)
1797 found = client;
1798 break;
1802 if(found)
1804 list_remove(&found->entry);
1805 IFileDialogEvents_Release(found->pfde);
1806 HeapFree(GetProcessHeap(), 0, found);
1807 return S_OK;
1810 return E_INVALIDARG;
1813 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
1815 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1816 TRACE("%p (0x%x)\n", This, fos);
1818 This->options = fos;
1820 return S_OK;
1823 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
1825 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1826 TRACE("%p (%p)\n", This, pfos);
1828 if(!pfos)
1829 return E_INVALIDARG;
1831 *pfos = This->options;
1833 return S_OK;
1836 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
1838 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1839 TRACE("%p (%p)\n", This, psi);
1840 if(This->psi_defaultfolder)
1841 IShellItem_Release(This->psi_defaultfolder);
1843 This->psi_defaultfolder = psi;
1845 if(This->psi_defaultfolder)
1846 IShellItem_AddRef(This->psi_defaultfolder);
1848 return S_OK;
1851 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
1853 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1854 TRACE("%p (%p)\n", This, psi);
1855 if(This->psi_setfolder)
1856 IShellItem_Release(This->psi_setfolder);
1858 This->psi_setfolder = psi;
1860 if(This->psi_setfolder)
1861 IShellItem_AddRef(This->psi_setfolder);
1863 return S_OK;
1866 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
1868 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1869 TRACE("%p (%p)\n", This, ppsi);
1870 if(!ppsi)
1871 return E_INVALIDARG;
1873 /* FIXME:
1874 If the dialog is shown, return the current(ly selected) folder. */
1876 *ppsi = NULL;
1877 if(This->psi_folder)
1878 *ppsi = This->psi_folder;
1879 else if(This->psi_setfolder)
1880 *ppsi = This->psi_setfolder;
1881 else if(This->psi_defaultfolder)
1882 *ppsi = This->psi_defaultfolder;
1884 if(*ppsi)
1886 IShellItem_AddRef(*ppsi);
1887 return S_OK;
1890 return E_FAIL;
1893 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
1895 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1896 HRESULT hr;
1897 TRACE("%p (%p)\n", This, ppsi);
1899 if(!ppsi)
1900 return E_INVALIDARG;
1902 if(This->psia_selection)
1904 /* FIXME: Check filename edit box */
1905 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
1906 return hr;
1909 return E_FAIL;
1912 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
1914 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1915 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
1917 set_file_name(This, pszName);
1919 return S_OK;
1922 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
1924 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1925 TRACE("%p (%p)\n", iface, pszName);
1927 if(!pszName)
1928 return E_INVALIDARG;
1930 *pszName = NULL;
1931 if(get_file_name(This, pszName))
1932 return S_OK;
1933 else
1934 return E_FAIL;
1937 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
1939 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1940 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
1942 LocalFree(This->custom_title);
1943 This->custom_title = StrDupW(pszTitle);
1944 update_control_text(This);
1946 return S_OK;
1949 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
1951 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1952 TRACE("%p (%s)\n", This, debugstr_w(pszText));
1954 LocalFree(This->custom_okbutton);
1955 This->custom_okbutton = StrDupW(pszText);
1956 update_control_text(This);
1957 update_layout(This);
1959 return S_OK;
1962 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
1964 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1965 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
1967 LocalFree(This->custom_filenamelabel);
1968 This->custom_filenamelabel = StrDupW(pszLabel);
1969 update_control_text(This);
1970 update_layout(This);
1972 return S_OK;
1975 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
1977 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1978 HRESULT hr;
1979 TRACE("%p (%p)\n", This, ppsi);
1981 if(!ppsi)
1982 return E_INVALIDARG;
1984 if(This->psia_results)
1986 UINT item_count;
1987 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
1988 if(SUCCEEDED(hr))
1990 if(item_count != 1)
1991 return E_FAIL;
1993 /* Adds a reference. */
1994 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
1997 return hr;
2000 return E_UNEXPECTED;
2003 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2005 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2006 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2007 return E_NOTIMPL;
2010 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2012 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2013 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2015 LocalFree(This->default_ext);
2016 This->default_ext = StrDupW(pszDefaultExtension);
2018 return S_OK;
2021 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2023 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2024 TRACE("%p (0x%08x)\n", This, hr);
2026 if(This->dlg_hwnd)
2027 EndDialog(This->dlg_hwnd, hr);
2029 return S_OK;
2032 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2034 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2035 FIXME("stub - %p (%s)\n", This, debugstr_guid(guid));
2036 return E_NOTIMPL;
2039 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2041 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2042 FIXME("stub - %p\n", This);
2043 return E_NOTIMPL;
2046 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2048 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2049 FIXME("stub - %p (%p)\n", This, pFilter);
2050 return E_NOTIMPL;
2053 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2055 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2056 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2058 LocalFree(This->custom_cancelbutton);
2059 This->custom_cancelbutton = StrDupW(pszLabel);
2060 update_control_text(This);
2061 update_layout(This);
2063 return S_OK;
2066 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2068 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2069 FIXME("stub - %p (%p)\n", This, psi);
2070 return E_NOTIMPL;
2073 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2074 IFileDialog2_fnQueryInterface,
2075 IFileDialog2_fnAddRef,
2076 IFileDialog2_fnRelease,
2077 IFileDialog2_fnShow,
2078 IFileDialog2_fnSetFileTypes,
2079 IFileDialog2_fnSetFileTypeIndex,
2080 IFileDialog2_fnGetFileTypeIndex,
2081 IFileDialog2_fnAdvise,
2082 IFileDialog2_fnUnadvise,
2083 IFileDialog2_fnSetOptions,
2084 IFileDialog2_fnGetOptions,
2085 IFileDialog2_fnSetDefaultFolder,
2086 IFileDialog2_fnSetFolder,
2087 IFileDialog2_fnGetFolder,
2088 IFileDialog2_fnGetCurrentSelection,
2089 IFileDialog2_fnSetFileName,
2090 IFileDialog2_fnGetFileName,
2091 IFileDialog2_fnSetTitle,
2092 IFileDialog2_fnSetOkButtonLabel,
2093 IFileDialog2_fnSetFileNameLabel,
2094 IFileDialog2_fnGetResult,
2095 IFileDialog2_fnAddPlace,
2096 IFileDialog2_fnSetDefaultExtension,
2097 IFileDialog2_fnClose,
2098 IFileDialog2_fnSetClientGuid,
2099 IFileDialog2_fnClearClientData,
2100 IFileDialog2_fnSetFilter,
2101 IFileDialog2_fnSetCancelButtonLabel,
2102 IFileDialog2_fnSetNavigationRoot
2105 /**************************************************************************
2106 * IFileOpenDialog
2108 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2110 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2113 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2114 REFIID riid, void **ppvObject)
2116 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2117 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2120 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2122 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2123 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2126 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2128 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2129 return IFileDialog2_Release(&This->IFileDialog2_iface);
2132 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2134 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2135 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2138 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2139 const COMDLG_FILTERSPEC *rgFilterSpec)
2141 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2142 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2145 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2147 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2148 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2151 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2153 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2154 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2157 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2158 DWORD *pdwCookie)
2160 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2161 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2164 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2166 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2167 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2170 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2172 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2173 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2176 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2178 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2179 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2182 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2184 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2185 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2188 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2190 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2191 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2194 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2196 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2197 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2200 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2202 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2203 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2206 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2208 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2209 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2212 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2214 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2215 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2218 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2220 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2221 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2224 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2226 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2227 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2230 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2232 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2233 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2236 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2238 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2239 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2242 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2244 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2245 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2248 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2249 LPCWSTR pszDefaultExtension)
2251 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2252 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2255 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2257 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2258 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2261 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2263 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2264 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2267 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2269 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2270 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2273 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2275 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2276 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2279 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2281 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2282 TRACE("%p (%p)\n", This, ppenum);
2284 *ppenum = This->psia_results;
2286 if(*ppenum)
2288 IShellItemArray_AddRef(*ppenum);
2289 return S_OK;
2292 return E_FAIL;
2295 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2297 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2298 TRACE("%p (%p)\n", This, ppsai);
2300 if(This->psia_selection)
2302 *ppsai = This->psia_selection;
2303 IShellItemArray_AddRef(*ppsai);
2304 return S_OK;
2307 return E_FAIL;
2310 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2311 IFileOpenDialog_fnQueryInterface,
2312 IFileOpenDialog_fnAddRef,
2313 IFileOpenDialog_fnRelease,
2314 IFileOpenDialog_fnShow,
2315 IFileOpenDialog_fnSetFileTypes,
2316 IFileOpenDialog_fnSetFileTypeIndex,
2317 IFileOpenDialog_fnGetFileTypeIndex,
2318 IFileOpenDialog_fnAdvise,
2319 IFileOpenDialog_fnUnadvise,
2320 IFileOpenDialog_fnSetOptions,
2321 IFileOpenDialog_fnGetOptions,
2322 IFileOpenDialog_fnSetDefaultFolder,
2323 IFileOpenDialog_fnSetFolder,
2324 IFileOpenDialog_fnGetFolder,
2325 IFileOpenDialog_fnGetCurrentSelection,
2326 IFileOpenDialog_fnSetFileName,
2327 IFileOpenDialog_fnGetFileName,
2328 IFileOpenDialog_fnSetTitle,
2329 IFileOpenDialog_fnSetOkButtonLabel,
2330 IFileOpenDialog_fnSetFileNameLabel,
2331 IFileOpenDialog_fnGetResult,
2332 IFileOpenDialog_fnAddPlace,
2333 IFileOpenDialog_fnSetDefaultExtension,
2334 IFileOpenDialog_fnClose,
2335 IFileOpenDialog_fnSetClientGuid,
2336 IFileOpenDialog_fnClearClientData,
2337 IFileOpenDialog_fnSetFilter,
2338 IFileOpenDialog_fnGetResults,
2339 IFileOpenDialog_fnGetSelectedItems
2342 /**************************************************************************
2343 * IFileSaveDialog
2345 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
2347 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
2350 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
2351 REFIID riid,
2352 void **ppvObject)
2354 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2355 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2358 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
2360 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2361 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2364 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
2366 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2367 return IFileDialog2_Release(&This->IFileDialog2_iface);
2370 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
2372 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2373 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2376 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
2377 const COMDLG_FILTERSPEC *rgFilterSpec)
2379 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2380 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2383 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
2385 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2386 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2389 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
2391 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2392 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2395 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
2396 DWORD *pdwCookie)
2398 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2399 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2402 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
2404 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2405 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2408 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
2410 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2411 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2414 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2416 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2417 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2420 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
2422 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2423 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2426 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
2428 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2429 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2432 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
2434 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2435 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2438 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
2440 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2441 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2444 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
2446 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2447 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2450 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
2452 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2453 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2456 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
2458 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2459 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2462 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
2464 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2465 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2468 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
2470 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2471 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2474 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
2476 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2477 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2480 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
2482 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2483 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2486 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
2487 LPCWSTR pszDefaultExtension)
2489 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2490 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2493 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
2495 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2496 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2499 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
2501 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2502 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2505 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
2507 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2508 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2511 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
2513 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2514 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2517 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
2519 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2520 FIXME("stub - %p (%p)\n", This, psi);
2521 return E_NOTIMPL;
2524 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
2526 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2527 FIXME("stub - %p (%p)\n", This, pStore);
2528 return E_NOTIMPL;
2531 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
2532 IPropertyDescriptionList *pList,
2533 BOOL fAppendDefault)
2535 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2536 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
2537 return E_NOTIMPL;
2540 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
2542 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2543 FIXME("stub - %p (%p)\n", This, ppStore);
2544 return E_NOTIMPL;
2547 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
2548 IShellItem *psi,
2549 IPropertyStore *pStore,
2550 HWND hwnd,
2551 IFileOperationProgressSink *pSink)
2553 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2554 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
2555 return E_NOTIMPL;
2558 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
2559 IFileSaveDialog_fnQueryInterface,
2560 IFileSaveDialog_fnAddRef,
2561 IFileSaveDialog_fnRelease,
2562 IFileSaveDialog_fnShow,
2563 IFileSaveDialog_fnSetFileTypes,
2564 IFileSaveDialog_fnSetFileTypeIndex,
2565 IFileSaveDialog_fnGetFileTypeIndex,
2566 IFileSaveDialog_fnAdvise,
2567 IFileSaveDialog_fnUnadvise,
2568 IFileSaveDialog_fnSetOptions,
2569 IFileSaveDialog_fnGetOptions,
2570 IFileSaveDialog_fnSetDefaultFolder,
2571 IFileSaveDialog_fnSetFolder,
2572 IFileSaveDialog_fnGetFolder,
2573 IFileSaveDialog_fnGetCurrentSelection,
2574 IFileSaveDialog_fnSetFileName,
2575 IFileSaveDialog_fnGetFileName,
2576 IFileSaveDialog_fnSetTitle,
2577 IFileSaveDialog_fnSetOkButtonLabel,
2578 IFileSaveDialog_fnSetFileNameLabel,
2579 IFileSaveDialog_fnGetResult,
2580 IFileSaveDialog_fnAddPlace,
2581 IFileSaveDialog_fnSetDefaultExtension,
2582 IFileSaveDialog_fnClose,
2583 IFileSaveDialog_fnSetClientGuid,
2584 IFileSaveDialog_fnClearClientData,
2585 IFileSaveDialog_fnSetFilter,
2586 IFileSaveDialog_fnSetSaveAsItem,
2587 IFileSaveDialog_fnSetProperties,
2588 IFileSaveDialog_fnSetCollectedProperties,
2589 IFileSaveDialog_fnGetProperties,
2590 IFileSaveDialog_fnApplyProperties
2593 /**************************************************************************
2594 * IExplorerBrowserEvents implementation
2596 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
2598 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
2601 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
2602 REFIID riid, void **ppvObject)
2604 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2605 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2607 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2610 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
2612 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2613 TRACE("%p\n", This);
2614 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2617 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
2619 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2620 TRACE("%p\n", This);
2621 return IFileDialog2_Release(&This->IFileDialog2_iface);
2624 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
2625 PCIDLIST_ABSOLUTE pidlFolder)
2627 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2628 IShellItem *psi;
2629 HRESULT hr;
2630 TRACE("%p (%p)\n", This, pidlFolder);
2632 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
2633 if(SUCCEEDED(hr))
2635 hr = events_OnFolderChanging(This, psi);
2636 IShellItem_Release(psi);
2638 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
2639 if(hr == S_FALSE)
2640 hr = E_FAIL;
2642 return hr;
2644 else
2645 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
2647 return S_OK;
2650 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
2651 IShellView *psv)
2653 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2654 TRACE("%p (%p)\n", This, psv);
2655 return S_OK;
2658 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
2659 PCIDLIST_ABSOLUTE pidlFolder)
2661 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2662 HRESULT hr;
2663 TRACE("%p (%p)\n", This, pidlFolder);
2665 if(This->psi_folder)
2666 IShellItem_Release(This->psi_folder);
2668 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
2669 if(FAILED(hr))
2671 ERR("Failed to get the current folder.\n");
2672 This->psi_folder = NULL;
2675 events_OnFolderChange(This);
2677 return S_OK;
2680 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
2681 PCIDLIST_ABSOLUTE pidlFolder)
2683 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2684 TRACE("%p (%p)\n", This, pidlFolder);
2685 return S_OK;
2688 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
2689 IExplorerBrowserEvents_fnQueryInterface,
2690 IExplorerBrowserEvents_fnAddRef,
2691 IExplorerBrowserEvents_fnRelease,
2692 IExplorerBrowserEvents_fnOnNavigationPending,
2693 IExplorerBrowserEvents_fnOnViewCreated,
2694 IExplorerBrowserEvents_fnOnNavigationComplete,
2695 IExplorerBrowserEvents_fnOnNavigationFailed
2698 /**************************************************************************
2699 * IServiceProvider implementation
2701 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2703 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
2706 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
2707 REFIID riid, void **ppvObject)
2709 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2710 TRACE("%p\n", This);
2711 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2714 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
2716 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2717 TRACE("%p\n", This);
2718 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2721 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
2723 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2724 TRACE("%p\n", This);
2725 return IFileDialog2_Release(&This->IFileDialog2_iface);
2728 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
2729 REFGUID guidService,
2730 REFIID riid, void **ppv)
2732 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2733 HRESULT hr = E_NOTIMPL;
2734 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
2736 *ppv = NULL;
2737 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
2738 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
2739 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
2740 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
2741 else
2742 FIXME("Interface %s requested from unknown service %s\n",
2743 debugstr_guid(riid), debugstr_guid(guidService));
2745 return hr;
2748 static const IServiceProviderVtbl vt_IServiceProvider = {
2749 IServiceProvider_fnQueryInterface,
2750 IServiceProvider_fnAddRef,
2751 IServiceProvider_fnRelease,
2752 IServiceProvider_fnQueryService
2755 /**************************************************************************
2756 * ICommDlgBrowser3 implementation
2758 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
2760 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
2763 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
2764 REFIID riid, void **ppvObject)
2766 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2767 TRACE("%p\n", This);
2768 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2771 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
2773 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2774 TRACE("%p\n", This);
2775 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2778 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
2780 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2781 TRACE("%p\n", This);
2782 return IFileDialog2_Release(&This->IFileDialog2_iface);
2785 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
2786 IShellView *shv)
2788 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2789 HRESULT hr;
2790 TRACE("%p (%p)\n", This, shv);
2792 hr = on_default_action(This);
2794 if(SUCCEEDED(hr))
2795 EndDialog(This->dlg_hwnd, S_OK);
2797 return S_OK;
2800 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
2801 IShellView *shv, ULONG uChange )
2803 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2804 IDataObject *new_selection;
2805 HRESULT hr;
2806 TRACE("%p (%p, %x)\n", This, shv, uChange);
2808 switch(uChange)
2810 case CDBOSC_SELCHANGE:
2811 if(This->psia_selection)
2813 IShellItemArray_Release(This->psia_selection);
2814 This->psia_selection = NULL;
2817 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
2818 if(SUCCEEDED(hr))
2820 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
2821 (void**)&This->psia_selection);
2822 if(SUCCEEDED(hr))
2824 fill_filename_from_selection(This);
2825 events_OnSelectionChange(This);
2828 IDataObject_Release(new_selection);
2830 break;
2831 default:
2832 TRACE("Unhandled state change\n");
2834 return S_OK;
2837 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
2838 IShellView *shv, LPCITEMIDLIST pidl)
2840 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2841 IShellItem *psi;
2842 LPWSTR filename;
2843 LPITEMIDLIST parent_pidl;
2844 HRESULT hr;
2845 ULONG attr;
2846 TRACE("%p (%p, %p)\n", This, shv, pidl);
2848 if(!This->filterspec_count)
2849 return S_OK;
2851 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
2852 if(SUCCEEDED(hr))
2854 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
2855 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
2856 ILFree(parent_pidl);
2857 ILFree(full_pidl);
2859 if(FAILED(hr))
2861 ERR("Failed to get shellitem (%08x).\n", hr);
2862 return S_OK;
2865 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
2866 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
2868 IShellItem_Release(psi);
2869 return S_OK;
2872 hr = S_OK;
2873 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
2875 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
2876 hr = S_FALSE;
2877 CoTaskMemFree(filename);
2880 IShellItem_Release(psi);
2881 return hr;
2884 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
2885 IShellView *ppshv, DWORD dwNotifyType)
2887 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2888 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
2889 return E_NOTIMPL;
2892 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
2893 IShellView *pshv,
2894 LPWSTR pszText, int cchMax)
2896 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2897 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
2898 return E_NOTIMPL;
2901 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
2903 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2904 FIXME("Stub: %p (%p)\n", This, pdwFlags);
2905 return E_NOTIMPL;
2908 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
2909 IShellView *pshv, int iColumn)
2911 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2912 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
2913 return E_NOTIMPL;
2916 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
2917 LPWSTR pszFileSpec, int cchFileSpec)
2919 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2920 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
2921 return E_NOTIMPL;
2924 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
2925 IShellView *pshv)
2927 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2928 FIXME("Stub: %p (%p)\n", This, pshv);
2929 return E_NOTIMPL;
2932 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
2933 ICommDlgBrowser3_fnQueryInterface,
2934 ICommDlgBrowser3_fnAddRef,
2935 ICommDlgBrowser3_fnRelease,
2936 ICommDlgBrowser3_fnOnDefaultCommand,
2937 ICommDlgBrowser3_fnOnStateChange,
2938 ICommDlgBrowser3_fnIncludeObject,
2939 ICommDlgBrowser3_fnNotify,
2940 ICommDlgBrowser3_fnGetDefaultMenuText,
2941 ICommDlgBrowser3_fnGetViewFlags,
2942 ICommDlgBrowser3_fnOnColumnClicked,
2943 ICommDlgBrowser3_fnGetCurrentFilter,
2944 ICommDlgBrowser3_fnOnPreviewCreated
2947 /**************************************************************************
2948 * IOleWindow implementation
2950 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
2952 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
2955 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
2957 FileDialogImpl *This = impl_from_IOleWindow(iface);
2958 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2961 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
2963 FileDialogImpl *This = impl_from_IOleWindow(iface);
2964 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2967 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
2969 FileDialogImpl *This = impl_from_IOleWindow(iface);
2970 return IFileDialog2_Release(&This->IFileDialog2_iface);
2973 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
2975 FileDialogImpl *This = impl_from_IOleWindow(iface);
2976 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
2977 return E_NOTIMPL;
2980 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
2982 FileDialogImpl *This = impl_from_IOleWindow(iface);
2983 TRACE("%p (%p)\n", This, phwnd);
2984 *phwnd = This->dlg_hwnd;
2985 return S_OK;
2988 static const IOleWindowVtbl vt_IOleWindow = {
2989 IOleWindow_fnQueryInterface,
2990 IOleWindow_fnAddRef,
2991 IOleWindow_fnRelease,
2992 IOleWindow_fnGetWindow,
2993 IOleWindow_fnContextSensitiveHelp
2996 /**************************************************************************
2997 * IFileDialogCustomize implementation
2999 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3001 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3004 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3005 REFIID riid, void **ppvObject)
3007 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3008 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3011 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3013 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3014 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3017 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3019 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3020 return IFileDialog2_Release(&This->IFileDialog2_iface);
3023 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3024 DWORD dwIDCtl)
3026 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3027 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3028 return E_NOTIMPL;
3031 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3032 DWORD dwIDCtl,
3033 LPCWSTR pszLabel)
3035 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3036 customctrl *ctrl;
3037 TBBUTTON tbb;
3038 HRESULT hr;
3039 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3041 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3042 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3043 This->cctrl_def_height, &ctrl);
3044 if(SUCCEEDED(hr))
3046 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3047 ctrl->type = IDLG_CCTRL_MENU;
3049 /* Add the actual button with a popup menu. */
3050 tbb.iBitmap = I_IMAGENONE;
3051 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3052 tbb.iString = (DWORD_PTR)pszLabel;
3053 tbb.fsState = TBSTATE_ENABLED;
3054 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3055 tbb.idCommand = 1;
3057 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3060 return hr;
3063 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3064 DWORD dwIDCtl,
3065 LPCWSTR pszLabel)
3067 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3068 customctrl *ctrl;
3069 HRESULT hr;
3070 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3072 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3073 This->cctrl_def_height, &ctrl);
3074 if(SUCCEEDED(hr))
3075 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3077 return hr;
3080 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3081 DWORD dwIDCtl)
3083 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3084 customctrl *ctrl;
3085 HRESULT hr;
3086 TRACE("%p (%d)\n", This, dwIDCtl);
3088 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3089 This->cctrl_def_height, &ctrl);
3090 if(SUCCEEDED(hr))
3091 ctrl->type = IDLG_CCTRL_COMBOBOX;
3093 return hr;
3096 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3097 DWORD dwIDCtl)
3099 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3100 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3101 return E_NOTIMPL;
3104 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3105 DWORD dwIDCtl,
3106 LPCWSTR pszLabel,
3107 BOOL bChecked)
3109 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3110 customctrl *ctrl;
3111 HRESULT hr;
3112 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3114 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX, 0,
3115 This->cctrl_def_height, &ctrl);
3116 if(SUCCEEDED(hr))
3118 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3119 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3122 return hr;
3125 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3126 DWORD dwIDCtl,
3127 LPCWSTR pszText)
3129 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3130 customctrl *ctrl;
3131 HRESULT hr;
3132 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3134 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3135 This->cctrl_def_height, &ctrl);
3136 if(SUCCEEDED(hr))
3137 ctrl->type = IDLG_CCTRL_EDITBOX;
3139 return hr;
3142 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3143 DWORD dwIDCtl)
3145 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3146 customctrl *ctrl;
3147 HRESULT hr;
3148 TRACE("%p (%d)\n", This, dwIDCtl);
3150 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3151 GetSystemMetrics(SM_CYEDGE), &ctrl);
3152 if(SUCCEEDED(hr))
3153 ctrl->type = IDLG_CCTRL_SEPARATOR;
3155 return hr;
3158 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3159 DWORD dwIDCtl,
3160 LPCWSTR pszText)
3162 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3163 customctrl *ctrl;
3164 HRESULT hr;
3165 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3167 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3168 This->cctrl_def_height, &ctrl);
3169 if(SUCCEEDED(hr))
3170 ctrl->type = IDLG_CCTRL_TEXT;
3172 return hr;
3175 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3176 DWORD dwIDCtl,
3177 LPCWSTR pszLabel)
3179 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3180 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3181 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3183 if(!ctrl) return E_INVALIDARG;
3185 switch(ctrl->type)
3187 case IDLG_CCTRL_MENU:
3188 case IDLG_CCTRL_PUSHBUTTON:
3189 case IDLG_CCTRL_CHECKBUTTON:
3190 case IDLG_CCTRL_TEXT:
3191 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3192 break;
3193 default:
3194 break;
3197 return S_OK;
3200 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3201 DWORD dwIDCtl,
3202 CDCONTROLSTATEF *pdwState)
3204 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3205 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3206 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3208 if(!ctrl) return E_NOTIMPL;
3210 *pdwState = ctrl->cdcstate;
3211 return S_OK;
3214 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3215 DWORD dwIDCtl,
3216 CDCONTROLSTATEF dwState)
3218 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3219 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3220 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3222 if(ctrl)
3224 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3226 if(dwState & CDCS_ENABLED)
3227 wndstyle &= ~(WS_DISABLED);
3228 else
3229 wndstyle |= WS_DISABLED;
3231 if(dwState & CDCS_VISIBLE)
3232 wndstyle |= WS_VISIBLE;
3233 else
3234 wndstyle &= ~(WS_VISIBLE);
3236 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3238 /* We save the state separately since at least one application
3239 * relies on being able to hide a control. */
3240 ctrl->cdcstate = dwState;
3243 return S_OK;
3246 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3247 DWORD dwIDCtl,
3248 WCHAR **ppszText)
3250 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3251 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3252 WCHAR len, *text;
3253 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
3255 if(!ctrl || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3256 return E_FAIL;
3258 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3259 if(!text) return E_FAIL;
3261 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3262 *ppszText = text;
3263 return S_OK;
3266 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
3267 DWORD dwIDCtl,
3268 LPCWSTR pszText)
3270 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3271 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3272 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
3274 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
3275 return E_FAIL;
3277 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
3278 return S_OK;
3281 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
3282 DWORD dwIDCtl,
3283 BOOL *pbChecked)
3285 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3286 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3287 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
3289 if(ctrl)
3290 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
3292 return S_OK;
3295 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
3296 DWORD dwIDCtl,
3297 BOOL bChecked)
3299 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3300 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3301 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
3303 if(ctrl)
3304 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
3306 return S_OK;
3309 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
3311 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
3312 UINT i;
3313 if(!count || (count == CB_ERR))
3314 return -1;
3316 for(i = 0; i < count; i++)
3317 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3318 return i;
3320 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
3321 return -1;
3324 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
3325 DWORD dwIDCtl,
3326 DWORD dwIDItem,
3327 LPCWSTR pszLabel)
3329 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3330 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3331 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3333 if(!ctrl) return E_FAIL;
3335 switch(ctrl->type)
3337 case IDLG_CCTRL_COMBOBOX:
3339 UINT index;
3341 if(get_combobox_index_from_id(ctrl->hwnd, dwIDItem) != -1)
3342 return E_INVALIDARG;
3344 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
3345 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
3347 return S_OK;
3349 case IDLG_CCTRL_MENU:
3351 TBBUTTON tbb;
3352 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3354 if(GetMenuState((HMENU)tbb.dwData, dwIDItem, MF_BYCOMMAND) != -1)
3355 return E_INVALIDARG;
3357 AppendMenuW((HMENU)tbb.dwData, MF_STRING, dwIDItem, pszLabel);
3358 return S_OK;
3360 default:
3361 break;
3364 return E_NOINTERFACE; /* win7 */
3367 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
3368 DWORD dwIDCtl,
3369 DWORD dwIDItem)
3371 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3372 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3373 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3375 if(!ctrl) return E_FAIL;
3377 switch(ctrl->type)
3379 case IDLG_CCTRL_COMBOBOX:
3381 UINT i, count = SendMessageW(ctrl->hwnd, CB_GETCOUNT, 0, 0);
3382 if(!count || (count == CB_ERR))
3383 return E_FAIL;
3385 for(i = 0; i < count; i++)
3386 if(SendMessageW(ctrl->hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3388 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, i, 0) == CB_ERR)
3389 return E_FAIL;
3390 return S_OK;
3393 return E_UNEXPECTED;
3395 case IDLG_CCTRL_MENU:
3397 TBBUTTON tbb;
3398 HMENU hmenu;
3399 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3400 hmenu = (HMENU)tbb.dwData;
3402 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
3403 return E_UNEXPECTED;
3405 return S_OK;
3407 default:
3408 break;
3411 return E_FAIL;
3414 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
3415 DWORD dwIDCtl)
3417 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3418 TRACE("%p (%d)\n", This, dwIDCtl);
3420 /* Not implemented by native */
3421 return E_NOTIMPL;
3424 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
3425 DWORD dwIDCtl,
3426 DWORD dwIDItem,
3427 CDCONTROLSTATEF *pdwState)
3429 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3430 FIXME("stub - %p\n", This);
3431 return E_NOTIMPL;
3434 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
3435 DWORD dwIDCtl,
3436 DWORD dwIDItem,
3437 CDCONTROLSTATEF dwState)
3439 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3440 FIXME("stub - %p\n", This);
3441 return E_NOTIMPL;
3444 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
3445 DWORD dwIDCtl,
3446 DWORD *pdwIDItem)
3448 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3449 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3450 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
3452 if(!ctrl) return E_FAIL;
3454 switch(ctrl->type)
3456 case IDLG_CCTRL_COMBOBOX:
3458 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
3459 if(index == CB_ERR)
3460 return E_FAIL;
3462 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
3463 return S_OK;
3465 default:
3466 FIXME("Unsupported control type %d\n", ctrl->type);
3469 return E_NOTIMPL;
3472 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
3473 DWORD dwIDCtl,
3474 DWORD dwIDItem)
3476 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3477 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3478 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3480 if(!ctrl) return E_INVALIDARG;
3482 switch(ctrl->type)
3484 case IDLG_CCTRL_COMBOBOX:
3486 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
3488 if(index == -1)
3489 return E_INVALIDARG;
3491 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
3492 return E_FAIL;
3494 return S_OK;
3496 default:
3497 FIXME("Unsupported control type %d\n", ctrl->type);
3500 return E_INVALIDARG;
3503 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
3504 DWORD dwIDCtl,
3505 LPCWSTR pszLabel)
3507 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3508 FIXME("stub - %p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
3509 return E_NOTIMPL;
3512 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
3514 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3515 FIXME("stub - %p\n", This);
3516 return E_NOTIMPL;
3519 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
3520 DWORD dwIDCtl)
3522 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3523 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3524 return E_NOTIMPL;
3527 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
3528 DWORD dwIDCtl,
3529 DWORD dwIDItem,
3530 LPCWSTR pszLabel)
3532 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3533 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3534 return E_NOTIMPL;
3537 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
3538 IFileDialogCustomize_fnQueryInterface,
3539 IFileDialogCustomize_fnAddRef,
3540 IFileDialogCustomize_fnRelease,
3541 IFileDialogCustomize_fnEnableOpenDropDown,
3542 IFileDialogCustomize_fnAddMenu,
3543 IFileDialogCustomize_fnAddPushButton,
3544 IFileDialogCustomize_fnAddComboBox,
3545 IFileDialogCustomize_fnAddRadioButtonList,
3546 IFileDialogCustomize_fnAddCheckButton,
3547 IFileDialogCustomize_fnAddEditBox,
3548 IFileDialogCustomize_fnAddSeparator,
3549 IFileDialogCustomize_fnAddText,
3550 IFileDialogCustomize_fnSetControlLabel,
3551 IFileDialogCustomize_fnGetControlState,
3552 IFileDialogCustomize_fnSetControlState,
3553 IFileDialogCustomize_fnGetEditBoxText,
3554 IFileDialogCustomize_fnSetEditBoxText,
3555 IFileDialogCustomize_fnGetCheckButtonState,
3556 IFileDialogCustomize_fnSetCheckButtonState,
3557 IFileDialogCustomize_fnAddControlItem,
3558 IFileDialogCustomize_fnRemoveControlItem,
3559 IFileDialogCustomize_fnRemoveAllControlItems,
3560 IFileDialogCustomize_fnGetControlItemState,
3561 IFileDialogCustomize_fnSetControlItemState,
3562 IFileDialogCustomize_fnGetSelectedControlItem,
3563 IFileDialogCustomize_fnSetSelectedControlItem,
3564 IFileDialogCustomize_fnStartVisualGroup,
3565 IFileDialogCustomize_fnEndVisualGroup,
3566 IFileDialogCustomize_fnMakeProminent,
3567 IFileDialogCustomize_fnSetControlItemText
3570 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
3572 FileDialogImpl *fdimpl;
3573 HRESULT hr;
3574 IShellFolder *psf;
3575 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
3577 if(!ppv)
3578 return E_POINTER;
3579 if(pUnkOuter)
3580 return CLASS_E_NOAGGREGATION;
3582 fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
3583 if(!fdimpl)
3584 return E_OUTOFMEMORY;
3586 fdimpl->ref = 1;
3587 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
3588 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
3589 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
3590 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
3591 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
3592 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
3594 if(type == ITEMDLG_TYPE_OPEN)
3596 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
3597 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
3598 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
3599 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
3601 else
3603 WCHAR buf[16];
3604 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
3605 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
3606 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
3608 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
3609 fdimpl->custom_title = StrDupW(buf);
3610 fdimpl->custom_okbutton = StrDupW(buf);
3613 fdimpl->filterspecs = NULL;
3614 fdimpl->filterspec_count = 0;
3615 fdimpl->filetypeindex = 0;
3617 fdimpl->psia_selection = fdimpl->psia_results = NULL;
3618 fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
3620 list_init(&fdimpl->events_clients);
3621 fdimpl->events_next_cookie = 0;
3623 fdimpl->dlg_hwnd = NULL;
3624 fdimpl->peb = NULL;
3626 fdimpl->set_filename = NULL;
3627 fdimpl->default_ext = NULL;
3628 fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL;
3630 /* FIXME: The default folder setting should be restored for the
3631 * application if it was previously set. */
3632 SHGetDesktopFolder(&psf);
3633 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
3634 IShellFolder_Release(psf);
3636 hr = init_custom_controls(fdimpl);
3637 if(FAILED(hr))
3639 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
3640 IUnknown_Release((IUnknown*)fdimpl);
3641 return E_FAIL;
3644 hr = IUnknown_QueryInterface((IUnknown*)fdimpl, riid, ppv);
3645 IUnknown_Release((IUnknown*)fdimpl);
3646 return hr;
3649 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3651 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
3654 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3656 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);