user32/tests: Add test for SendMessage race condition.
[wine/multimedia.git] / dlls / comdlg32 / itemdlg.c
blob2313b0af9108327274b1c076df8ccb2d6abacfbf
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;
129 GUID client_guid;
130 } FileDialogImpl;
132 /**************************************************************************
133 * Event wrappers.
135 static HRESULT events_OnFileOk(FileDialogImpl *This)
137 events_client *cursor;
138 HRESULT hr = S_OK;
139 TRACE("%p\n", This);
141 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
143 TRACE("Notifying %p\n", cursor);
144 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
145 if(FAILED(hr) && hr != E_NOTIMPL)
146 break;
149 if(hr == E_NOTIMPL)
150 hr = S_OK;
152 return hr;
155 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
157 events_client *cursor;
158 HRESULT hr = S_OK;
159 TRACE("%p (%p)\n", This, folder);
161 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
163 TRACE("Notifying %p\n", cursor);
164 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
165 if(FAILED(hr) && hr != E_NOTIMPL)
166 break;
169 if(hr == E_NOTIMPL)
170 hr = S_OK;
172 return hr;
175 static void events_OnFolderChange(FileDialogImpl *This)
177 events_client *cursor;
178 TRACE("%p\n", This);
180 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
182 TRACE("Notifying %p\n", cursor);
183 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
187 static void events_OnSelectionChange(FileDialogImpl *This)
189 events_client *cursor;
190 TRACE("%p\n", This);
192 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
194 TRACE("Notifying %p\n", cursor);
195 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
199 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
201 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
204 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
206 events_client *cursor;
207 TRACE("%p\n", This);
209 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
211 IFileDialogControlEvents *pfdce;
212 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
214 TRACE("Notifying %p\n", cursor);
215 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
216 IFileDialogControlEvents_Release(pfdce);
220 return S_OK;
223 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
225 events_client *cursor;
226 TRACE("%p\n", This);
228 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
230 IFileDialogControlEvents *pfdce;
231 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
233 TRACE("Notifying %p\n", cursor);
234 IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
235 IFileDialogControlEvents_Release(pfdce);
239 return S_OK;
242 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
244 events_client *cursor;
245 TRACE("%p\n", This);
247 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
249 IFileDialogControlEvents *pfdce;
250 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
252 TRACE("Notifying %p\n", cursor);
253 IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
254 IFileDialogControlEvents_Release(pfdce);
258 return S_OK;
261 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
262 DWORD ctl_id)
264 events_client *cursor;
265 TRACE("%p\n", This);
267 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
269 IFileDialogControlEvents *pfdce;
270 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
272 TRACE("Notifying %p\n", cursor);
273 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
274 IFileDialogControlEvents_Release(pfdce);
278 return S_OK;
281 /**************************************************************************
282 * Helper functions.
284 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
286 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
287 UINT len;
289 if(!hwnd_edit)
291 if(This->set_filename)
293 len = lstrlenW(This->set_filename);
294 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
295 lstrcpyW(*str, This->set_filename);
296 return len;
298 return FALSE;
301 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
302 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
303 if(!*str)
304 return FALSE;
306 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
307 return len;
310 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
312 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
314 if(This->set_filename)
315 LocalFree(This->set_filename);
317 This->set_filename = StrDupW(str);
319 return SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str);
322 static void fill_filename_from_selection(FileDialogImpl *This)
324 IShellItem *psi;
325 LPWSTR *names;
326 HRESULT hr;
327 UINT item_count, valid_count;
328 UINT len_total, i;
330 if(!This->psia_selection)
331 return;
333 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
334 if(FAILED(hr) || !item_count)
335 return;
337 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
339 /* Get names of the selected items */
340 valid_count = 0; len_total = 0;
341 for(i = 0; i < item_count; i++)
343 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
344 if(SUCCEEDED(hr))
346 UINT attr;
348 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
349 if(SUCCEEDED(hr) && (attr & SFGAO_FOLDER))
350 continue; /* FIXME: FOS_PICKFOLDERS */
352 hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
353 if(SUCCEEDED(hr))
355 len_total += lstrlenW(names[valid_count]) + 3;
356 valid_count++;
358 IShellItem_Release(psi);
362 if(valid_count == 1)
364 set_file_name(This, names[0]);
365 CoTaskMemFree(names[0]);
367 else if(valid_count > 1)
369 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
370 LPWSTR cur_point = string;
372 for(i = 0; i < valid_count; i++)
374 LPWSTR file = names[i];
375 *cur_point++ = '\"';
376 lstrcpyW(cur_point, file);
377 cur_point += lstrlenW(file);
378 *cur_point++ = '\"';
379 *cur_point++ = ' ';
380 CoTaskMemFree(file);
382 *(cur_point-1) = '\0';
384 set_file_name(This, string);
385 HeapFree(GetProcessHeap(), 0, string);
388 HeapFree(GetProcessHeap(), 0, names);
389 return;
392 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
394 WCHAR *endpos, *ext;
396 lstrcpyW(buf, spec);
397 if( (endpos = StrChrW(buf, ';')) )
398 *endpos = '\0';
400 ext = PathFindExtensionW(buf);
401 if(StrChrW(ext, '*'))
402 return NULL;
404 return ext;
407 static HRESULT on_default_action(FileDialogImpl *This)
409 IShellFolder *psf_parent, *psf_desktop;
410 LPITEMIDLIST *pidla;
411 LPITEMIDLIST current_folder;
412 LPWSTR fn_iter, files = NULL, tmp_files;
413 UINT file_count = 0, len, i;
414 int open_action;
415 HRESULT hr, ret = E_FAIL;
417 len = get_file_name(This, &tmp_files);
418 if(len)
420 UINT size_used;
421 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
422 CoTaskMemFree(tmp_files);
424 if(!file_count) return E_FAIL;
426 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
427 if(FAILED(hr))
429 ERR("Failed to get pidl for current directory.\n");
430 HeapFree(GetProcessHeap(), 0, files);
431 return hr;
434 TRACE("Acting on %d file(s).\n", file_count);
436 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
437 open_action = ONOPEN_OPEN;
438 fn_iter = files;
440 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
442 WCHAR canon_filename[MAX_PATH];
443 psf_parent = NULL;
445 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
447 if( (This->options & FOS_NOVALIDATE) &&
448 !(This->options & FOS_FILEMUSTEXIST) )
449 open_action = ONOPEN_OPEN;
450 else
451 open_action = ONOPEN_BROWSE;
453 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
454 This->options & ~FOS_FILEMUSTEXIST,
455 (This->dlg_type == ITEMDLG_TYPE_SAVE),
456 open_action);
458 /* Add the proper extension */
459 if(open_action == ONOPEN_OPEN)
461 static const WCHAR dotW[] = {'.',0};
463 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
465 WCHAR extbuf[MAX_PATH], *newext = NULL;
467 if(This->filterspec_count)
469 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
471 else if(This->default_ext)
473 lstrcpyW(extbuf, dotW);
474 lstrcatW(extbuf, This->default_ext);
475 newext = extbuf;
478 if(newext)
480 WCHAR *ext = PathFindExtensionW(canon_filename);
481 if(lstrcmpW(ext, newext))
482 lstrcatW(canon_filename, newext);
485 else
487 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
488 !PathFileExistsW(canon_filename))
490 if(This->default_ext)
492 lstrcatW(canon_filename, dotW);
493 lstrcatW(canon_filename, This->default_ext);
495 if(!PathFileExistsW(canon_filename))
497 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
498 open_action = ONOPEN_BROWSE;
501 else
503 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
504 open_action = ONOPEN_BROWSE;
510 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
512 if(psf_parent && !(open_action == ONOPEN_BROWSE))
513 IShellFolder_Release(psf_parent);
515 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
518 HeapFree(GetProcessHeap(), 0, files);
519 ILFree(current_folder);
521 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
522 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
524 switch(open_action)
526 case ONOPEN_SEARCH:
527 FIXME("Filtering not implemented.\n");
528 break;
530 case ONOPEN_BROWSE:
531 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
532 if(FAILED(hr))
533 ERR("Failed to browse to directory: %08x\n", hr);
535 IShellFolder_Release(psf_parent);
536 break;
538 case ONOPEN_OPEN:
539 if(events_OnFileOk(This) != S_OK)
540 break;
542 hr = SHGetDesktopFolder(&psf_desktop);
543 if(SUCCEEDED(hr))
545 if(This->psia_results)
546 IShellItemArray_Release(This->psia_results);
548 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
549 &This->psia_results);
550 if(SUCCEEDED(hr))
551 ret = S_OK;
553 IShellFolder_Release(psf_desktop);
555 break;
557 default:
558 ERR("Failed.\n");
559 break;
562 /* Clean up */
563 for(i = 0; i < file_count; i++)
564 ILFree(pidla[i]);
565 HeapFree(GetProcessHeap(), 0, pidla);
567 /* Success closes the dialog */
568 return ret;
571 /**************************************************************************
572 * Control functions.
574 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
576 customctrl *ctrl;
578 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
579 if(ctrl->dlgid == dlgid)
580 return ctrl;
582 ERR("Failed to find control with dialog id %d\n", dlgid);
583 return NULL;
586 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
588 customctrl *ctrl;
590 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
591 if(ctrl->id == ctlid)
592 return ctrl;
594 ERR("Failed to find control with control id %d\n", ctlid);
595 return NULL;
598 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
600 LPWSTR text;
601 UINT len, final_width;
602 UINT lines, final_height;
603 SIZE size;
604 RECT rc;
605 HDC hdc;
606 WCHAR *c;
608 TRACE("\n");
610 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
611 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
612 if(!text) return;
613 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
615 hdc = GetDC(hctrl);
616 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
617 ReleaseDC(hctrl, hdc);
619 if(len && multiline)
621 /* FIXME: line-wrap */
622 for(lines = 1, c = text; *c != '\0'; c++)
623 if(*c == '\n') lines++;
625 final_height = size.cy*lines + 2*4;
627 else
629 GetWindowRect(hctrl, &rc);
630 final_height = rc.bottom - rc.top;
633 final_width = min(max(size.cx, min_width) + 4, max_width);
634 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
635 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
637 HeapFree(GetProcessHeap(), 0, text);
640 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
642 RECT rc;
644 switch(ctrl->type)
646 case IDLG_CCTRL_PUSHBUTTON:
647 case IDLG_CCTRL_COMBOBOX:
648 case IDLG_CCTRL_CHECKBUTTON:
649 case IDLG_CCTRL_TEXT:
650 ctrl_resize(ctrl->hwnd, 160, 160, TRUE);
651 GetWindowRect(ctrl->hwnd, &rc);
652 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
653 SWP_NOZORDER|SWP_NOMOVE|SWP_NOZORDER);
654 break;
655 case IDLG_CCTRL_RADIOBUTTONLIST:
656 case IDLG_CCTRL_EDITBOX:
657 case IDLG_CCTRL_SEPARATOR:
658 case IDLG_CCTRL_MENU:
659 /* Nothing */
660 break;
664 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
666 FileDialogImpl *This = crs->lpCreateParams;
667 TRACE("%p\n", This);
669 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
670 return TRUE;
673 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
675 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
677 TRACE("%p, %lx\n", This, wparam);
679 if(ctrl)
681 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
683 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
684 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
686 else
687 cctrl_event_OnButtonClicked(This, ctrl->id);
690 return TRUE;
693 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
695 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
696 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
698 if(ctrl)
700 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
701 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
703 cctrl_event_OnItemSelected(This, ctrl->id, selid);
705 return TRUE;
708 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
710 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
711 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
712 POINT pt = { 0, nmtb->rcButton.bottom };
713 TBBUTTON tbb;
714 UINT idcmd;
716 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
718 if(ctrl)
720 cctrl_event_OnControlActivating(This,ctrl->id);
722 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
723 ClientToScreen(ctrl->hwnd, &pt);
724 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
725 if(idcmd)
726 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
729 return TBDDRET_DEFAULT;
732 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
734 switch(HIWORD(wparam))
736 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
737 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
740 return FALSE;
743 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
745 NMHDR *nmhdr = (NMHDR*)lparam;
747 switch(nmhdr->code)
749 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
752 return FALSE;
755 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
757 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
758 HWND hwnd_child;
759 RECT rc;
761 switch(message)
763 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
764 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
765 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
766 case WM_SIZE:
767 hwnd_child = GetPropW(hwnd, notifysink_childW);
768 GetClientRect(hwnd, &rc);
769 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
770 return TRUE;
773 return DefWindowProcW(hwnd, message, wparam, lparam);
776 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
777 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
778 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
780 HWND ns_hwnd, control_hwnd;
781 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
782 customctrl *ctrl;
784 if(get_cctrl(This, id))
785 return E_UNEXPECTED; /* Duplicate id */
787 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
788 0, 0, This->cctrl_width, height, This->cctrls_hwnd,
789 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
790 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
791 0, 0, This->cctrl_width, height, ns_hwnd,
792 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
794 if(!ns_hwnd || !control_hwnd)
796 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
797 DestroyWindow(ns_hwnd);
798 DestroyWindow(control_hwnd);
800 return E_FAIL;
803 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
805 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
806 if(!ctrl)
807 return E_OUTOFMEMORY;
809 ctrl->hwnd = control_hwnd;
810 ctrl->wrapper_hwnd = ns_hwnd;
811 ctrl->id = id;
812 ctrl->dlgid = This->cctrl_next_dlgid;
813 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
814 list_add_tail(&This->cctrls, &ctrl->entry);
815 if(ppctrl) *ppctrl = ctrl;
817 This->cctrl_next_dlgid++;
818 return S_OK;
821 /**************************************************************************
822 * Container functions.
824 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
826 UINT container_height;
827 UINT column_width;
828 UINT nr_of_cols;
829 UINT max_control_height, total_height = 0;
830 UINT cur_col_pos, cur_row_pos;
831 customctrl *ctrl;
832 BOOL fits_height;
833 static const UINT col_indent = 100; /* The first column is indented 100px */
834 static const UINT cspacing = 90; /* Columns are spaced with 90px */
835 static const UINT rspacing = 4; /* Rows are spaced with 4 px. */
837 /* Given the new width of the container, this function determines the
838 * needed height of the container and places the controls according to
839 * the new layout. Returns the new height.
842 TRACE("%p\n", This);
844 column_width = This->cctrl_width + cspacing;
845 nr_of_cols = (container_width - col_indent + cspacing) / column_width;
847 /* We don't need to do anything unless the number of visible columns has changed. */
848 if(nr_of_cols == This->cctrls_cols)
850 RECT rc;
851 GetWindowRect(This->cctrls_hwnd, &rc);
852 return rc.bottom - rc.top;
855 This->cctrls_cols = nr_of_cols;
857 /* Get the size of the tallest control, and the total size of
858 * all the controls to figure out the number of slots we need.
860 max_control_height = 0;
861 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
863 if(ctrl->cdcstate & CDCS_VISIBLE)
865 RECT rc;
866 UINT control_height;
867 GetWindowRect(ctrl->wrapper_hwnd, &rc);
868 control_height = rc.bottom - rc.top;
869 max_control_height = max(max_control_height, control_height);
871 total_height += control_height + rspacing;
875 if(!total_height)
876 return 0;
878 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
879 TRACE("Guess: container_height: %d\n",container_height);
881 /* Incrementally increase container_height until all the controls
882 * fit.
884 do {
885 UINT columns_needed = 1;
886 cur_row_pos = 0;
888 fits_height = TRUE;
889 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
891 if(ctrl->cdcstate & CDCS_VISIBLE)
893 RECT rc;
894 UINT control_height;
895 GetWindowRect(ctrl->wrapper_hwnd, &rc);
896 control_height = rc.bottom - rc.top;
898 if(cur_row_pos + control_height > container_height)
900 if(++columns_needed > nr_of_cols)
902 container_height += 1;
903 fits_height = FALSE;
904 break;
906 cur_row_pos = 0;
909 cur_row_pos += control_height + rspacing;
912 } while(!fits_height);
914 TRACE("Final container height: %d\n", container_height);
916 /* Move the controls to their final destination
918 cur_col_pos = col_indent, cur_row_pos = 0;
919 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
921 if(ctrl->cdcstate & CDCS_VISIBLE)
923 RECT rc;
924 UINT control_height;
925 GetWindowRect(ctrl->wrapper_hwnd, &rc);
926 control_height = rc.bottom - rc.top;
928 if(cur_row_pos + control_height > container_height)
930 cur_row_pos = 0;
931 cur_col_pos += This->cctrl_width + cspacing;
934 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos, cur_row_pos, 0, 0,
935 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
937 cur_row_pos += control_height + rspacing;
941 /* Sanity check */
942 if(cur_row_pos + This->cctrl_width > container_width)
943 ERR("-- Failed to place controls properly.\n");
945 return container_height;
948 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
950 LONG wndstyle;
952 if(parent)
954 customctrl *ctrl;
955 HFONT font;
957 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
958 wndstyle &= ~(WS_POPUP);
959 wndstyle |= WS_CHILD;
960 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
962 SetParent(This->cctrls_hwnd, parent);
963 ShowWindow(This->cctrls_hwnd, TRUE);
965 /* Set the fonts to match the dialog font. */
966 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
967 if(!font)
968 ERR("Failed to get font handle from dialog.\n");
970 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
972 if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
973 customctrl_resize(This, ctrl);
976 else
978 ShowWindow(This->cctrls_hwnd, FALSE);
980 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
981 wndstyle &= ~(WS_CHILD);
982 wndstyle |= WS_POPUP;
983 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
985 SetParent(This->cctrls_hwnd, NULL);
989 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
991 FileDialogImpl *This = crs->lpCreateParams;
992 TRACE("%p\n", This);
994 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
995 return TRUE;
998 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
1000 customctrl *cur1, *cur2;
1001 TRACE("%p\n", This);
1003 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1005 TRACE("Freeing control %p\n", cur1);
1006 list_remove(&cur1->entry);
1008 if(cur1->type == IDLG_CCTRL_MENU)
1010 TBBUTTON tbb;
1011 SendMessageW(cur1->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1012 DestroyMenu((HMENU)tbb.dwData);
1015 DestroyWindow(cur1->hwnd);
1016 HeapFree(GetProcessHeap(), 0, cur1);
1019 return TRUE;
1022 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1024 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1026 switch(umessage)
1028 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1029 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1030 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1033 return FALSE;
1036 static HRESULT init_custom_controls(FileDialogImpl *This)
1038 WNDCLASSW wc;
1039 static const WCHAR ctrl_container_classname[] =
1040 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1042 InitCommonControlsEx(NULL);
1044 This->cctrl_width = 160; /* Controls have a fixed width */
1045 This->cctrl_def_height = 23;
1046 This->cctrls_cols = 0;
1048 This->cctrl_next_dlgid = 0x2000;
1049 list_init(&This->cctrls);
1051 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1053 wc.style = CS_HREDRAW | CS_VREDRAW;
1054 wc.lpfnWndProc = ctrl_container_wndproc;
1055 wc.cbClsExtra = 0;
1056 wc.cbWndExtra = 0;
1057 wc.hInstance = COMDLG32_hInstance;
1058 wc.hIcon = 0;
1059 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1060 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1061 wc.lpszMenuName = NULL;
1062 wc.lpszClassName = ctrl_container_classname;
1064 if(!RegisterClassW(&wc)) return E_FAIL;
1067 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1068 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1069 0, 0, 0, 0, NULL, 0,
1070 COMDLG32_hInstance, (void*)This);
1071 if(!This->cctrls_hwnd)
1072 return E_FAIL;
1074 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1076 /* Register class for */
1077 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1078 wc.hInstance != COMDLG32_hInstance)
1080 wc.style = CS_HREDRAW | CS_VREDRAW;
1081 wc.lpfnWndProc = notifysink_proc;
1082 wc.cbClsExtra = 0;
1083 wc.cbWndExtra = 0;
1084 wc.hInstance = COMDLG32_hInstance;
1085 wc.hIcon = 0;
1086 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1087 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1088 wc.lpszMenuName = NULL;
1089 wc.lpszClassName = floatnotifysinkW;
1091 if (!RegisterClassW(&wc))
1092 ERR("Failed to register FloatNotifySink window class.\n");
1095 return S_OK;
1098 /**************************************************************************
1099 * Window related functions.
1101 static SIZE update_layout(FileDialogImpl *This)
1103 HDWP hdwp;
1104 HWND hwnd;
1105 RECT dialog_rc;
1106 RECT cancel_rc, open_rc;
1107 RECT filetype_rc, filename_rc, filenamelabel_rc;
1108 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1109 int missing_width, missing_height;
1110 static const UINT vspacing = 4, hspacing = 4;
1111 SIZE ret;
1113 GetClientRect(This->dlg_hwnd, &dialog_rc);
1115 missing_width = max(0, 320 - dialog_rc.right);
1116 missing_height = max(0, 200 - dialog_rc.bottom);
1118 if(missing_width || missing_height)
1120 TRACE("Missing (%d, %d)\n", missing_width, missing_height);
1121 ret.cx = missing_width;
1122 ret.cy = missing_height;
1123 return ret;
1126 /****
1127 * Calculate the size of the dialog and all the parts.
1130 /* Cancel button */
1131 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1132 if(hwnd)
1134 int cancel_width, cancel_height;
1135 GetWindowRect(hwnd, &cancel_rc);
1136 cancel_width = cancel_rc.right - cancel_rc.left;
1137 cancel_height = cancel_rc.bottom - cancel_rc.top;
1139 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1140 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1141 cancel_rc.right = cancel_rc.left + cancel_width;
1142 cancel_rc.bottom = cancel_rc.top + cancel_height;
1145 /* Open/Save button */
1146 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1147 if(hwnd)
1149 int open_width, open_height;
1150 GetWindowRect(hwnd, &open_rc);
1151 open_width = open_rc.right - open_rc.left;
1152 open_height = open_rc.bottom - open_rc.top;
1154 open_rc.left = cancel_rc.left - open_width - hspacing;
1155 open_rc.top = cancel_rc.top;
1156 open_rc.right = open_rc.left + open_width;
1157 open_rc.bottom = open_rc.top + open_height;
1160 /* The filetype combobox. */
1161 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1162 if(hwnd)
1164 int filetype_width, filetype_height;
1165 GetWindowRect(hwnd, &filetype_rc);
1167 filetype_width = filetype_rc.right - filetype_rc.left;
1168 filetype_height = filetype_rc.bottom - filetype_rc.top;
1170 filetype_rc.right = cancel_rc.right;
1172 filetype_rc.left = filetype_rc.right - filetype_width;
1173 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1174 filetype_rc.bottom = filetype_rc.top + filetype_height;
1176 if(!This->filterspec_count)
1177 filetype_rc.left = filetype_rc.right;
1180 /* Filename label. */
1181 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1182 if(hwnd)
1184 int filetypelabel_width, filetypelabel_height;
1185 GetWindowRect(hwnd, &filenamelabel_rc);
1187 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1188 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1190 filenamelabel_rc.left = 160; /* FIXME */
1191 filenamelabel_rc.top = filetype_rc.top;
1192 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1193 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1196 /* Filename edit box. */
1197 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1198 if(hwnd)
1200 int filename_width, filename_height;
1201 GetWindowRect(hwnd, &filename_rc);
1203 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1204 filename_height = filename_rc.bottom - filename_rc.top;
1206 filename_rc.left = filenamelabel_rc.right + hspacing;
1207 filename_rc.top = filetype_rc.top;
1208 filename_rc.right = filename_rc.left + filename_width;
1209 filename_rc.bottom = filename_rc.top + filename_height;
1212 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1213 if(hwnd)
1215 GetWindowRect(hwnd, &toolbar_rc);
1216 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1219 /* The custom controls */
1220 customctrls_rc.left = dialog_rc.left + hspacing;
1221 customctrls_rc.right = dialog_rc.right - hspacing;
1222 customctrls_rc.bottom = filename_rc.top - vspacing;
1223 customctrls_rc.top = customctrls_rc.bottom -
1224 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1226 /* The ExplorerBrowser control. */
1227 ebrowser_rc.left = dialog_rc.left + hspacing;
1228 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1229 ebrowser_rc.right = dialog_rc.right - hspacing;
1230 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1232 /****
1233 * Move everything to the right place.
1236 /* FIXME: The Save Dialog uses a slightly different layout. */
1237 hdwp = BeginDeferWindowPos(7);
1239 if(hdwp && This->peb)
1240 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1242 if(hdwp && This->cctrls_hwnd)
1243 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1244 customctrls_rc.left, customctrls_rc.top,
1245 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1246 SWP_NOZORDER | SWP_NOACTIVATE);
1248 /* The default controls */
1249 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1250 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1251 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1253 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1254 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1255 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1256 SWP_NOZORDER | SWP_NOACTIVATE);
1258 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1259 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1260 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1262 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1263 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1264 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1266 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1267 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1268 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1270 if(hdwp)
1271 EndDeferWindowPos(hdwp);
1272 else
1273 ERR("Failed to position dialog controls.\n");
1275 ret.cx = 0; ret.cy = 0;
1276 return ret;
1279 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1281 IShellItem *psi_folder;
1282 FOLDERSETTINGS fos;
1283 RECT rc = {0};
1284 HRESULT hr;
1286 /* Create ExplorerBrowser instance */
1287 OleInitialize(NULL);
1289 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1290 &IID_IExplorerBrowser, (void**)&This->peb);
1291 if(FAILED(hr))
1293 ERR("Failed to instantiate ExplorerBrowser control.\n");
1294 return hr;
1297 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES);
1299 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1300 if(FAILED(hr))
1302 ERR("Failed to initialize the ExplorerBrowser control.\n");
1303 IExplorerBrowser_Release(This->peb);
1304 This->peb = NULL;
1305 return hr;
1307 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1308 if(FAILED(hr))
1309 ERR("Advise (ExplorerBrowser) failed.\n");
1311 /* Get previous options? */
1312 fos.ViewMode = fos.fFlags = 0;
1313 if(!(This->options & FOS_ALLOWMULTISELECT))
1314 fos.fFlags |= FWF_SINGLESEL;
1316 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1318 hr = IUnknown_SetSite((IUnknown*)This->peb, (IUnknown*)This);
1319 if(FAILED(hr))
1320 ERR("SetSite (ExplorerBrowser) failed.\n");
1322 /* Browse somewhere */
1323 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1324 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1326 return S_OK;
1329 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1331 HWND htoolbar;
1332 TBADDBITMAP tbab;
1333 TBBUTTON button[2];
1335 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1336 0, 0, 0, 0,
1337 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1339 tbab.hInst = HINST_COMMCTRL;
1340 tbab.nID = IDB_HIST_LARGE_COLOR;
1341 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1343 button[0].iBitmap = HIST_BACK;
1344 button[0].idCommand = IDC_NAVBACK;
1345 button[0].fsState = TBSTATE_ENABLED;
1346 button[0].fsStyle = BTNS_BUTTON;
1347 button[0].dwData = 0;
1348 button[0].iString = 0;
1350 button[1].iBitmap = HIST_FORWARD;
1351 button[1].idCommand = IDC_NAVFORWARD;
1352 button[1].fsState = TBSTATE_ENABLED;
1353 button[1].fsStyle = BTNS_BUTTON;
1354 button[1].dwData = 0;
1355 button[1].iString = 0;
1357 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1358 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1359 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1362 static void update_control_text(FileDialogImpl *This)
1364 HWND hitem;
1365 if(This->custom_title)
1366 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1368 if(This->custom_okbutton &&
1369 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1371 SetWindowTextW(hitem, This->custom_okbutton);
1372 ctrl_resize(hitem, 50, 250, FALSE);
1375 if(This->custom_cancelbutton &&
1376 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1378 SetWindowTextW(hitem, This->custom_cancelbutton);
1379 ctrl_resize(hitem, 50, 250, FALSE);
1382 if(This->custom_filenamelabel &&
1383 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1385 SetWindowTextW(hitem, This->custom_filenamelabel);
1386 ctrl_resize(hitem, 50, 250, FALSE);
1390 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1392 FileDialogImpl *This = (FileDialogImpl*)lParam;
1393 HWND hitem;
1395 TRACE("(%p, %p)\n", This, hwnd);
1397 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1398 This->dlg_hwnd = hwnd;
1400 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1401 if(hitem) ShowWindow(hitem, SW_HIDE);
1403 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1404 if(hitem) ShowWindow(hitem, SW_HIDE);
1406 /* Fill filetypes combobox, or hide it. */
1407 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1408 if(This->filterspec_count)
1410 UINT i;
1411 for(i = 0; i < This->filterspec_count; i++)
1412 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
1414 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
1416 else
1417 ShowWindow(hitem, SW_HIDE);
1419 if(This->set_filename &&
1420 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1421 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
1423 ctrl_container_reparent(This, This->dlg_hwnd);
1424 init_explorerbrowser(This);
1425 init_toolbar(This, hwnd);
1426 update_control_text(This);
1427 update_layout(This);
1429 return TRUE;
1432 static LRESULT on_wm_size(FileDialogImpl *This)
1434 update_layout(This);
1435 return FALSE;
1438 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
1440 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
1441 TRACE("%p (%p)\n", This, mmi);
1443 /* FIXME */
1444 mmi->ptMinTrackSize.x = 640;
1445 mmi->ptMinTrackSize.y = 480;
1447 return FALSE;
1450 static LRESULT on_wm_destroy(FileDialogImpl *This)
1452 TRACE("%p\n", This);
1454 if(This->peb)
1456 IExplorerBrowser_Destroy(This->peb);
1457 IExplorerBrowser_Release(This->peb);
1458 This->peb = NULL;
1461 ctrl_container_reparent(This, NULL);
1462 This->dlg_hwnd = NULL;
1464 return TRUE;
1467 static LRESULT on_idok(FileDialogImpl *This)
1469 TRACE("%p\n", This);
1471 if(SUCCEEDED(on_default_action(This)))
1472 EndDialog(This->dlg_hwnd, S_OK);
1474 return FALSE;
1477 static LRESULT on_idcancel(FileDialogImpl *This)
1479 TRACE("%p\n", This);
1481 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
1483 return FALSE;
1486 static LRESULT on_browse_back(FileDialogImpl *This)
1488 TRACE("%p\n", This);
1489 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
1490 return FALSE;
1493 static LRESULT on_browse_forward(FileDialogImpl *This)
1495 TRACE("%p\n", This);
1496 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
1497 return FALSE;
1500 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1502 if(HIWORD(wparam) == CBN_SELCHANGE)
1504 IShellView *psv;
1505 HRESULT hr;
1506 LPWSTR filename;
1507 UINT prev_index = This->filetypeindex;
1509 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
1510 TRACE("File type selection changed to %d.\n", This->filetypeindex);
1512 if(prev_index == This->filetypeindex)
1513 return FALSE;
1515 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
1516 if(SUCCEEDED(hr))
1518 IShellView_Refresh(psv);
1519 IShellView_Release(psv);
1522 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
1524 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
1526 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
1527 if(ext)
1529 lstrcpyW(buf, filename);
1531 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
1532 PathRemoveExtensionW(buf);
1534 lstrcatW(buf, ext);
1535 set_file_name(This, buf);
1537 CoTaskMemFree(filename);
1541 return FALSE;
1544 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
1546 switch(LOWORD(wparam))
1548 case IDOK: return on_idok(This);
1549 case IDCANCEL: return on_idcancel(This);
1550 case IDC_NAVBACK: return on_browse_back(This);
1551 case IDC_NAVFORWARD: return on_browse_forward(This);
1552 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
1553 default: TRACE("Unknown command.\n");
1555 return FALSE;
1558 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1560 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1562 switch(umessage)
1564 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
1565 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
1566 case WM_SIZE: return on_wm_size(This);
1567 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
1568 case WM_DESTROY: return on_wm_destroy(This);
1571 return FALSE;
1574 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
1576 INT_PTR res;
1578 SetLastError(0);
1579 res = DialogBoxParamW(COMDLG32_hInstance,
1580 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
1581 parent, itemdlg_dlgproc, (LPARAM)This);
1582 This->dlg_hwnd = NULL;
1583 if(res == -1)
1585 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
1586 return E_FAIL;
1589 TRACE("Returning 0x%08x\n", (HRESULT)res);
1590 return (HRESULT)res;
1593 /**************************************************************************
1594 * IFileDialog implementation
1596 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
1598 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
1601 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
1602 REFIID riid,
1603 void **ppvObject)
1605 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1606 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1608 *ppvObject = NULL;
1609 if(IsEqualGUID(riid, &IID_IUnknown) ||
1610 IsEqualGUID(riid, &IID_IFileDialog) ||
1611 IsEqualGUID(riid, &IID_IFileDialog2))
1613 *ppvObject = iface;
1615 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
1617 *ppvObject = &This->u.IFileOpenDialog_iface;
1619 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
1621 *ppvObject = &This->u.IFileSaveDialog_iface;
1623 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
1625 *ppvObject = &This->IExplorerBrowserEvents_iface;
1627 else if(IsEqualGUID(riid, &IID_IServiceProvider))
1629 *ppvObject = &This->IServiceProvider_iface;
1631 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
1632 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
1633 IsEqualGUID(&IID_ICommDlgBrowser, riid))
1635 *ppvObject = &This->ICommDlgBrowser3_iface;
1637 else if(IsEqualGUID(&IID_IOleWindow, riid))
1639 *ppvObject = &This->IOleWindow_iface;
1641 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
1642 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
1644 *ppvObject = &This->IFileDialogCustomize_iface;
1646 else
1647 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
1649 if(*ppvObject)
1651 IUnknown_AddRef((IUnknown*)*ppvObject);
1652 return S_OK;
1655 return E_NOINTERFACE;
1658 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
1660 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1661 LONG ref = InterlockedIncrement(&This->ref);
1662 TRACE("%p - ref %d\n", This, ref);
1664 return ref;
1667 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
1669 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1670 LONG ref = InterlockedDecrement(&This->ref);
1671 TRACE("%p - ref %d\n", This, ref);
1673 if(!ref)
1675 UINT i;
1676 for(i = 0; i < This->filterspec_count; i++)
1678 LocalFree((void*)This->filterspecs[i].pszName);
1679 LocalFree((void*)This->filterspecs[i].pszSpec);
1681 HeapFree(GetProcessHeap(), 0, This->filterspecs);
1683 DestroyWindow(This->cctrls_hwnd);
1685 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
1686 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
1687 if(This->psi_folder) IShellItem_Release(This->psi_folder);
1688 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
1689 if(This->psia_results) IShellItemArray_Release(This->psia_results);
1691 LocalFree(This->set_filename);
1692 LocalFree(This->default_ext);
1693 LocalFree(This->custom_title);
1694 LocalFree(This->custom_okbutton);
1695 LocalFree(This->custom_cancelbutton);
1696 LocalFree(This->custom_filenamelabel);
1698 HeapFree(GetProcessHeap(), 0, This);
1701 return ref;
1704 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
1706 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1707 TRACE("%p (%p)\n", iface, hwndOwner);
1709 return create_dialog(This, hwndOwner);
1712 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
1713 const COMDLG_FILTERSPEC *rgFilterSpec)
1715 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1716 UINT i;
1717 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
1719 if(This->filterspecs)
1720 return E_UNEXPECTED;
1722 if(!rgFilterSpec)
1723 return E_INVALIDARG;
1725 if(!cFileTypes)
1726 return S_OK;
1728 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
1729 for(i = 0; i < cFileTypes; i++)
1731 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
1732 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
1734 This->filterspec_count = cFileTypes;
1736 return S_OK;
1739 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
1741 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1742 TRACE("%p (%d)\n", This, iFileType);
1744 if(!This->filterspecs)
1745 return E_FAIL;
1747 if(iFileType >= This->filterspec_count)
1748 This->filetypeindex = This->filterspec_count - 1;
1749 else
1750 This->filetypeindex = iFileType;
1752 return S_OK;
1755 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
1757 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1758 TRACE("%p (%p)\n", This, piFileType);
1760 if(!piFileType)
1761 return E_INVALIDARG;
1763 *piFileType = This->filetypeindex;
1765 return S_OK;
1768 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
1770 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1771 events_client *client;
1772 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
1774 if(!pfde || !pdwCookie)
1775 return E_INVALIDARG;
1777 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
1778 client->pfde = pfde;
1779 client->cookie = ++This->events_next_cookie;
1781 IFileDialogEvents_AddRef(pfde);
1782 *pdwCookie = client->cookie;
1784 list_add_tail(&This->events_clients, &client->entry);
1786 return S_OK;
1789 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
1791 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1792 events_client *client, *found = NULL;
1793 TRACE("%p (%d)\n", This, dwCookie);
1795 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
1797 if(client->cookie == dwCookie)
1799 found = client;
1800 break;
1804 if(found)
1806 list_remove(&found->entry);
1807 IFileDialogEvents_Release(found->pfde);
1808 HeapFree(GetProcessHeap(), 0, found);
1809 return S_OK;
1812 return E_INVALIDARG;
1815 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
1817 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1818 TRACE("%p (0x%x)\n", This, fos);
1820 This->options = fos;
1822 return S_OK;
1825 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
1827 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1828 TRACE("%p (%p)\n", This, pfos);
1830 if(!pfos)
1831 return E_INVALIDARG;
1833 *pfos = This->options;
1835 return S_OK;
1838 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
1840 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1841 TRACE("%p (%p)\n", This, psi);
1842 if(This->psi_defaultfolder)
1843 IShellItem_Release(This->psi_defaultfolder);
1845 This->psi_defaultfolder = psi;
1847 if(This->psi_defaultfolder)
1848 IShellItem_AddRef(This->psi_defaultfolder);
1850 return S_OK;
1853 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
1855 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1856 TRACE("%p (%p)\n", This, psi);
1857 if(This->psi_setfolder)
1858 IShellItem_Release(This->psi_setfolder);
1860 This->psi_setfolder = psi;
1862 if(This->psi_setfolder)
1863 IShellItem_AddRef(This->psi_setfolder);
1865 return S_OK;
1868 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
1870 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1871 TRACE("%p (%p)\n", This, ppsi);
1872 if(!ppsi)
1873 return E_INVALIDARG;
1875 /* FIXME:
1876 If the dialog is shown, return the current(ly selected) folder. */
1878 *ppsi = NULL;
1879 if(This->psi_folder)
1880 *ppsi = This->psi_folder;
1881 else if(This->psi_setfolder)
1882 *ppsi = This->psi_setfolder;
1883 else if(This->psi_defaultfolder)
1884 *ppsi = This->psi_defaultfolder;
1886 if(*ppsi)
1888 IShellItem_AddRef(*ppsi);
1889 return S_OK;
1892 return E_FAIL;
1895 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
1897 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1898 HRESULT hr;
1899 TRACE("%p (%p)\n", This, ppsi);
1901 if(!ppsi)
1902 return E_INVALIDARG;
1904 if(This->psia_selection)
1906 /* FIXME: Check filename edit box */
1907 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
1908 return hr;
1911 return E_FAIL;
1914 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
1916 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1917 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
1919 set_file_name(This, pszName);
1921 return S_OK;
1924 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
1926 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1927 TRACE("%p (%p)\n", iface, pszName);
1929 if(!pszName)
1930 return E_INVALIDARG;
1932 *pszName = NULL;
1933 if(get_file_name(This, pszName))
1934 return S_OK;
1935 else
1936 return E_FAIL;
1939 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
1941 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1942 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
1944 LocalFree(This->custom_title);
1945 This->custom_title = StrDupW(pszTitle);
1946 update_control_text(This);
1948 return S_OK;
1951 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
1953 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1954 TRACE("%p (%s)\n", This, debugstr_w(pszText));
1956 LocalFree(This->custom_okbutton);
1957 This->custom_okbutton = StrDupW(pszText);
1958 update_control_text(This);
1959 update_layout(This);
1961 return S_OK;
1964 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
1966 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1967 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
1969 LocalFree(This->custom_filenamelabel);
1970 This->custom_filenamelabel = StrDupW(pszLabel);
1971 update_control_text(This);
1972 update_layout(This);
1974 return S_OK;
1977 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
1979 FileDialogImpl *This = impl_from_IFileDialog2(iface);
1980 HRESULT hr;
1981 TRACE("%p (%p)\n", This, ppsi);
1983 if(!ppsi)
1984 return E_INVALIDARG;
1986 if(This->psia_results)
1988 UINT item_count;
1989 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
1990 if(SUCCEEDED(hr))
1992 if(item_count != 1)
1993 return E_FAIL;
1995 /* Adds a reference. */
1996 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
1999 return hr;
2002 return E_UNEXPECTED;
2005 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2007 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2008 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2009 return E_NOTIMPL;
2012 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2014 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2015 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2017 LocalFree(This->default_ext);
2018 This->default_ext = StrDupW(pszDefaultExtension);
2020 return S_OK;
2023 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2025 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2026 TRACE("%p (0x%08x)\n", This, hr);
2028 if(This->dlg_hwnd)
2029 EndDialog(This->dlg_hwnd, hr);
2031 return S_OK;
2034 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2036 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2037 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2038 This->client_guid = *guid;
2039 return S_OK;
2042 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2044 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2045 FIXME("stub - %p\n", This);
2046 return E_NOTIMPL;
2049 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2051 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2052 FIXME("stub - %p (%p)\n", This, pFilter);
2053 return E_NOTIMPL;
2056 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2058 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2059 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2061 LocalFree(This->custom_cancelbutton);
2062 This->custom_cancelbutton = StrDupW(pszLabel);
2063 update_control_text(This);
2064 update_layout(This);
2066 return S_OK;
2069 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2071 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2072 FIXME("stub - %p (%p)\n", This, psi);
2073 return E_NOTIMPL;
2076 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2077 IFileDialog2_fnQueryInterface,
2078 IFileDialog2_fnAddRef,
2079 IFileDialog2_fnRelease,
2080 IFileDialog2_fnShow,
2081 IFileDialog2_fnSetFileTypes,
2082 IFileDialog2_fnSetFileTypeIndex,
2083 IFileDialog2_fnGetFileTypeIndex,
2084 IFileDialog2_fnAdvise,
2085 IFileDialog2_fnUnadvise,
2086 IFileDialog2_fnSetOptions,
2087 IFileDialog2_fnGetOptions,
2088 IFileDialog2_fnSetDefaultFolder,
2089 IFileDialog2_fnSetFolder,
2090 IFileDialog2_fnGetFolder,
2091 IFileDialog2_fnGetCurrentSelection,
2092 IFileDialog2_fnSetFileName,
2093 IFileDialog2_fnGetFileName,
2094 IFileDialog2_fnSetTitle,
2095 IFileDialog2_fnSetOkButtonLabel,
2096 IFileDialog2_fnSetFileNameLabel,
2097 IFileDialog2_fnGetResult,
2098 IFileDialog2_fnAddPlace,
2099 IFileDialog2_fnSetDefaultExtension,
2100 IFileDialog2_fnClose,
2101 IFileDialog2_fnSetClientGuid,
2102 IFileDialog2_fnClearClientData,
2103 IFileDialog2_fnSetFilter,
2104 IFileDialog2_fnSetCancelButtonLabel,
2105 IFileDialog2_fnSetNavigationRoot
2108 /**************************************************************************
2109 * IFileOpenDialog
2111 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2113 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2116 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2117 REFIID riid, void **ppvObject)
2119 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2120 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2123 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2125 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2126 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2129 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2131 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2132 return IFileDialog2_Release(&This->IFileDialog2_iface);
2135 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2137 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2138 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2141 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2142 const COMDLG_FILTERSPEC *rgFilterSpec)
2144 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2145 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2148 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2150 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2151 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2154 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2156 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2157 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2160 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2161 DWORD *pdwCookie)
2163 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2164 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2167 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2169 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2170 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2173 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2175 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2176 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2179 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2181 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2182 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2185 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2187 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2188 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2191 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2193 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2194 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2197 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2199 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2200 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2203 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2205 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2206 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2209 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2211 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2212 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2215 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2217 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2218 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2221 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2223 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2224 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2227 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2229 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2230 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2233 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2235 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2236 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2239 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2241 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2242 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2245 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2247 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2248 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2251 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2252 LPCWSTR pszDefaultExtension)
2254 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2255 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2258 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2260 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2261 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2264 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2266 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2267 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2270 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2272 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2273 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2276 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2278 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2279 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2282 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2284 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2285 TRACE("%p (%p)\n", This, ppenum);
2287 *ppenum = This->psia_results;
2289 if(*ppenum)
2291 IShellItemArray_AddRef(*ppenum);
2292 return S_OK;
2295 return E_FAIL;
2298 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2300 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2301 TRACE("%p (%p)\n", This, ppsai);
2303 if(This->psia_selection)
2305 *ppsai = This->psia_selection;
2306 IShellItemArray_AddRef(*ppsai);
2307 return S_OK;
2310 return E_FAIL;
2313 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2314 IFileOpenDialog_fnQueryInterface,
2315 IFileOpenDialog_fnAddRef,
2316 IFileOpenDialog_fnRelease,
2317 IFileOpenDialog_fnShow,
2318 IFileOpenDialog_fnSetFileTypes,
2319 IFileOpenDialog_fnSetFileTypeIndex,
2320 IFileOpenDialog_fnGetFileTypeIndex,
2321 IFileOpenDialog_fnAdvise,
2322 IFileOpenDialog_fnUnadvise,
2323 IFileOpenDialog_fnSetOptions,
2324 IFileOpenDialog_fnGetOptions,
2325 IFileOpenDialog_fnSetDefaultFolder,
2326 IFileOpenDialog_fnSetFolder,
2327 IFileOpenDialog_fnGetFolder,
2328 IFileOpenDialog_fnGetCurrentSelection,
2329 IFileOpenDialog_fnSetFileName,
2330 IFileOpenDialog_fnGetFileName,
2331 IFileOpenDialog_fnSetTitle,
2332 IFileOpenDialog_fnSetOkButtonLabel,
2333 IFileOpenDialog_fnSetFileNameLabel,
2334 IFileOpenDialog_fnGetResult,
2335 IFileOpenDialog_fnAddPlace,
2336 IFileOpenDialog_fnSetDefaultExtension,
2337 IFileOpenDialog_fnClose,
2338 IFileOpenDialog_fnSetClientGuid,
2339 IFileOpenDialog_fnClearClientData,
2340 IFileOpenDialog_fnSetFilter,
2341 IFileOpenDialog_fnGetResults,
2342 IFileOpenDialog_fnGetSelectedItems
2345 /**************************************************************************
2346 * IFileSaveDialog
2348 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
2350 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
2353 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
2354 REFIID riid,
2355 void **ppvObject)
2357 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2358 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2361 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
2363 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2364 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2367 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
2369 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2370 return IFileDialog2_Release(&This->IFileDialog2_iface);
2373 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
2375 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2376 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2379 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
2380 const COMDLG_FILTERSPEC *rgFilterSpec)
2382 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2383 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2386 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
2388 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2389 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2392 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
2394 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2395 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2398 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
2399 DWORD *pdwCookie)
2401 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2402 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2405 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
2407 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2408 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2411 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
2413 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2414 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2417 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2419 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2420 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2423 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
2425 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2426 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2429 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
2431 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2432 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2435 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
2437 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2438 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2441 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
2443 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2444 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2447 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
2449 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2450 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2453 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
2455 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2456 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2459 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
2461 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2462 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2465 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
2467 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2468 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2471 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
2473 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2474 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2477 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
2479 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2480 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2483 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
2485 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2486 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2489 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
2490 LPCWSTR pszDefaultExtension)
2492 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2493 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2496 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
2498 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2499 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2502 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
2504 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2505 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2508 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
2510 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2511 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2514 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
2516 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2517 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2520 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
2522 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2523 FIXME("stub - %p (%p)\n", This, psi);
2524 return E_NOTIMPL;
2527 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
2529 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2530 FIXME("stub - %p (%p)\n", This, pStore);
2531 return E_NOTIMPL;
2534 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
2535 IPropertyDescriptionList *pList,
2536 BOOL fAppendDefault)
2538 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2539 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
2540 return E_NOTIMPL;
2543 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
2545 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2546 FIXME("stub - %p (%p)\n", This, ppStore);
2547 return E_NOTIMPL;
2550 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
2551 IShellItem *psi,
2552 IPropertyStore *pStore,
2553 HWND hwnd,
2554 IFileOperationProgressSink *pSink)
2556 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
2557 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
2558 return E_NOTIMPL;
2561 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
2562 IFileSaveDialog_fnQueryInterface,
2563 IFileSaveDialog_fnAddRef,
2564 IFileSaveDialog_fnRelease,
2565 IFileSaveDialog_fnShow,
2566 IFileSaveDialog_fnSetFileTypes,
2567 IFileSaveDialog_fnSetFileTypeIndex,
2568 IFileSaveDialog_fnGetFileTypeIndex,
2569 IFileSaveDialog_fnAdvise,
2570 IFileSaveDialog_fnUnadvise,
2571 IFileSaveDialog_fnSetOptions,
2572 IFileSaveDialog_fnGetOptions,
2573 IFileSaveDialog_fnSetDefaultFolder,
2574 IFileSaveDialog_fnSetFolder,
2575 IFileSaveDialog_fnGetFolder,
2576 IFileSaveDialog_fnGetCurrentSelection,
2577 IFileSaveDialog_fnSetFileName,
2578 IFileSaveDialog_fnGetFileName,
2579 IFileSaveDialog_fnSetTitle,
2580 IFileSaveDialog_fnSetOkButtonLabel,
2581 IFileSaveDialog_fnSetFileNameLabel,
2582 IFileSaveDialog_fnGetResult,
2583 IFileSaveDialog_fnAddPlace,
2584 IFileSaveDialog_fnSetDefaultExtension,
2585 IFileSaveDialog_fnClose,
2586 IFileSaveDialog_fnSetClientGuid,
2587 IFileSaveDialog_fnClearClientData,
2588 IFileSaveDialog_fnSetFilter,
2589 IFileSaveDialog_fnSetSaveAsItem,
2590 IFileSaveDialog_fnSetProperties,
2591 IFileSaveDialog_fnSetCollectedProperties,
2592 IFileSaveDialog_fnGetProperties,
2593 IFileSaveDialog_fnApplyProperties
2596 /**************************************************************************
2597 * IExplorerBrowserEvents implementation
2599 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
2601 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
2604 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
2605 REFIID riid, void **ppvObject)
2607 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2608 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2610 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2613 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
2615 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2616 TRACE("%p\n", This);
2617 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2620 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
2622 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2623 TRACE("%p\n", This);
2624 return IFileDialog2_Release(&This->IFileDialog2_iface);
2627 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
2628 PCIDLIST_ABSOLUTE pidlFolder)
2630 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2631 IShellItem *psi;
2632 HRESULT hr;
2633 TRACE("%p (%p)\n", This, pidlFolder);
2635 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
2636 if(SUCCEEDED(hr))
2638 hr = events_OnFolderChanging(This, psi);
2639 IShellItem_Release(psi);
2641 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
2642 if(hr == S_FALSE)
2643 hr = E_FAIL;
2645 return hr;
2647 else
2648 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
2650 return S_OK;
2653 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
2654 IShellView *psv)
2656 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2657 TRACE("%p (%p)\n", This, psv);
2658 return S_OK;
2661 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
2662 PCIDLIST_ABSOLUTE pidlFolder)
2664 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2665 HRESULT hr;
2666 TRACE("%p (%p)\n", This, pidlFolder);
2668 if(This->psi_folder)
2669 IShellItem_Release(This->psi_folder);
2671 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
2672 if(FAILED(hr))
2674 ERR("Failed to get the current folder.\n");
2675 This->psi_folder = NULL;
2678 events_OnFolderChange(This);
2680 return S_OK;
2683 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
2684 PCIDLIST_ABSOLUTE pidlFolder)
2686 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
2687 TRACE("%p (%p)\n", This, pidlFolder);
2688 return S_OK;
2691 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
2692 IExplorerBrowserEvents_fnQueryInterface,
2693 IExplorerBrowserEvents_fnAddRef,
2694 IExplorerBrowserEvents_fnRelease,
2695 IExplorerBrowserEvents_fnOnNavigationPending,
2696 IExplorerBrowserEvents_fnOnViewCreated,
2697 IExplorerBrowserEvents_fnOnNavigationComplete,
2698 IExplorerBrowserEvents_fnOnNavigationFailed
2701 /**************************************************************************
2702 * IServiceProvider implementation
2704 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
2706 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
2709 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
2710 REFIID riid, void **ppvObject)
2712 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2713 TRACE("%p\n", This);
2714 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2717 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
2719 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2720 TRACE("%p\n", This);
2721 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2724 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
2726 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2727 TRACE("%p\n", This);
2728 return IFileDialog2_Release(&This->IFileDialog2_iface);
2731 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
2732 REFGUID guidService,
2733 REFIID riid, void **ppv)
2735 FileDialogImpl *This = impl_from_IServiceProvider(iface);
2736 HRESULT hr = E_NOTIMPL;
2737 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
2739 *ppv = NULL;
2740 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
2741 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
2742 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
2743 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
2744 else
2745 FIXME("Interface %s requested from unknown service %s\n",
2746 debugstr_guid(riid), debugstr_guid(guidService));
2748 return hr;
2751 static const IServiceProviderVtbl vt_IServiceProvider = {
2752 IServiceProvider_fnQueryInterface,
2753 IServiceProvider_fnAddRef,
2754 IServiceProvider_fnRelease,
2755 IServiceProvider_fnQueryService
2758 /**************************************************************************
2759 * ICommDlgBrowser3 implementation
2761 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
2763 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
2766 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
2767 REFIID riid, void **ppvObject)
2769 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2770 TRACE("%p\n", This);
2771 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2774 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
2776 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2777 TRACE("%p\n", This);
2778 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2781 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
2783 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2784 TRACE("%p\n", This);
2785 return IFileDialog2_Release(&This->IFileDialog2_iface);
2788 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
2789 IShellView *shv)
2791 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2792 HRESULT hr;
2793 TRACE("%p (%p)\n", This, shv);
2795 hr = on_default_action(This);
2797 if(SUCCEEDED(hr))
2798 EndDialog(This->dlg_hwnd, S_OK);
2800 return S_OK;
2803 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
2804 IShellView *shv, ULONG uChange )
2806 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2807 IDataObject *new_selection;
2808 HRESULT hr;
2809 TRACE("%p (%p, %x)\n", This, shv, uChange);
2811 switch(uChange)
2813 case CDBOSC_SELCHANGE:
2814 if(This->psia_selection)
2816 IShellItemArray_Release(This->psia_selection);
2817 This->psia_selection = NULL;
2820 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
2821 if(SUCCEEDED(hr))
2823 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
2824 (void**)&This->psia_selection);
2825 if(SUCCEEDED(hr))
2827 fill_filename_from_selection(This);
2828 events_OnSelectionChange(This);
2831 IDataObject_Release(new_selection);
2833 break;
2834 default:
2835 TRACE("Unhandled state change\n");
2837 return S_OK;
2840 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
2841 IShellView *shv, LPCITEMIDLIST pidl)
2843 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2844 IShellItem *psi;
2845 LPWSTR filename;
2846 LPITEMIDLIST parent_pidl;
2847 HRESULT hr;
2848 ULONG attr;
2849 TRACE("%p (%p, %p)\n", This, shv, pidl);
2851 if(!This->filterspec_count)
2852 return S_OK;
2854 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
2855 if(SUCCEEDED(hr))
2857 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
2858 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
2859 ILFree(parent_pidl);
2860 ILFree(full_pidl);
2862 if(FAILED(hr))
2864 ERR("Failed to get shellitem (%08x).\n", hr);
2865 return S_OK;
2868 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
2869 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
2871 IShellItem_Release(psi);
2872 return S_OK;
2875 hr = S_OK;
2876 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
2878 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
2879 hr = S_FALSE;
2880 CoTaskMemFree(filename);
2883 IShellItem_Release(psi);
2884 return hr;
2887 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
2888 IShellView *ppshv, DWORD dwNotifyType)
2890 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2891 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
2892 return E_NOTIMPL;
2895 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
2896 IShellView *pshv,
2897 LPWSTR pszText, int cchMax)
2899 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2900 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
2901 return E_NOTIMPL;
2904 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
2906 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2907 FIXME("Stub: %p (%p)\n", This, pdwFlags);
2908 return E_NOTIMPL;
2911 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
2912 IShellView *pshv, int iColumn)
2914 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2915 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
2916 return E_NOTIMPL;
2919 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
2920 LPWSTR pszFileSpec, int cchFileSpec)
2922 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2923 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
2924 return E_NOTIMPL;
2927 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
2928 IShellView *pshv)
2930 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2931 FIXME("Stub: %p (%p)\n", This, pshv);
2932 return E_NOTIMPL;
2935 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
2936 ICommDlgBrowser3_fnQueryInterface,
2937 ICommDlgBrowser3_fnAddRef,
2938 ICommDlgBrowser3_fnRelease,
2939 ICommDlgBrowser3_fnOnDefaultCommand,
2940 ICommDlgBrowser3_fnOnStateChange,
2941 ICommDlgBrowser3_fnIncludeObject,
2942 ICommDlgBrowser3_fnNotify,
2943 ICommDlgBrowser3_fnGetDefaultMenuText,
2944 ICommDlgBrowser3_fnGetViewFlags,
2945 ICommDlgBrowser3_fnOnColumnClicked,
2946 ICommDlgBrowser3_fnGetCurrentFilter,
2947 ICommDlgBrowser3_fnOnPreviewCreated
2950 /**************************************************************************
2951 * IOleWindow implementation
2953 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
2955 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
2958 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
2960 FileDialogImpl *This = impl_from_IOleWindow(iface);
2961 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2964 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
2966 FileDialogImpl *This = impl_from_IOleWindow(iface);
2967 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2970 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
2972 FileDialogImpl *This = impl_from_IOleWindow(iface);
2973 return IFileDialog2_Release(&This->IFileDialog2_iface);
2976 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
2978 FileDialogImpl *This = impl_from_IOleWindow(iface);
2979 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
2980 return E_NOTIMPL;
2983 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
2985 FileDialogImpl *This = impl_from_IOleWindow(iface);
2986 TRACE("%p (%p)\n", This, phwnd);
2987 *phwnd = This->dlg_hwnd;
2988 return S_OK;
2991 static const IOleWindowVtbl vt_IOleWindow = {
2992 IOleWindow_fnQueryInterface,
2993 IOleWindow_fnAddRef,
2994 IOleWindow_fnRelease,
2995 IOleWindow_fnGetWindow,
2996 IOleWindow_fnContextSensitiveHelp
2999 /**************************************************************************
3000 * IFileDialogCustomize implementation
3002 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3004 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3007 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3008 REFIID riid, void **ppvObject)
3010 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3011 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3014 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3016 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3017 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3020 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3022 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3023 return IFileDialog2_Release(&This->IFileDialog2_iface);
3026 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3027 DWORD dwIDCtl)
3029 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3030 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3031 return E_NOTIMPL;
3034 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3035 DWORD dwIDCtl,
3036 LPCWSTR pszLabel)
3038 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3039 customctrl *ctrl;
3040 TBBUTTON tbb;
3041 HRESULT hr;
3042 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3044 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3045 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3046 This->cctrl_def_height, &ctrl);
3047 if(SUCCEEDED(hr))
3049 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3050 ctrl->type = IDLG_CCTRL_MENU;
3052 /* Add the actual button with a popup menu. */
3053 tbb.iBitmap = I_IMAGENONE;
3054 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3055 tbb.iString = (DWORD_PTR)pszLabel;
3056 tbb.fsState = TBSTATE_ENABLED;
3057 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3058 tbb.idCommand = 1;
3060 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3063 return hr;
3066 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3067 DWORD dwIDCtl,
3068 LPCWSTR pszLabel)
3070 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3071 customctrl *ctrl;
3072 HRESULT hr;
3073 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3075 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3076 This->cctrl_def_height, &ctrl);
3077 if(SUCCEEDED(hr))
3078 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3080 return hr;
3083 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3084 DWORD dwIDCtl)
3086 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3087 customctrl *ctrl;
3088 HRESULT hr;
3089 TRACE("%p (%d)\n", This, dwIDCtl);
3091 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3092 This->cctrl_def_height, &ctrl);
3093 if(SUCCEEDED(hr))
3094 ctrl->type = IDLG_CCTRL_COMBOBOX;
3096 return hr;
3099 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3100 DWORD dwIDCtl)
3102 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3103 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3104 return E_NOTIMPL;
3107 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3108 DWORD dwIDCtl,
3109 LPCWSTR pszLabel,
3110 BOOL bChecked)
3112 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3113 customctrl *ctrl;
3114 HRESULT hr;
3115 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3117 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX, 0,
3118 This->cctrl_def_height, &ctrl);
3119 if(SUCCEEDED(hr))
3121 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3122 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3125 return hr;
3128 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3129 DWORD dwIDCtl,
3130 LPCWSTR pszText)
3132 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3133 customctrl *ctrl;
3134 HRESULT hr;
3135 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3137 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3138 This->cctrl_def_height, &ctrl);
3139 if(SUCCEEDED(hr))
3140 ctrl->type = IDLG_CCTRL_EDITBOX;
3142 return hr;
3145 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3146 DWORD dwIDCtl)
3148 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3149 customctrl *ctrl;
3150 HRESULT hr;
3151 TRACE("%p (%d)\n", This, dwIDCtl);
3153 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3154 GetSystemMetrics(SM_CYEDGE), &ctrl);
3155 if(SUCCEEDED(hr))
3156 ctrl->type = IDLG_CCTRL_SEPARATOR;
3158 return hr;
3161 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3162 DWORD dwIDCtl,
3163 LPCWSTR pszText)
3165 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3166 customctrl *ctrl;
3167 HRESULT hr;
3168 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3170 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3171 This->cctrl_def_height, &ctrl);
3172 if(SUCCEEDED(hr))
3173 ctrl->type = IDLG_CCTRL_TEXT;
3175 return hr;
3178 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3179 DWORD dwIDCtl,
3180 LPCWSTR pszLabel)
3182 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3183 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3184 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3186 if(!ctrl) return E_INVALIDARG;
3188 switch(ctrl->type)
3190 case IDLG_CCTRL_MENU:
3191 case IDLG_CCTRL_PUSHBUTTON:
3192 case IDLG_CCTRL_CHECKBUTTON:
3193 case IDLG_CCTRL_TEXT:
3194 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3195 break;
3196 default:
3197 break;
3200 return S_OK;
3203 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3204 DWORD dwIDCtl,
3205 CDCONTROLSTATEF *pdwState)
3207 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3208 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3209 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3211 if(!ctrl) return E_NOTIMPL;
3213 *pdwState = ctrl->cdcstate;
3214 return S_OK;
3217 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3218 DWORD dwIDCtl,
3219 CDCONTROLSTATEF dwState)
3221 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3222 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3223 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3225 if(ctrl)
3227 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3229 if(dwState & CDCS_ENABLED)
3230 wndstyle &= ~(WS_DISABLED);
3231 else
3232 wndstyle |= WS_DISABLED;
3234 if(dwState & CDCS_VISIBLE)
3235 wndstyle |= WS_VISIBLE;
3236 else
3237 wndstyle &= ~(WS_VISIBLE);
3239 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3241 /* We save the state separately since at least one application
3242 * relies on being able to hide a control. */
3243 ctrl->cdcstate = dwState;
3246 return S_OK;
3249 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3250 DWORD dwIDCtl,
3251 WCHAR **ppszText)
3253 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3254 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3255 WCHAR len, *text;
3256 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
3258 if(!ctrl || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3259 return E_FAIL;
3261 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3262 if(!text) return E_FAIL;
3264 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3265 *ppszText = text;
3266 return S_OK;
3269 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
3270 DWORD dwIDCtl,
3271 LPCWSTR pszText)
3273 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3274 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3275 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
3277 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
3278 return E_FAIL;
3280 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
3281 return S_OK;
3284 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
3285 DWORD dwIDCtl,
3286 BOOL *pbChecked)
3288 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3289 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3290 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
3292 if(ctrl)
3293 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
3295 return S_OK;
3298 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
3299 DWORD dwIDCtl,
3300 BOOL bChecked)
3302 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3303 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3304 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
3306 if(ctrl)
3307 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
3309 return S_OK;
3312 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
3314 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
3315 UINT i;
3316 if(!count || (count == CB_ERR))
3317 return -1;
3319 for(i = 0; i < count; i++)
3320 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3321 return i;
3323 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
3324 return -1;
3327 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
3328 DWORD dwIDCtl,
3329 DWORD dwIDItem,
3330 LPCWSTR pszLabel)
3332 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3333 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3334 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3336 if(!ctrl) return E_FAIL;
3338 switch(ctrl->type)
3340 case IDLG_CCTRL_COMBOBOX:
3342 UINT index;
3344 if(get_combobox_index_from_id(ctrl->hwnd, dwIDItem) != -1)
3345 return E_INVALIDARG;
3347 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
3348 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
3350 return S_OK;
3352 case IDLG_CCTRL_MENU:
3354 TBBUTTON tbb;
3355 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3357 if(GetMenuState((HMENU)tbb.dwData, dwIDItem, MF_BYCOMMAND) != -1)
3358 return E_INVALIDARG;
3360 AppendMenuW((HMENU)tbb.dwData, MF_STRING, dwIDItem, pszLabel);
3361 return S_OK;
3363 default:
3364 break;
3367 return E_NOINTERFACE; /* win7 */
3370 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
3371 DWORD dwIDCtl,
3372 DWORD dwIDItem)
3374 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3375 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3376 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3378 if(!ctrl) return E_FAIL;
3380 switch(ctrl->type)
3382 case IDLG_CCTRL_COMBOBOX:
3384 UINT i, count = SendMessageW(ctrl->hwnd, CB_GETCOUNT, 0, 0);
3385 if(!count || (count == CB_ERR))
3386 return E_FAIL;
3388 for(i = 0; i < count; i++)
3389 if(SendMessageW(ctrl->hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
3391 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, i, 0) == CB_ERR)
3392 return E_FAIL;
3393 return S_OK;
3396 return E_UNEXPECTED;
3398 case IDLG_CCTRL_MENU:
3400 TBBUTTON tbb;
3401 HMENU hmenu;
3402 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
3403 hmenu = (HMENU)tbb.dwData;
3405 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
3406 return E_UNEXPECTED;
3408 return S_OK;
3410 default:
3411 break;
3414 return E_FAIL;
3417 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
3418 DWORD dwIDCtl)
3420 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3421 TRACE("%p (%d)\n", This, dwIDCtl);
3423 /* Not implemented by native */
3424 return E_NOTIMPL;
3427 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
3428 DWORD dwIDCtl,
3429 DWORD dwIDItem,
3430 CDCONTROLSTATEF *pdwState)
3432 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3433 FIXME("stub - %p\n", This);
3434 return E_NOTIMPL;
3437 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
3438 DWORD dwIDCtl,
3439 DWORD dwIDItem,
3440 CDCONTROLSTATEF dwState)
3442 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3443 FIXME("stub - %p\n", This);
3444 return E_NOTIMPL;
3447 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
3448 DWORD dwIDCtl,
3449 DWORD *pdwIDItem)
3451 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3452 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3453 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
3455 if(!ctrl) return E_FAIL;
3457 switch(ctrl->type)
3459 case IDLG_CCTRL_COMBOBOX:
3461 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
3462 if(index == CB_ERR)
3463 return E_FAIL;
3465 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
3466 return S_OK;
3468 default:
3469 FIXME("Unsupported control type %d\n", ctrl->type);
3472 return E_NOTIMPL;
3475 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
3476 DWORD dwIDCtl,
3477 DWORD dwIDItem)
3479 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3480 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3481 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
3483 if(!ctrl) return E_INVALIDARG;
3485 switch(ctrl->type)
3487 case IDLG_CCTRL_COMBOBOX:
3489 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
3491 if(index == -1)
3492 return E_INVALIDARG;
3494 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
3495 return E_FAIL;
3497 return S_OK;
3499 default:
3500 FIXME("Unsupported control type %d\n", ctrl->type);
3503 return E_INVALIDARG;
3506 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
3507 DWORD dwIDCtl,
3508 LPCWSTR pszLabel)
3510 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3511 FIXME("stub - %p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
3512 return E_NOTIMPL;
3515 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
3517 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3518 FIXME("stub - %p\n", This);
3519 return E_NOTIMPL;
3522 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
3523 DWORD dwIDCtl)
3525 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3526 FIXME("stub - %p (%d)\n", This, dwIDCtl);
3527 return E_NOTIMPL;
3530 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
3531 DWORD dwIDCtl,
3532 DWORD dwIDItem,
3533 LPCWSTR pszLabel)
3535 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3536 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
3537 return E_NOTIMPL;
3540 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
3541 IFileDialogCustomize_fnQueryInterface,
3542 IFileDialogCustomize_fnAddRef,
3543 IFileDialogCustomize_fnRelease,
3544 IFileDialogCustomize_fnEnableOpenDropDown,
3545 IFileDialogCustomize_fnAddMenu,
3546 IFileDialogCustomize_fnAddPushButton,
3547 IFileDialogCustomize_fnAddComboBox,
3548 IFileDialogCustomize_fnAddRadioButtonList,
3549 IFileDialogCustomize_fnAddCheckButton,
3550 IFileDialogCustomize_fnAddEditBox,
3551 IFileDialogCustomize_fnAddSeparator,
3552 IFileDialogCustomize_fnAddText,
3553 IFileDialogCustomize_fnSetControlLabel,
3554 IFileDialogCustomize_fnGetControlState,
3555 IFileDialogCustomize_fnSetControlState,
3556 IFileDialogCustomize_fnGetEditBoxText,
3557 IFileDialogCustomize_fnSetEditBoxText,
3558 IFileDialogCustomize_fnGetCheckButtonState,
3559 IFileDialogCustomize_fnSetCheckButtonState,
3560 IFileDialogCustomize_fnAddControlItem,
3561 IFileDialogCustomize_fnRemoveControlItem,
3562 IFileDialogCustomize_fnRemoveAllControlItems,
3563 IFileDialogCustomize_fnGetControlItemState,
3564 IFileDialogCustomize_fnSetControlItemState,
3565 IFileDialogCustomize_fnGetSelectedControlItem,
3566 IFileDialogCustomize_fnSetSelectedControlItem,
3567 IFileDialogCustomize_fnStartVisualGroup,
3568 IFileDialogCustomize_fnEndVisualGroup,
3569 IFileDialogCustomize_fnMakeProminent,
3570 IFileDialogCustomize_fnSetControlItemText
3573 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
3575 FileDialogImpl *fdimpl;
3576 HRESULT hr;
3577 IShellFolder *psf;
3578 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
3580 if(!ppv)
3581 return E_POINTER;
3582 if(pUnkOuter)
3583 return CLASS_E_NOAGGREGATION;
3585 fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
3586 if(!fdimpl)
3587 return E_OUTOFMEMORY;
3589 fdimpl->ref = 1;
3590 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
3591 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
3592 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
3593 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
3594 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
3595 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
3597 if(type == ITEMDLG_TYPE_OPEN)
3599 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
3600 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
3601 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
3602 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
3604 else
3606 WCHAR buf[16];
3607 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
3608 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
3609 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
3611 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
3612 fdimpl->custom_title = StrDupW(buf);
3613 fdimpl->custom_okbutton = StrDupW(buf);
3616 fdimpl->filterspecs = NULL;
3617 fdimpl->filterspec_count = 0;
3618 fdimpl->filetypeindex = 0;
3620 fdimpl->psia_selection = fdimpl->psia_results = NULL;
3621 fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
3623 list_init(&fdimpl->events_clients);
3624 fdimpl->events_next_cookie = 0;
3626 fdimpl->dlg_hwnd = NULL;
3627 fdimpl->peb = NULL;
3629 fdimpl->set_filename = NULL;
3630 fdimpl->default_ext = NULL;
3631 fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL;
3633 fdimpl->client_guid = GUID_NULL;
3635 /* FIXME: The default folder setting should be restored for the
3636 * application if it was previously set. */
3637 SHGetDesktopFolder(&psf);
3638 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
3639 IShellFolder_Release(psf);
3641 hr = init_custom_controls(fdimpl);
3642 if(FAILED(hr))
3644 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
3645 IUnknown_Release((IUnknown*)fdimpl);
3646 return E_FAIL;
3649 hr = IUnknown_QueryInterface((IUnknown*)fdimpl, riid, ppv);
3650 IUnknown_Release((IUnknown*)fdimpl);
3651 return hr;
3654 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3656 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
3659 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
3661 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);