mfplat/sample: Refactor sample_CopyToBuffer().
[wine.git] / dlls / comdlg32 / itemdlg.c
blob1a598046dff771f9d7bc4249883de8e67e5d2cc2
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 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "wingdi.h"
28 #include "winreg.h"
29 #include "shlwapi.h"
31 #include "commdlg.h"
32 #include "cdlg.h"
33 #include "filedlgbrowser.h"
35 #include "wine/debug.h"
36 #include "wine/list.h"
38 #define IDC_NAV_TOOLBAR 200
39 #define IDC_NAVBACK 201
40 #define IDC_NAVFORWARD 202
41 #define IDC_NAVUP 203
43 #include <initguid.h>
44 /* This seems to be another version of IID_IFileDialogCustomize. If
45 * there is any difference I have yet to find it. */
46 DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F);
48 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
50 enum ITEMDLG_TYPE {
51 ITEMDLG_TYPE_OPEN,
52 ITEMDLG_TYPE_SAVE
55 enum ITEMDLG_CCTRL_TYPE {
56 IDLG_CCTRL_MENU,
57 IDLG_CCTRL_PUSHBUTTON,
58 IDLG_CCTRL_COMBOBOX,
59 IDLG_CCTRL_RADIOBUTTONLIST,
60 IDLG_CCTRL_CHECKBUTTON,
61 IDLG_CCTRL_EDITBOX,
62 IDLG_CCTRL_SEPARATOR,
63 IDLG_CCTRL_TEXT,
64 IDLG_CCTRL_OPENDROPDOWN,
65 IDLG_CCTRL_VISUALGROUP
68 typedef struct cctrl_item {
69 DWORD id, parent_id;
70 LPWSTR label;
71 CDCONTROLSTATEF cdcstate;
72 HWND hwnd;
73 struct list entry;
74 } cctrl_item;
76 typedef struct {
77 HWND hwnd, wrapper_hwnd;
78 UINT id, dlgid;
79 enum ITEMDLG_CCTRL_TYPE type;
80 CDCONTROLSTATEF cdcstate;
81 struct list entry;
83 struct list sub_cctrls;
84 struct list sub_cctrls_entry;
85 struct list sub_items;
86 } customctrl;
88 typedef struct {
89 struct list entry;
90 IFileDialogEvents *pfde;
91 DWORD cookie;
92 } events_client;
94 typedef struct FileDialogImpl {
95 IFileDialog2 IFileDialog2_iface;
96 union {
97 IFileOpenDialog IFileOpenDialog_iface;
98 IFileSaveDialog IFileSaveDialog_iface;
99 } u;
100 enum ITEMDLG_TYPE dlg_type;
101 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
102 IServiceProvider IServiceProvider_iface;
103 ICommDlgBrowser3 ICommDlgBrowser3_iface;
104 IOleWindow IOleWindow_iface;
105 IFileDialogCustomize IFileDialogCustomize_iface;
106 LONG ref;
108 FILEOPENDIALOGOPTIONS options;
109 COMDLG_FILTERSPEC *filterspecs;
110 UINT filterspec_count;
111 UINT filetypeindex;
113 struct list events_clients;
114 DWORD events_next_cookie;
116 IShellItemArray *psia_selection;
117 IShellItemArray *psia_results;
118 IShellItem *psi_defaultfolder;
119 IShellItem *psi_setfolder;
120 IShellItem *psi_folder;
122 HWND dlg_hwnd;
123 IExplorerBrowser *peb;
124 DWORD ebevents_cookie;
126 LPWSTR set_filename;
127 LPWSTR default_ext;
128 LPWSTR custom_title;
129 LPWSTR custom_okbutton;
130 LPWSTR custom_cancelbutton;
131 LPWSTR custom_filenamelabel;
133 UINT cctrl_width, cctrl_def_height, cctrls_cols;
134 UINT cctrl_indent, dpi_x, dpi_y;
135 HWND cctrls_hwnd;
136 struct list cctrls;
137 UINT_PTR cctrl_next_dlgid;
138 customctrl *cctrl_active_vg;
140 HMENU hmenu_opendropdown;
141 customctrl cctrl_opendropdown;
142 HFONT hfont_opendropdown;
143 BOOL opendropdown_has_selection;
144 DWORD opendropdown_selection;
146 GUID client_guid;
148 HANDLE user_actctx;
149 } FileDialogImpl;
151 /**************************************************************************
152 * Event wrappers.
154 static HRESULT events_OnFileOk(FileDialogImpl *This)
156 ULONG_PTR ctx_cookie = 0;
157 events_client *cursor;
158 HRESULT hr = S_OK;
159 TRACE("%p\n", This);
161 if (This->user_actctx != INVALID_HANDLE_VALUE)
162 ActivateActCtx(This->user_actctx, &ctx_cookie);
164 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
166 TRACE("Notifying %p\n", cursor);
167 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
168 if(FAILED(hr) && hr != E_NOTIMPL)
169 break;
172 if (This->user_actctx != INVALID_HANDLE_VALUE)
173 DeactivateActCtx(0, ctx_cookie);
175 if(hr == E_NOTIMPL)
176 hr = S_OK;
178 return hr;
181 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
183 ULONG_PTR ctx_cookie = 0;
184 events_client *cursor;
185 HRESULT hr = S_OK;
186 TRACE("%p (%p)\n", This, folder);
188 if (This->user_actctx != INVALID_HANDLE_VALUE)
189 ActivateActCtx(This->user_actctx, &ctx_cookie);
191 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
193 TRACE("Notifying %p\n", cursor);
194 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
195 if(FAILED(hr) && hr != E_NOTIMPL)
196 break;
199 if (This->user_actctx != INVALID_HANDLE_VALUE)
200 DeactivateActCtx(0, ctx_cookie);
202 if(hr == E_NOTIMPL)
203 hr = S_OK;
205 return hr;
208 static void events_OnFolderChange(FileDialogImpl *This)
210 ULONG_PTR ctx_cookie = 0;
211 events_client *cursor;
212 TRACE("%p\n", This);
214 if (This->user_actctx != INVALID_HANDLE_VALUE)
215 ActivateActCtx(This->user_actctx, &ctx_cookie);
217 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
219 TRACE("Notifying %p\n", cursor);
220 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
223 if (This->user_actctx != INVALID_HANDLE_VALUE)
224 DeactivateActCtx(0, ctx_cookie);
227 static void events_OnSelectionChange(FileDialogImpl *This)
229 ULONG_PTR ctx_cookie = 0;
230 events_client *cursor;
231 TRACE("%p\n", This);
233 if (This->user_actctx != INVALID_HANDLE_VALUE)
234 ActivateActCtx(This->user_actctx, &ctx_cookie);
236 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
238 TRACE("Notifying %p\n", cursor);
239 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
242 if (This->user_actctx != INVALID_HANDLE_VALUE)
243 DeactivateActCtx(0, ctx_cookie);
246 static void events_OnTypeChange(FileDialogImpl *This)
248 ULONG_PTR ctx_cookie = 0;
249 events_client *cursor;
250 TRACE("%p\n", This);
252 if (This->user_actctx != INVALID_HANDLE_VALUE)
253 ActivateActCtx(This->user_actctx, &ctx_cookie);
255 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
257 TRACE("Notifying %p\n", cursor);
258 IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
261 if (This->user_actctx != INVALID_HANDLE_VALUE)
262 DeactivateActCtx(0, ctx_cookie);
265 static HRESULT events_OnOverwrite(FileDialogImpl *This, IShellItem *shellitem)
267 ULONG_PTR ctx_cookie = 0;
268 events_client *cursor;
269 HRESULT hr = S_OK;
270 FDE_OVERWRITE_RESPONSE response = FDEOR_DEFAULT;
271 TRACE("%p %p\n", This, shellitem);
273 if (This->user_actctx != INVALID_HANDLE_VALUE)
274 ActivateActCtx(This->user_actctx, &ctx_cookie);
276 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
278 TRACE("Notifying %p\n", cursor);
279 hr = IFileDialogEvents_OnOverwrite(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, shellitem, &response);
280 TRACE("<-- hr=%lx response=%u\n", hr, response);
281 if(FAILED(hr) && hr != E_NOTIMPL)
282 break;
285 if (This->user_actctx != INVALID_HANDLE_VALUE)
286 DeactivateActCtx(0, ctx_cookie);
288 if(hr == E_NOTIMPL)
289 hr = S_OK;
291 if(SUCCEEDED(hr))
293 if (response == FDEOR_DEFAULT)
295 WCHAR buf[100];
296 int answer;
298 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, buf, 100);
299 answer = MessageBoxW(This->dlg_hwnd, buf, This->custom_title,
300 MB_YESNO | MB_ICONEXCLAMATION);
301 if (answer == IDNO || answer == IDCANCEL)
303 hr = E_FAIL;
306 else if (response == FDEOR_REFUSE)
307 hr = E_FAIL;
310 return hr;
313 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
315 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
318 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
320 ULONG_PTR ctx_cookie = 0;
321 events_client *cursor;
322 TRACE("%p\n", This);
324 if (This->user_actctx != INVALID_HANDLE_VALUE)
325 ActivateActCtx(This->user_actctx, &ctx_cookie);
327 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
329 IFileDialogControlEvents *pfdce;
330 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
332 TRACE("Notifying %p\n", cursor);
333 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
334 IFileDialogControlEvents_Release(pfdce);
338 if (This->user_actctx != INVALID_HANDLE_VALUE)
339 DeactivateActCtx(0, ctx_cookie);
341 return S_OK;
344 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
346 ULONG_PTR ctx_cookie = 0;
347 events_client *cursor;
348 TRACE("%p %li %li\n", This, ctl_id, item_id);
350 if (This->user_actctx != INVALID_HANDLE_VALUE)
351 ActivateActCtx(This->user_actctx, &ctx_cookie);
353 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
355 IFileDialogControlEvents *pfdce;
356 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
358 TRACE("Notifying %p\n", cursor);
359 IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
360 IFileDialogControlEvents_Release(pfdce);
364 if (This->user_actctx != INVALID_HANDLE_VALUE)
365 DeactivateActCtx(0, ctx_cookie);
367 return S_OK;
370 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
372 ULONG_PTR ctx_cookie = 0;
373 events_client *cursor;
374 TRACE("%p\n", This);
376 if (This->user_actctx != INVALID_HANDLE_VALUE)
377 ActivateActCtx(This->user_actctx, &ctx_cookie);
379 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
381 IFileDialogControlEvents *pfdce;
382 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
384 TRACE("Notifying %p\n", cursor);
385 IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
386 IFileDialogControlEvents_Release(pfdce);
390 if (This->user_actctx != INVALID_HANDLE_VALUE)
391 DeactivateActCtx(0, ctx_cookie);
393 return S_OK;
396 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
397 DWORD ctl_id)
399 ULONG_PTR ctx_cookie = 0;
400 events_client *cursor;
401 TRACE("%p\n", This);
403 if (This->user_actctx != INVALID_HANDLE_VALUE)
404 ActivateActCtx(This->user_actctx, &ctx_cookie);
406 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
408 IFileDialogControlEvents *pfdce;
409 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
411 TRACE("Notifying %p\n", cursor);
412 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
413 IFileDialogControlEvents_Release(pfdce);
417 if (This->user_actctx != INVALID_HANDLE_VALUE)
418 DeactivateActCtx(0, ctx_cookie);
420 return S_OK;
423 /**************************************************************************
424 * Helper functions.
426 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
428 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
429 UINT len;
431 if(!hwnd_edit)
433 if(This->set_filename)
435 len = lstrlenW(This->set_filename);
436 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
437 lstrcpyW(*str, This->set_filename);
438 return len;
440 return 0;
443 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
444 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
445 if(!*str)
446 return 0;
448 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
449 return len;
452 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
454 if(This->set_filename)
455 LocalFree(This->set_filename);
457 This->set_filename = str ? StrDupW(str) : NULL;
459 return SetDlgItemTextW(This->dlg_hwnd, IDC_FILENAME, This->set_filename);
462 static void fill_filename_from_selection(FileDialogImpl *This)
464 IShellItem *psi;
465 LPWSTR *names;
466 HRESULT hr;
467 DWORD item_count;
468 UINT valid_count;
469 UINT len_total, i;
471 if(!This->psia_selection)
472 return;
474 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
475 if(FAILED(hr) || !item_count)
476 return;
478 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
480 /* Get names of the selected items */
481 valid_count = 0; len_total = 0;
482 for(i = 0; i < item_count; i++)
484 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
485 if(SUCCEEDED(hr))
487 DWORD attr;
489 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
490 if(SUCCEEDED(hr) &&
491 (( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
492 (!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
493 continue;
495 hr = IShellItem_GetDisplayName(psi, (This->options & FOS_PICKFOLDERS) ? SIGDN_FILESYSPATH : SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
496 if(SUCCEEDED(hr))
498 len_total += lstrlenW(names[valid_count]) + 3;
499 valid_count++;
501 IShellItem_Release(psi);
505 if(valid_count == 1)
507 set_file_name(This, names[0]);
508 CoTaskMemFree(names[0]);
510 else if(valid_count > 1)
512 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
513 LPWSTR cur_point = string;
515 for(i = 0; i < valid_count; i++)
517 LPWSTR file = names[i];
518 *cur_point++ = '\"';
519 lstrcpyW(cur_point, file);
520 cur_point += lstrlenW(file);
521 *cur_point++ = '\"';
522 *cur_point++ = ' ';
523 CoTaskMemFree(file);
525 *(cur_point-1) = '\0';
527 set_file_name(This, string);
528 HeapFree(GetProcessHeap(), 0, string);
531 HeapFree(GetProcessHeap(), 0, names);
532 return;
535 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
537 WCHAR *endpos, *ext;
539 lstrcpyW(buf, spec);
540 if( (endpos = StrChrW(buf, ';')) )
541 *endpos = '\0';
543 ext = PathFindExtensionW(buf);
544 if(StrChrW(ext, '*'))
545 return NULL;
547 return ext;
550 static BOOL shell_item_exists(IShellItem* shellitem)
552 LPWSTR filename;
553 HRESULT hr;
554 BOOL result;
556 hr = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &filename);
557 if (SUCCEEDED(hr))
559 /* FIXME: Implement SFGAO_VALIDATE in Wine and use it instead. */
560 result = (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES);
561 CoTaskMemFree(filename);
563 else
565 SFGAOF attributes;
566 result = SUCCEEDED(IShellItem_GetAttributes(shellitem, SFGAO_VALIDATE, &attributes));
569 return result;
572 static HRESULT on_default_action(FileDialogImpl *This)
574 IShellFolder *psf_parent, *psf_desktop;
575 LPITEMIDLIST *pidla;
576 LPITEMIDLIST current_folder;
577 LPWSTR fn_iter, files = NULL, tmp_files;
578 UINT file_count = 0, len, i;
579 int open_action;
580 HRESULT hr, ret = E_FAIL;
582 len = get_file_name(This, &tmp_files);
583 if(len)
585 UINT size_used;
586 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
587 CoTaskMemFree(tmp_files);
589 if(!file_count) return E_FAIL;
591 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
592 if(FAILED(hr))
594 ERR("Failed to get pidl for current directory.\n");
595 HeapFree(GetProcessHeap(), 0, files);
596 return hr;
599 TRACE("Acting on %d file(s).\n", file_count);
601 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
602 open_action = ONOPEN_OPEN;
603 fn_iter = files;
605 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
607 WCHAR canon_filename[MAX_PATH];
608 psf_parent = NULL;
610 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
612 if( (This->options & FOS_NOVALIDATE) &&
613 !(This->options & FOS_FILEMUSTEXIST) )
614 open_action = ONOPEN_OPEN;
615 else
616 open_action = ONOPEN_BROWSE;
618 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
619 This->options & ~FOS_FILEMUSTEXIST,
620 (This->dlg_type == ITEMDLG_TYPE_SAVE),
621 open_action);
623 /* Add the proper extension */
624 if(open_action == ONOPEN_OPEN)
626 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
628 WCHAR extbuf[MAX_PATH], *newext = NULL;
630 if(This->filterspec_count)
632 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
634 else if(This->default_ext)
636 lstrcpyW(extbuf, L".");
637 lstrcatW(extbuf, This->default_ext);
638 newext = extbuf;
641 if(newext)
643 WCHAR *ext = PathFindExtensionW(canon_filename);
644 if(lstrcmpW(ext, newext))
645 lstrcatW(canon_filename, newext);
648 else
650 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
651 !PathFileExistsW(canon_filename))
653 if(This->default_ext)
655 lstrcatW(canon_filename, L".");
656 lstrcatW(canon_filename, This->default_ext);
658 if(!PathFileExistsW(canon_filename))
660 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
661 open_action = ONOPEN_BROWSE;
664 else
666 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
667 open_action = ONOPEN_BROWSE;
673 pidla[i] = SHSimpleIDListFromPath(canon_filename);
675 if(psf_parent && !(open_action == ONOPEN_BROWSE))
676 IShellFolder_Release(psf_parent);
678 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
681 HeapFree(GetProcessHeap(), 0, files);
682 ILFree(current_folder);
684 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
685 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
687 switch(open_action)
689 case ONOPEN_SEARCH:
690 FIXME("Filtering not implemented.\n");
691 break;
693 case ONOPEN_BROWSE:
694 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
695 if(FAILED(hr))
696 ERR("Failed to browse to directory: %08lx\n", hr);
698 IShellFolder_Release(psf_parent);
699 break;
701 case ONOPEN_OPEN:
702 hr = SHGetDesktopFolder(&psf_desktop);
703 if(SUCCEEDED(hr))
705 if(This->psia_results)
707 IShellItemArray_Release(This->psia_results);
708 This->psia_results = NULL;
711 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
712 &This->psia_results);
714 IShellFolder_Release(psf_desktop);
716 if(FAILED(hr))
717 break;
719 if(This->options & FOS_PICKFOLDERS)
721 SFGAOF attributes;
722 hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
723 if(hr != S_OK)
725 WCHAR buf[64];
726 LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, ARRAY_SIZE(buf));
728 MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
730 IShellItemArray_Release(This->psia_results);
731 This->psia_results = NULL;
732 break;
736 if((This->options & FOS_OVERWRITEPROMPT) && This->dlg_type == ITEMDLG_TYPE_SAVE)
738 IShellItem *shellitem;
740 for (i=0; SUCCEEDED(hr) && i<file_count; i++)
742 hr = IShellItemArray_GetItemAt(This->psia_results, i, &shellitem);
743 if (SUCCEEDED(hr))
745 if (shell_item_exists(shellitem))
746 hr = events_OnOverwrite(This, shellitem);
748 IShellItem_Release(shellitem);
752 if (FAILED(hr))
753 break;
756 if(events_OnFileOk(This) == S_OK)
757 ret = S_OK;
759 break;
761 default:
762 ERR("Failed.\n");
763 break;
766 /* Clean up */
767 for(i = 0; i < file_count; i++)
768 ILFree(pidla[i]);
769 HeapFree(GetProcessHeap(), 0, pidla);
771 /* Success closes the dialog */
772 return ret;
775 static void show_opendropdown(FileDialogImpl *This)
777 HWND open_hwnd;
778 RECT open_rc;
779 MSG msg;
781 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
783 GetWindowRect(open_hwnd, &open_rc);
785 if (TrackPopupMenu(This->hmenu_opendropdown, 0, open_rc.left, open_rc.bottom, 0, This->dlg_hwnd, NULL) &&
786 PeekMessageW(&msg, This->dlg_hwnd, WM_MENUCOMMAND, WM_MENUCOMMAND, PM_REMOVE))
788 MENUITEMINFOW mii;
790 This->opendropdown_has_selection = TRUE;
792 mii.cbSize = sizeof(mii);
793 mii.fMask = MIIM_ID;
794 GetMenuItemInfoW((HMENU)msg.lParam, msg.wParam, TRUE, &mii);
795 This->opendropdown_selection = mii.wID;
797 if(SUCCEEDED(on_default_action(This)))
798 EndDialog(This->dlg_hwnd, S_OK);
799 else
800 This->opendropdown_has_selection = FALSE;
804 /**************************************************************************
805 * Control item functions.
808 static void item_free(cctrl_item *item)
810 DestroyWindow(item->hwnd);
811 HeapFree(GetProcessHeap(), 0, item->label);
812 HeapFree(GetProcessHeap(), 0, item);
815 static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF visible_flags, DWORD* position)
817 DWORD dummy;
818 cctrl_item* item;
820 if (!position) position = &dummy;
822 *position = 0;
824 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
826 if (item->id == itemid)
827 return item;
829 if ((item->cdcstate & visible_flags) == visible_flags)
830 (*position)++;
833 return NULL;
836 static cctrl_item* get_first_item(customctrl* parent)
838 cctrl_item* item;
840 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
842 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
843 return item;
846 return NULL;
849 static HRESULT add_item(customctrl* parent, DWORD itemid, LPCWSTR label, cctrl_item** result)
851 cctrl_item* item;
852 LPWSTR label_copy;
854 if (get_item(parent, itemid, 0, NULL))
855 return E_INVALIDARG;
857 item = HeapAlloc(GetProcessHeap(), 0, sizeof(*item));
858 label_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(label)+1)*sizeof(WCHAR));
860 if (!item || !label_copy)
862 HeapFree(GetProcessHeap(), 0, item);
863 HeapFree(GetProcessHeap(), 0, label_copy);
864 return E_OUTOFMEMORY;
867 item->id = itemid;
868 item->parent_id = parent->id;
869 lstrcpyW(label_copy, label);
870 item->label = label_copy;
871 item->cdcstate = CDCS_VISIBLE|CDCS_ENABLED;
872 item->hwnd = NULL;
873 list_add_tail(&parent->sub_items, &item->entry);
875 *result = item;
877 return S_OK;
880 /**************************************************************************
881 * Control functions.
883 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
885 customctrl *ctrl, *sub_ctrl;
887 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
889 if(ctrl->dlgid == dlgid)
890 return ctrl;
892 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
893 if(sub_ctrl->dlgid == dlgid)
894 return sub_ctrl;
897 ERR("Failed to find control with dialog id %ld\n", dlgid);
898 return NULL;
901 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
903 customctrl *ctrl, *sub_ctrl;
905 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
907 if(ctrl->id == ctlid)
908 return ctrl;
910 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
911 if(sub_ctrl->id == ctlid)
912 return sub_ctrl;
915 if (This->hmenu_opendropdown && This->cctrl_opendropdown.id == ctlid)
916 return &This->cctrl_opendropdown;
918 TRACE("No existing control with control id %ld\n", ctlid);
919 return NULL;
922 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
924 LPWSTR text;
925 UINT len, final_width;
926 UINT lines, final_height;
927 SIZE size;
928 RECT rc;
929 HDC hdc;
930 WCHAR *c;
931 HFONT font;
933 TRACE("\n");
935 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
936 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
937 if(!text) return;
938 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
940 hdc = GetDC(hctrl);
941 font = (HFONT)SendMessageW(hctrl, WM_GETFONT, 0, 0);
942 font = SelectObject(hdc, font);
943 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
944 SelectObject(hdc, font);
945 ReleaseDC(hctrl, hdc);
947 if(len && multiline)
949 /* FIXME: line-wrap */
950 for(lines = 1, c = text; *c != '\0'; c++)
951 if(*c == '\n') lines++;
953 final_height = size.cy*lines + 2*4;
955 else
957 GetWindowRect(hctrl, &rc);
958 final_height = rc.bottom - rc.top;
961 final_width = min(max(size.cx, min_width) + 4, max_width);
962 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
963 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
965 HeapFree(GetProcessHeap(), 0, text);
968 static UINT ctrl_get_height(customctrl *ctrl) {
969 RECT rc;
970 GetWindowRect(ctrl->wrapper_hwnd, &rc);
971 return rc.bottom - rc.top;
974 static void ctrl_free(customctrl *ctrl)
976 customctrl *sub_cur1, *sub_cur2;
977 cctrl_item *item_cur1, *item_cur2;
979 TRACE("Freeing control %p\n", ctrl);
980 if(ctrl->type == IDLG_CCTRL_MENU)
982 TBBUTTON tbb;
983 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
984 DestroyMenu((HMENU)tbb.dwData);
987 LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
989 list_remove(&sub_cur1->sub_cctrls_entry);
990 ctrl_free(sub_cur1);
993 LIST_FOR_EACH_ENTRY_SAFE(item_cur1, item_cur2, &ctrl->sub_items, cctrl_item, entry)
995 list_remove(&item_cur1->entry);
996 item_free(item_cur1);
999 DestroyWindow(ctrl->hwnd);
1000 HeapFree(GetProcessHeap(), 0, ctrl);
1003 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
1005 RECT rc;
1006 UINT total_height;
1007 UINT max_width, size;
1008 customctrl *sub_ctrl;
1010 switch(ctrl->type)
1012 case IDLG_CCTRL_PUSHBUTTON:
1013 case IDLG_CCTRL_COMBOBOX:
1014 case IDLG_CCTRL_CHECKBUTTON:
1015 case IDLG_CCTRL_TEXT:
1016 size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1017 ctrl_resize(ctrl->hwnd, size, size, TRUE);
1018 GetWindowRect(ctrl->hwnd, &rc);
1019 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
1020 SWP_NOZORDER|SWP_NOMOVE);
1021 break;
1022 case IDLG_CCTRL_VISUALGROUP:
1023 total_height = 0;
1024 ctrl_resize(ctrl->hwnd, 0, This->cctrl_indent, TRUE);
1026 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1028 customctrl_resize(This, sub_ctrl);
1029 SetWindowPos(sub_ctrl->wrapper_hwnd, NULL, This->cctrl_indent, total_height, 0, 0,
1030 SWP_NOZORDER|SWP_NOSIZE);
1032 total_height += ctrl_get_height(sub_ctrl);
1035 /* The label should be right adjusted */
1037 UINT width, height;
1039 GetWindowRect(ctrl->hwnd, &rc);
1040 width = rc.right - rc.left;
1041 height = rc.bottom - rc.top;
1043 SetWindowPos(ctrl->hwnd, NULL, This->cctrl_indent - width, 0, width, height, SWP_NOZORDER);
1046 /* Resize the wrapper window to fit all the sub controls */
1047 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, This->cctrl_width + This->cctrl_indent, total_height,
1048 SWP_NOZORDER|SWP_NOMOVE);
1049 break;
1050 case IDLG_CCTRL_RADIOBUTTONLIST:
1052 cctrl_item* item;
1054 total_height = 0;
1055 max_width = 0;
1057 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1059 size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1060 ctrl_resize(item->hwnd, size, size, TRUE);
1061 SetWindowPos(item->hwnd, NULL, 0, total_height, 0, 0,
1062 SWP_NOZORDER|SWP_NOSIZE);
1064 GetWindowRect(item->hwnd, &rc);
1066 total_height += rc.bottom - rc.top;
1067 max_width = max(rc.right - rc.left, max_width);
1070 SetWindowPos(ctrl->hwnd, NULL, 0, 0, max_width, total_height,
1071 SWP_NOZORDER|SWP_NOMOVE);
1073 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, max_width, total_height,
1074 SWP_NOZORDER|SWP_NOMOVE);
1076 break;
1078 case IDLG_CCTRL_EDITBOX:
1079 case IDLG_CCTRL_SEPARATOR:
1080 case IDLG_CCTRL_MENU:
1081 case IDLG_CCTRL_OPENDROPDOWN:
1082 /* Nothing */
1083 break;
1087 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
1089 FileDialogImpl *This = crs->lpCreateParams;
1090 TRACE("%p\n", This);
1092 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1093 return TRUE;
1096 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1098 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1100 TRACE("%p, %Ix\n", This, wparam);
1102 if(ctrl)
1104 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
1106 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
1107 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
1109 else
1110 cctrl_event_OnButtonClicked(This, ctrl->id);
1113 return TRUE;
1116 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1118 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1119 TRACE("%p, %p (%Ix)\n", This, ctrl, wparam);
1121 if(ctrl)
1123 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
1124 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
1126 cctrl_event_OnItemSelected(This, ctrl->id, selid);
1128 return TRUE;
1131 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
1133 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
1134 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
1135 POINT pt = { 0, nmtb->rcButton.bottom };
1136 TBBUTTON tbb;
1137 UINT idcmd;
1139 TRACE("%p, %p (%Ix)\n", This, ctrl, lparam);
1141 if(ctrl)
1143 cctrl_event_OnControlActivating(This,ctrl->id);
1145 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1146 ClientToScreen(ctrl->hwnd, &pt);
1147 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
1148 if(idcmd)
1149 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
1152 return TBDDRET_DEFAULT;
1155 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1157 switch(HIWORD(wparam))
1159 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
1160 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
1163 return FALSE;
1166 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1168 NMHDR *nmhdr = (NMHDR*)lparam;
1170 switch(nmhdr->code)
1172 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
1175 return FALSE;
1178 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1180 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1181 customctrl *ctrl;
1182 HWND hwnd_child;
1183 RECT rc;
1185 switch(message)
1187 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
1188 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
1189 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
1190 case WM_SIZE:
1191 hwnd_child = GetPropW(hwnd, L"nfs_child");
1192 ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA);
1193 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
1195 GetClientRect(hwnd, &rc);
1196 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1198 return TRUE;
1201 return DefWindowProcW(hwnd, message, wparam, lparam);
1204 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
1205 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
1206 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
1208 HWND ns_hwnd, control_hwnd, parent_hwnd;
1209 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
1210 customctrl *ctrl;
1212 if(get_cctrl(This, id))
1213 return E_UNEXPECTED; /* Duplicate id */
1215 if(This->cctrl_active_vg)
1216 parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
1217 else
1218 parent_hwnd = This->cctrls_hwnd;
1220 ns_hwnd = CreateWindowExW(0, L"FloatNotifySink", NULL, wsflags,
1221 0, 0, This->cctrl_width, height, parent_hwnd,
1222 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
1223 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
1224 0, 0, This->cctrl_width, height, ns_hwnd,
1225 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
1227 if(!ns_hwnd || !control_hwnd)
1229 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
1230 DestroyWindow(ns_hwnd);
1231 DestroyWindow(control_hwnd);
1233 return E_FAIL;
1236 SetPropW(ns_hwnd, L"nfs_child", control_hwnd);
1238 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
1239 if(!ctrl)
1240 return E_OUTOFMEMORY;
1242 ctrl->hwnd = control_hwnd;
1243 ctrl->wrapper_hwnd = ns_hwnd;
1244 ctrl->id = id;
1245 ctrl->dlgid = This->cctrl_next_dlgid;
1246 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
1247 list_init(&ctrl->sub_cctrls);
1248 list_init(&ctrl->sub_items);
1250 if(This->cctrl_active_vg)
1251 list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
1252 else
1253 list_add_tail(&This->cctrls, &ctrl->entry);
1255 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl);
1257 if(ppctrl) *ppctrl = ctrl;
1259 This->cctrl_next_dlgid++;
1260 return S_OK;
1263 /**************************************************************************
1264 * Container functions.
1266 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
1268 UINT container_height;
1269 UINT column_width;
1270 UINT nr_of_cols;
1271 UINT max_control_height, total_height = 0;
1272 UINT cur_col_pos, cur_row_pos;
1273 customctrl *ctrl;
1274 BOOL fits_height;
1275 UINT cspacing = MulDiv(90, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Columns are spaced with 90px */
1276 UINT rspacing = MulDiv(4, This->dpi_y, USER_DEFAULT_SCREEN_DPI); /* Rows are spaced with 4 px. */
1278 /* Given the new width of the container, this function determines the
1279 * needed height of the container and places the controls according to
1280 * the new layout. Returns the new height.
1283 TRACE("%p\n", This);
1285 column_width = This->cctrl_width + cspacing;
1286 nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
1288 /* We don't need to do anything unless the number of visible columns has changed. */
1289 if(nr_of_cols == This->cctrls_cols)
1291 RECT rc;
1292 GetWindowRect(This->cctrls_hwnd, &rc);
1293 return rc.bottom - rc.top;
1296 This->cctrls_cols = nr_of_cols;
1298 /* Get the size of the tallest control, and the total size of
1299 * all the controls to figure out the number of slots we need.
1301 max_control_height = 0;
1302 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1304 if(ctrl->cdcstate & CDCS_VISIBLE)
1306 UINT control_height = ctrl_get_height(ctrl);
1307 max_control_height = max(max_control_height, control_height);
1309 total_height += control_height + rspacing;
1313 if(!total_height)
1314 return 0;
1316 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
1317 TRACE("Guess: container_height: %d\n",container_height);
1319 /* Incrementally increase container_height until all the controls
1320 * fit.
1322 do {
1323 UINT columns_needed = 1;
1324 cur_row_pos = 0;
1326 fits_height = TRUE;
1327 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1329 if(ctrl->cdcstate & CDCS_VISIBLE)
1331 UINT control_height = ctrl_get_height(ctrl);
1333 if(cur_row_pos + control_height > container_height)
1335 if(++columns_needed > nr_of_cols)
1337 container_height += 1;
1338 fits_height = FALSE;
1339 break;
1341 cur_row_pos = 0;
1344 cur_row_pos += control_height + rspacing;
1347 } while(!fits_height);
1349 TRACE("Final container height: %d\n", container_height);
1351 /* Move the controls to their final destination
1353 cur_col_pos = 0; cur_row_pos = 0;
1354 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1356 if(ctrl->cdcstate & CDCS_VISIBLE)
1358 RECT rc;
1359 UINT control_height, control_indent;
1360 GetWindowRect(ctrl->wrapper_hwnd, &rc);
1361 control_height = rc.bottom - rc.top;
1363 if(cur_row_pos + control_height > container_height)
1365 cur_row_pos = 0;
1366 cur_col_pos += This->cctrl_width + cspacing;
1370 if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
1371 control_indent = 0;
1372 else
1373 control_indent = This->cctrl_indent;
1375 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
1376 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1378 cur_row_pos += control_height + rspacing;
1382 /* Sanity check */
1383 if(cur_row_pos + This->cctrl_width > container_width)
1384 ERR("-- Failed to place controls properly.\n");
1386 return container_height;
1389 static void ctrl_set_font(customctrl *ctrl, HFONT font)
1391 customctrl *sub_ctrl;
1392 cctrl_item* item;
1394 SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1396 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1398 ctrl_set_font(sub_ctrl, font);
1401 if (ctrl->type == IDLG_CCTRL_RADIOBUTTONLIST)
1403 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1405 SendMessageW(item->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1410 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
1412 LONG wndstyle;
1414 if(parent)
1416 customctrl *ctrl;
1417 HFONT font;
1419 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1420 wndstyle &= ~(WS_POPUP);
1421 wndstyle |= WS_CHILD;
1422 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1424 SetParent(This->cctrls_hwnd, parent);
1425 ShowWindow(This->cctrls_hwnd, TRUE);
1427 /* Set the fonts to match the dialog font. */
1428 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
1429 if(!font)
1430 ERR("Failed to get font handle from dialog.\n");
1432 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1434 if(font) ctrl_set_font(ctrl, font);
1435 customctrl_resize(This, ctrl);
1438 else
1440 ShowWindow(This->cctrls_hwnd, FALSE);
1442 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1443 wndstyle &= ~(WS_CHILD);
1444 wndstyle |= WS_POPUP;
1445 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1447 SetParent(This->cctrls_hwnd, NULL);
1451 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
1453 FileDialogImpl *This = crs->lpCreateParams;
1454 TRACE("%p\n", This);
1456 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1457 return TRUE;
1460 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
1462 customctrl *cur1, *cur2;
1463 TRACE("%p\n", This);
1465 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1467 list_remove(&cur1->entry);
1468 ctrl_free(cur1);
1471 return TRUE;
1474 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1476 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1478 switch(umessage)
1480 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1481 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1482 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1485 return FALSE;
1488 static void radiobuttonlist_set_selected_item(FileDialogImpl *This, customctrl *ctrl, cctrl_item *item)
1490 cctrl_item *cursor;
1492 LIST_FOR_EACH_ENTRY(cursor, &ctrl->sub_items, cctrl_item, entry)
1494 SendMessageW(cursor->hwnd, BM_SETCHECK, (cursor == item) ? BST_CHECKED : BST_UNCHECKED, 0);
1498 static LRESULT radiobuttonlist_on_bn_clicked(FileDialogImpl *This, HWND hwnd, HWND child)
1500 DWORD ctrl_id = (DWORD)GetWindowLongPtrW(hwnd, GWLP_ID);
1501 customctrl *ctrl;
1502 cctrl_item *item;
1503 BOOL found_item=FALSE;
1505 ctrl = get_cctrl_from_dlgid(This, ctrl_id);
1507 if (!ctrl)
1509 ERR("Can't find this control\n");
1510 return 0;
1513 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1515 if (item->hwnd == child)
1517 found_item = TRUE;
1518 break;
1522 if (!found_item)
1524 ERR("Can't find control item\n");
1525 return 0;
1528 radiobuttonlist_set_selected_item(This, ctrl, item);
1530 cctrl_event_OnItemSelected(This, ctrl->id, item->id);
1532 return 0;
1535 static LRESULT radiobuttonlist_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1537 switch(HIWORD(wparam))
1539 case BN_CLICKED: return radiobuttonlist_on_bn_clicked(This, hwnd, (HWND)lparam);
1542 return FALSE;
1545 static LRESULT CALLBACK radiobuttonlist_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1547 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1549 switch(message)
1551 case WM_COMMAND: return radiobuttonlist_on_wm_command(This, hwnd, wparam, lparam);
1554 return DefWindowProcW(hwnd, message, wparam, lparam);
1557 static HRESULT init_custom_controls(FileDialogImpl *This)
1559 WNDCLASSW wc;
1560 HDC hdc;
1561 static const WCHAR ctrl_container_classname[] = L"idlg_container_pane";
1563 InitCommonControlsEx(NULL);
1565 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1567 wc.style = CS_HREDRAW | CS_VREDRAW;
1568 wc.lpfnWndProc = ctrl_container_wndproc;
1569 wc.cbClsExtra = 0;
1570 wc.cbWndExtra = 0;
1571 wc.hInstance = COMDLG32_hInstance;
1572 wc.hIcon = 0;
1573 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1574 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1575 wc.lpszMenuName = NULL;
1576 wc.lpszClassName = ctrl_container_classname;
1578 if(!RegisterClassW(&wc)) return E_FAIL;
1581 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1582 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1583 0, 0, 0, 0, NULL, 0,
1584 COMDLG32_hInstance, This);
1585 if(!This->cctrls_hwnd)
1586 return E_FAIL;
1588 hdc = GetDC(This->cctrls_hwnd);
1589 This->dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
1590 This->dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
1591 ReleaseDC(This->cctrls_hwnd, hdc);
1593 This->cctrl_width = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Controls have a fixed width */
1594 This->cctrl_indent = MulDiv(100, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1595 This->cctrl_def_height = MulDiv(23, This->dpi_y, USER_DEFAULT_SCREEN_DPI);
1596 This->cctrls_cols = 0;
1598 This->cctrl_next_dlgid = 0x2000;
1599 list_init(&This->cctrls);
1600 This->cctrl_active_vg = NULL;
1602 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1604 /* Register class for */
1605 if (!GetClassInfoW(COMDLG32_hInstance, L"FloatNotifySink", &wc) ||
1606 wc.hInstance != COMDLG32_hInstance)
1608 wc.style = CS_HREDRAW | CS_VREDRAW;
1609 wc.lpfnWndProc = notifysink_proc;
1610 wc.cbClsExtra = 0;
1611 wc.cbWndExtra = 0;
1612 wc.hInstance = COMDLG32_hInstance;
1613 wc.hIcon = 0;
1614 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1615 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1616 wc.lpszMenuName = NULL;
1617 wc.lpszClassName = L"FloatNotifySink";
1619 if (!RegisterClassW(&wc))
1620 ERR("Failed to register FloatNotifySink window class.\n");
1623 if (!GetClassInfoW(COMDLG32_hInstance, L"RadioButtonList", &wc) ||
1624 wc.hInstance != COMDLG32_hInstance)
1626 wc.style = CS_HREDRAW | CS_VREDRAW;
1627 wc.lpfnWndProc = radiobuttonlist_proc;
1628 wc.cbClsExtra = 0;
1629 wc.cbWndExtra = 0;
1630 wc.hInstance = COMDLG32_hInstance;
1631 wc.hIcon = 0;
1632 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1633 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1634 wc.lpszMenuName = NULL;
1635 wc.lpszClassName = L"RadioButtonList";
1637 if (!RegisterClassW(&wc))
1638 ERR("Failed to register RadioButtonList window class.\n");
1641 return S_OK;
1644 /**************************************************************************
1645 * Window related functions.
1647 static BOOL update_open_dropdown(FileDialogImpl *This)
1649 /* Show or hide the open dropdown button as appropriate */
1650 BOOL show=FALSE, showing;
1651 HWND open_hwnd, dropdown_hwnd;
1653 if (This->hmenu_opendropdown)
1655 INT num_visible_items=0;
1656 cctrl_item* item;
1658 LIST_FOR_EACH_ENTRY(item, &This->cctrl_opendropdown.sub_items, cctrl_item, entry)
1660 if (item->cdcstate & CDCS_VISIBLE)
1662 num_visible_items++;
1663 if (num_visible_items >= 2)
1665 show = TRUE;
1666 break;
1672 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1673 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1675 showing = (GetWindowLongPtrW(dropdown_hwnd, GWL_STYLE) & WS_VISIBLE) != 0;
1677 if (showing != show)
1679 RECT open_rc, dropdown_rc;
1681 GetWindowRect(open_hwnd, &open_rc);
1682 GetWindowRect(dropdown_hwnd, &dropdown_rc);
1684 if (show)
1686 ShowWindow(dropdown_hwnd, SW_SHOW);
1688 SetWindowPos(open_hwnd, NULL, 0, 0,
1689 (open_rc.right - open_rc.left) - (dropdown_rc.right - dropdown_rc.left),
1690 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1692 else
1694 ShowWindow(dropdown_hwnd, SW_HIDE);
1696 SetWindowPos(open_hwnd, NULL, 0, 0,
1697 (open_rc.right - open_rc.left) + (dropdown_rc.right - dropdown_rc.left),
1698 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1702 return show;
1705 static void update_layout(FileDialogImpl *This)
1707 HDWP hdwp;
1708 HWND hwnd;
1709 RECT dialog_rc;
1710 RECT cancel_rc, dropdown_rc, open_rc;
1711 RECT filetype_rc, filename_rc, filenamelabel_rc;
1712 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1713 static const UINT vspacing = 4, hspacing = 4;
1714 static const UINT min_width = 320, min_height = 200;
1715 BOOL show_dropdown;
1717 if (!GetClientRect(This->dlg_hwnd, &dialog_rc))
1719 TRACE("Invalid dialog window, not updating layout\n");
1720 return;
1723 if(dialog_rc.right < min_width || dialog_rc.bottom < min_height)
1725 TRACE("Dialog size (%ld, %ld) too small, not updating layout\n", dialog_rc.right, dialog_rc.bottom);
1726 return;
1729 /****
1730 * Calculate the size of the dialog and all the parts.
1733 /* Cancel button */
1734 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1735 if(hwnd)
1737 int cancel_width, cancel_height;
1738 GetWindowRect(hwnd, &cancel_rc);
1739 cancel_width = cancel_rc.right - cancel_rc.left;
1740 cancel_height = cancel_rc.bottom - cancel_rc.top;
1742 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1743 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1744 cancel_rc.right = cancel_rc.left + cancel_width;
1745 cancel_rc.bottom = cancel_rc.top + cancel_height;
1748 /* Open/Save dropdown */
1749 show_dropdown = update_open_dropdown(This);
1751 if(show_dropdown)
1753 int dropdown_width, dropdown_height;
1754 hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1756 GetWindowRect(hwnd, &dropdown_rc);
1757 dropdown_width = dropdown_rc.right - dropdown_rc.left;
1758 dropdown_height = dropdown_rc.bottom - dropdown_rc.top;
1760 dropdown_rc.left = cancel_rc.left - dropdown_width - hspacing;
1761 dropdown_rc.top = cancel_rc.top;
1762 dropdown_rc.right = dropdown_rc.left + dropdown_width;
1763 dropdown_rc.bottom = dropdown_rc.top + dropdown_height;
1765 else
1767 dropdown_rc.left = dropdown_rc.right = cancel_rc.left - hspacing;
1768 dropdown_rc.top = cancel_rc.top;
1769 dropdown_rc.bottom = cancel_rc.bottom;
1772 /* Open/Save button */
1773 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1774 if(hwnd)
1776 int open_width, open_height;
1777 GetWindowRect(hwnd, &open_rc);
1778 open_width = open_rc.right - open_rc.left;
1779 open_height = open_rc.bottom - open_rc.top;
1781 open_rc.left = dropdown_rc.left - open_width;
1782 open_rc.top = dropdown_rc.top;
1783 open_rc.right = open_rc.left + open_width;
1784 open_rc.bottom = open_rc.top + open_height;
1787 /* The filetype combobox. */
1788 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1789 if(hwnd)
1791 int filetype_width, filetype_height;
1792 GetWindowRect(hwnd, &filetype_rc);
1794 filetype_width = filetype_rc.right - filetype_rc.left;
1795 filetype_height = filetype_rc.bottom - filetype_rc.top;
1797 filetype_rc.right = cancel_rc.right;
1799 filetype_rc.left = filetype_rc.right - filetype_width;
1800 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1801 filetype_rc.bottom = filetype_rc.top + filetype_height;
1803 if(!This->filterspec_count)
1804 filetype_rc.left = filetype_rc.right;
1807 /* Filename label. */
1808 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1809 if(hwnd)
1811 int filetypelabel_width, filetypelabel_height;
1812 GetWindowRect(hwnd, &filenamelabel_rc);
1814 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1815 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1817 filenamelabel_rc.left = 160; /* FIXME */
1818 filenamelabel_rc.top = filetype_rc.top;
1819 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1820 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1823 /* Filename edit box. */
1824 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1825 if(hwnd)
1827 int filename_width, filename_height;
1828 GetWindowRect(hwnd, &filename_rc);
1830 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1831 filename_height = filename_rc.bottom - filename_rc.top;
1833 filename_rc.left = filenamelabel_rc.right + hspacing;
1834 filename_rc.top = filetype_rc.top;
1835 filename_rc.right = filename_rc.left + filename_width;
1836 filename_rc.bottom = filename_rc.top + filename_height;
1839 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1840 if(hwnd)
1842 GetWindowRect(hwnd, &toolbar_rc);
1843 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1846 /* The custom controls */
1847 customctrls_rc.left = dialog_rc.left + hspacing;
1848 customctrls_rc.right = dialog_rc.right - hspacing;
1849 customctrls_rc.bottom = filename_rc.top - vspacing;
1850 customctrls_rc.top = customctrls_rc.bottom -
1851 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1853 /* The ExplorerBrowser control. */
1854 ebrowser_rc.left = dialog_rc.left + hspacing;
1855 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1856 ebrowser_rc.right = dialog_rc.right - hspacing;
1857 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1859 /****
1860 * Move everything to the right place.
1863 /* FIXME: The Save Dialog uses a slightly different layout. */
1864 hdwp = BeginDeferWindowPos(7);
1866 if(hdwp && This->peb)
1867 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1869 if(hdwp && This->cctrls_hwnd)
1870 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1871 customctrls_rc.left, customctrls_rc.top,
1872 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1873 SWP_NOZORDER | SWP_NOACTIVATE);
1875 /* The default controls */
1876 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1877 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1878 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1880 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1881 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1882 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1883 SWP_NOZORDER | SWP_NOACTIVATE);
1885 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1886 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1887 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1889 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1890 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1891 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1893 if(hdwp && This->hmenu_opendropdown && (hwnd = GetDlgItem(This->dlg_hwnd, psh1)))
1894 DeferWindowPos(hdwp, hwnd, NULL, dropdown_rc.left, dropdown_rc.top, 0, 0,
1895 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1897 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1898 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1899 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1901 if(hdwp)
1902 EndDeferWindowPos(hdwp);
1903 else
1904 ERR("Failed to position dialog controls.\n");
1906 return;
1909 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1911 IShellItem *psi_folder;
1912 IObjectWithSite *client;
1913 FOLDERSETTINGS fos;
1914 RECT rc = {0};
1915 HRESULT hr;
1917 /* Create ExplorerBrowser instance */
1918 OleInitialize(NULL);
1920 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1921 &IID_IExplorerBrowser, (void**)&This->peb);
1922 if(FAILED(hr))
1924 ERR("Failed to instantiate ExplorerBrowser control.\n");
1925 return hr;
1928 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES | EBO_NOBORDER);
1930 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1931 if(FAILED(hr))
1933 ERR("Failed to initialize the ExplorerBrowser control.\n");
1934 IExplorerBrowser_Release(This->peb);
1935 This->peb = NULL;
1936 return hr;
1938 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1939 if(FAILED(hr))
1940 ERR("Advise (ExplorerBrowser) failed.\n");
1942 /* Get previous options? */
1943 fos.ViewMode = fos.fFlags = 0;
1944 if(!(This->options & FOS_ALLOWMULTISELECT))
1945 fos.fFlags |= FWF_SINGLESEL;
1947 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1949 hr = IExplorerBrowser_QueryInterface(This->peb, &IID_IObjectWithSite, (void**)&client);
1950 if (hr == S_OK)
1952 hr = IObjectWithSite_SetSite(client, (IUnknown*)&This->IFileDialog2_iface);
1953 IObjectWithSite_Release(client);
1954 if(FAILED(hr))
1955 ERR("SetSite failed, 0x%08lx\n", hr);
1958 /* Browse somewhere */
1959 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1960 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1962 return S_OK;
1965 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1967 HWND htoolbar;
1968 TBADDBITMAP tbab;
1969 TBBUTTON button[3];
1970 int height;
1971 int navUpImgIndex;
1973 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1974 0, 0, 0, 0,
1975 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1977 tbab.hInst = HINST_COMMCTRL;
1978 tbab.nID = IDB_HIST_LARGE_COLOR;
1979 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1980 tbab.nID = IDB_VIEW_LARGE_COLOR;
1981 navUpImgIndex = SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1982 navUpImgIndex += VIEW_PARENTFOLDER;
1984 button[0].iBitmap = HIST_BACK;
1985 button[0].idCommand = IDC_NAVBACK;
1986 button[0].fsState = TBSTATE_ENABLED;
1987 button[0].fsStyle = BTNS_BUTTON;
1988 button[0].dwData = 0;
1989 button[0].iString = 0;
1991 button[1].iBitmap = HIST_FORWARD;
1992 button[1].idCommand = IDC_NAVFORWARD;
1993 button[1].fsState = TBSTATE_ENABLED;
1994 button[1].fsStyle = BTNS_BUTTON;
1995 button[1].dwData = 0;
1996 button[1].iString = 0;
1998 button[2].iBitmap = navUpImgIndex;
1999 button[2].idCommand = IDC_NAVUP;
2000 button[2].fsState = TBSTATE_ENABLED;
2001 button[2].fsStyle = BTNS_BUTTON;
2002 button[2].dwData = 0;
2003 button[2].iString = 0;
2005 SendMessageW(htoolbar, TB_ADDBUTTONSW, 3, (LPARAM)button);
2006 height = MulDiv(24, This->dpi_y, USER_DEFAULT_SCREEN_DPI);
2007 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(height, height));
2008 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
2011 static void update_control_text(FileDialogImpl *This)
2013 HWND hitem;
2014 LPCWSTR custom_okbutton;
2015 cctrl_item* item;
2016 UINT min_width = MulDiv(50, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
2017 UINT max_width = MulDiv(250, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
2019 if(This->custom_title)
2020 SetWindowTextW(This->dlg_hwnd, This->custom_title);
2022 if(This->hmenu_opendropdown && (item = get_first_item(&This->cctrl_opendropdown)))
2023 custom_okbutton = item->label;
2024 else
2025 custom_okbutton = This->custom_okbutton;
2027 if(custom_okbutton &&
2028 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
2030 SetWindowTextW(hitem, custom_okbutton);
2031 ctrl_resize(hitem, min_width, max_width, FALSE);
2034 if(This->custom_cancelbutton &&
2035 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
2037 SetWindowTextW(hitem, This->custom_cancelbutton);
2038 ctrl_resize(hitem, min_width, max_width, FALSE);
2041 if(This->custom_filenamelabel &&
2042 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
2044 SetWindowTextW(hitem, This->custom_filenamelabel);
2045 ctrl_resize(hitem, min_width, max_width, FALSE);
2049 static LRESULT CALLBACK dropdown_subclass_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
2051 if (umessage == WM_LBUTTONDOWN)
2053 FileDialogImpl *This = GetPropW(hwnd, L"itemdlg_This");
2055 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
2056 show_opendropdown(This);
2057 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
2059 return 0;
2062 return CallWindowProcW((WNDPROC)GetPropW(hwnd, L"itemdlg_oldwndproc"), hwnd, umessage, wparam, lparam);
2065 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
2067 FileDialogImpl *This = (FileDialogImpl*)lParam;
2068 HWND hitem;
2070 TRACE("(%p, %p)\n", This, hwnd);
2072 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
2073 This->dlg_hwnd = hwnd;
2075 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
2076 if(hitem) ShowWindow(hitem, SW_HIDE);
2078 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
2079 if(hitem) ShowWindow(hitem, SW_HIDE);
2081 /* Fill filetypes combobox, or hide it. */
2082 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
2083 if(This->filterspec_count)
2085 HDC hdc;
2086 HFONT font;
2087 SIZE size;
2088 UINT i, maxwidth = 0;
2090 hdc = GetDC(hitem);
2091 font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
2092 SelectObject(hdc, font);
2094 for(i = 0; i < This->filterspec_count; i++)
2096 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
2098 if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
2099 maxwidth = max(maxwidth, size.cx);
2101 ReleaseDC(hitem, hdc);
2103 if(maxwidth > 0)
2105 maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
2106 SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
2108 else
2109 ERR("Failed to calculate width of filetype dropdown\n");
2111 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
2113 else
2114 ShowWindow(hitem, SW_HIDE);
2116 if(This->set_filename &&
2117 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
2118 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
2120 if(This->hmenu_opendropdown)
2122 HWND dropdown_hwnd;
2123 LOGFONTW lfw, lfw_marlett;
2124 HFONT dialog_font;
2126 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
2128 /* Change dropdown button font to Marlett */
2129 dialog_font = (HFONT)SendMessageW(dropdown_hwnd, WM_GETFONT, 0, 0);
2131 GetObjectW(dialog_font, sizeof(lfw), &lfw);
2133 memset(&lfw_marlett, 0, sizeof(lfw_marlett));
2134 lstrcpyW(lfw_marlett.lfFaceName, L"Marlett");
2135 lfw_marlett.lfHeight = lfw.lfHeight;
2136 lfw_marlett.lfCharSet = SYMBOL_CHARSET;
2138 This->hfont_opendropdown = CreateFontIndirectW(&lfw_marlett);
2140 SendMessageW(dropdown_hwnd, WM_SETFONT, (LPARAM)This->hfont_opendropdown, 0);
2142 /* Subclass button so we can handle LBUTTONDOWN */
2143 SetPropW(dropdown_hwnd, L"itemdlg_This", This);
2144 SetPropW(dropdown_hwnd, L"itemdlg_oldwndproc",
2145 (HANDLE)SetWindowLongPtrW(dropdown_hwnd, GWLP_WNDPROC, (LONG_PTR)dropdown_subclass_proc));
2148 ctrl_container_reparent(This, This->dlg_hwnd);
2149 init_explorerbrowser(This);
2150 init_toolbar(This, hwnd);
2151 update_control_text(This);
2152 update_layout(This);
2154 if(This->filterspec_count)
2155 events_OnTypeChange(This);
2157 if ((hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)))
2158 SetFocus(hitem);
2160 return FALSE;
2163 static LRESULT on_wm_size(FileDialogImpl *This)
2165 update_layout(This);
2166 return FALSE;
2169 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
2171 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
2172 TRACE("%p (%p)\n", This, mmi);
2174 /* FIXME */
2175 mmi->ptMinTrackSize.x = 640;
2176 mmi->ptMinTrackSize.y = 480;
2178 return FALSE;
2181 static LRESULT on_wm_destroy(FileDialogImpl *This)
2183 TRACE("%p\n", This);
2185 if(This->peb)
2187 IExplorerBrowser_Destroy(This->peb);
2188 IExplorerBrowser_Release(This->peb);
2189 This->peb = NULL;
2192 ctrl_container_reparent(This, NULL);
2193 This->dlg_hwnd = NULL;
2195 DeleteObject(This->hfont_opendropdown);
2196 This->hfont_opendropdown = NULL;
2198 return TRUE;
2201 static LRESULT on_idok(FileDialogImpl *This)
2203 TRACE("%p\n", This);
2205 if(SUCCEEDED(on_default_action(This)))
2206 EndDialog(This->dlg_hwnd, S_OK);
2208 return FALSE;
2211 static LRESULT on_idcancel(FileDialogImpl *This)
2213 TRACE("%p\n", This);
2215 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
2217 return FALSE;
2220 static LRESULT on_command_opendropdown(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2222 if(HIWORD(wparam) == BN_CLICKED)
2224 HWND hwnd = (HWND)lparam;
2225 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
2226 show_opendropdown(This);
2227 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
2230 return FALSE;
2233 static LRESULT on_browse_back(FileDialogImpl *This)
2235 TRACE("%p\n", This);
2236 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
2237 return FALSE;
2240 static LRESULT on_browse_forward(FileDialogImpl *This)
2242 TRACE("%p\n", This);
2243 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
2244 return FALSE;
2247 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2249 if(HIWORD(wparam) == CBN_SELCHANGE)
2251 IShellView *psv;
2252 HRESULT hr;
2253 LPWSTR filename;
2254 UINT prev_index = This->filetypeindex;
2256 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
2257 TRACE("File type selection changed to %d.\n", This->filetypeindex);
2259 if(prev_index == This->filetypeindex)
2260 return FALSE;
2262 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
2263 if(SUCCEEDED(hr))
2265 IShellView_Refresh(psv);
2266 IShellView_Release(psv);
2269 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
2271 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
2273 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
2274 if(ext)
2276 lstrcpyW(buf, filename);
2278 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
2279 PathRemoveExtensionW(buf);
2281 lstrcatW(buf, ext);
2282 set_file_name(This, buf);
2284 CoTaskMemFree(filename);
2287 /* The documentation claims that OnTypeChange is called only
2288 * when the dialog is opened, but this is obviously not the
2289 * case. */
2290 events_OnTypeChange(This);
2293 return FALSE;
2296 static LRESULT on_browse_up(FileDialogImpl *This)
2298 TRACE("%p\n", This);
2299 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_PARENT);
2300 return FALSE;
2303 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2305 switch(LOWORD(wparam))
2307 case IDOK: return on_idok(This);
2308 case IDCANCEL: return on_idcancel(This);
2309 case psh1: return on_command_opendropdown(This, wparam, lparam);
2310 case IDC_NAVBACK: return on_browse_back(This);
2311 case IDC_NAVFORWARD: return on_browse_forward(This);
2312 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
2313 case IDC_NAVUP: return on_browse_up(This);
2314 default: TRACE("Unknown command.\n");
2316 return FALSE;
2319 static INT_PTR CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
2321 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
2323 switch(umessage)
2325 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
2326 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
2327 case WM_SIZE: return on_wm_size(This);
2328 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
2329 case WM_DESTROY: return on_wm_destroy(This);
2332 return FALSE;
2335 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
2337 ULONG_PTR ctx_cookie = 0;
2338 INT_PTR res;
2340 if (This->dlg_hwnd)
2341 return E_UNEXPECTED;
2343 if (!GetCurrentActCtx(&This->user_actctx))
2344 This->user_actctx = INVALID_HANDLE_VALUE;
2346 if (COMDLG32_hActCtx != INVALID_HANDLE_VALUE)
2347 ActivateActCtx(COMDLG32_hActCtx, &ctx_cookie);
2349 SetLastError(0);
2350 res = DialogBoxParamW(COMDLG32_hInstance,
2351 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
2352 parent, itemdlg_dlgproc, (LPARAM)This);
2353 This->dlg_hwnd = NULL;
2355 if (COMDLG32_hActCtx != INVALID_HANDLE_VALUE)
2356 DeactivateActCtx(0, ctx_cookie);
2358 if (This->user_actctx != INVALID_HANDLE_VALUE)
2360 ReleaseActCtx(This->user_actctx);
2361 This->user_actctx = INVALID_HANDLE_VALUE;
2364 if(res == -1)
2366 ERR("Failed to show dialog (LastError: %ld)\n", GetLastError());
2367 return E_FAIL;
2370 TRACE("Returning 0x%08lx\n", (HRESULT)res);
2371 return (HRESULT)res;
2374 /**************************************************************************
2375 * IFileDialog implementation
2377 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
2379 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
2382 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
2383 REFIID riid,
2384 void **ppvObject)
2386 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2387 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2389 *ppvObject = NULL;
2390 if(IsEqualGUID(riid, &IID_IUnknown) ||
2391 IsEqualGUID(riid, &IID_IFileDialog) ||
2392 IsEqualGUID(riid, &IID_IFileDialog2))
2394 *ppvObject = iface;
2396 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
2398 *ppvObject = &This->u.IFileOpenDialog_iface;
2400 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
2402 *ppvObject = &This->u.IFileSaveDialog_iface;
2404 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
2406 *ppvObject = &This->IExplorerBrowserEvents_iface;
2408 else if(IsEqualGUID(riid, &IID_IServiceProvider))
2410 *ppvObject = &This->IServiceProvider_iface;
2412 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
2413 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
2414 IsEqualGUID(&IID_ICommDlgBrowser, riid))
2416 *ppvObject = &This->ICommDlgBrowser3_iface;
2418 else if(IsEqualGUID(&IID_IOleWindow, riid))
2420 *ppvObject = &This->IOleWindow_iface;
2422 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
2423 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
2425 *ppvObject = &This->IFileDialogCustomize_iface;
2427 else
2428 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
2430 if(*ppvObject)
2432 IUnknown_AddRef((IUnknown*)*ppvObject);
2433 return S_OK;
2436 return E_NOINTERFACE;
2439 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
2441 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2442 LONG ref = InterlockedIncrement(&This->ref);
2443 TRACE("%p - ref %ld\n", This, ref);
2445 return ref;
2448 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
2450 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2451 LONG ref = InterlockedDecrement(&This->ref);
2452 TRACE("%p - ref %ld\n", This, ref);
2454 if(!ref)
2456 UINT i;
2457 for(i = 0; i < This->filterspec_count; i++)
2459 LocalFree((void*)This->filterspecs[i].pszName);
2460 LocalFree((void*)This->filterspecs[i].pszSpec);
2462 HeapFree(GetProcessHeap(), 0, This->filterspecs);
2464 DestroyWindow(This->cctrls_hwnd);
2466 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
2467 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
2468 if(This->psi_folder) IShellItem_Release(This->psi_folder);
2469 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
2470 if(This->psia_results) IShellItemArray_Release(This->psia_results);
2472 LocalFree(This->set_filename);
2473 LocalFree(This->default_ext);
2474 LocalFree(This->custom_title);
2475 LocalFree(This->custom_okbutton);
2476 LocalFree(This->custom_cancelbutton);
2477 LocalFree(This->custom_filenamelabel);
2479 DestroyMenu(This->hmenu_opendropdown);
2480 DeleteObject(This->hfont_opendropdown);
2482 HeapFree(GetProcessHeap(), 0, This);
2485 return ref;
2488 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
2490 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2491 TRACE("%p (%p)\n", iface, hwndOwner);
2493 This->opendropdown_has_selection = FALSE;
2495 return create_dialog(This, hwndOwner);
2498 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
2499 const COMDLG_FILTERSPEC *rgFilterSpec)
2501 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2502 UINT i;
2503 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
2505 if(!rgFilterSpec)
2506 return E_INVALIDARG;
2508 if(This->filterspecs)
2509 return E_UNEXPECTED;
2511 if(!cFileTypes)
2512 return S_OK;
2514 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
2515 for(i = 0; i < cFileTypes; i++)
2517 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
2518 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
2520 This->filterspec_count = cFileTypes;
2522 return S_OK;
2525 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
2527 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2528 TRACE("%p (%d)\n", This, iFileType);
2530 if(!This->filterspecs)
2531 return E_FAIL;
2533 iFileType = max(iFileType, 1);
2534 iFileType = min(iFileType, This->filterspec_count);
2535 This->filetypeindex = iFileType-1;
2537 return S_OK;
2540 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
2542 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2543 TRACE("%p (%p)\n", This, piFileType);
2545 if(!piFileType)
2546 return E_INVALIDARG;
2548 if(This->filterspec_count == 0)
2549 *piFileType = 0;
2550 else
2551 *piFileType = This->filetypeindex + 1;
2553 return S_OK;
2556 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
2558 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2559 events_client *client;
2560 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
2562 if(!pfde || !pdwCookie)
2563 return E_INVALIDARG;
2565 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
2566 client->pfde = pfde;
2567 client->cookie = ++This->events_next_cookie;
2569 IFileDialogEvents_AddRef(pfde);
2570 *pdwCookie = client->cookie;
2572 list_add_tail(&This->events_clients, &client->entry);
2574 return S_OK;
2577 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
2579 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2580 events_client *client, *found = NULL;
2581 TRACE("%p (%ld)\n", This, dwCookie);
2583 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
2585 if(client->cookie == dwCookie)
2587 found = client;
2588 break;
2592 if(found)
2594 list_remove(&found->entry);
2595 IFileDialogEvents_Release(found->pfde);
2596 HeapFree(GetProcessHeap(), 0, found);
2597 return S_OK;
2600 return E_INVALIDARG;
2603 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
2605 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2606 TRACE("%p (0x%lx)\n", This, fos);
2608 if (fos & ~(FOS_OVERWRITEPROMPT | FOS_STRICTFILETYPES | FOS_NOCHANGEDIR | FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM
2609 | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_ALLOWMULTISELECT | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST
2610 | FOS_CREATEPROMPT | FOS_SHAREAWARE | FOS_NOREADONLYRETURN | FOS_NOTESTFILECREATE | FOS_HIDEMRUPLACES
2611 | FOS_HIDEPINNEDPLACES | FOS_NODEREFERENCELINKS | FOS_DONTADDTORECENT | FOS_FORCESHOWHIDDEN
2612 | FOS_DEFAULTNOMINIMODE | FOS_FORCEPREVIEWPANEON | FOS_SUPPORTSTREAMABLEITEMS))
2614 WARN("Invalid option %#lx\n", fos);
2615 return E_INVALIDARG;
2618 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
2620 WCHAR buf[30];
2621 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, ARRAY_SIZE(buf));
2622 IFileDialog2_SetTitle(iface, buf);
2625 This->options = fos;
2627 return S_OK;
2630 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
2632 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2633 TRACE("%p (%p)\n", This, pfos);
2635 if(!pfos)
2636 return E_INVALIDARG;
2638 *pfos = This->options;
2640 return S_OK;
2643 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
2645 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2646 TRACE("%p (%p)\n", This, psi);
2647 if(This->psi_defaultfolder)
2648 IShellItem_Release(This->psi_defaultfolder);
2650 This->psi_defaultfolder = psi;
2652 if(This->psi_defaultfolder)
2653 IShellItem_AddRef(This->psi_defaultfolder);
2655 return S_OK;
2658 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
2660 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2661 TRACE("%p (%p)\n", This, psi);
2662 if(This->psi_setfolder)
2663 IShellItem_Release(This->psi_setfolder);
2665 This->psi_setfolder = psi;
2667 if(This->psi_setfolder)
2668 IShellItem_AddRef(This->psi_setfolder);
2670 return S_OK;
2673 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
2675 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2676 TRACE("%p (%p)\n", This, ppsi);
2677 if(!ppsi)
2678 return E_INVALIDARG;
2680 /* FIXME:
2681 If the dialog is shown, return the current(ly selected) folder. */
2683 *ppsi = NULL;
2684 if(This->psi_folder)
2685 *ppsi = This->psi_folder;
2686 else if(This->psi_setfolder)
2687 *ppsi = This->psi_setfolder;
2688 else if(This->psi_defaultfolder)
2689 *ppsi = This->psi_defaultfolder;
2691 if(*ppsi)
2693 IShellItem_AddRef(*ppsi);
2694 return S_OK;
2697 return E_FAIL;
2700 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
2702 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2703 HRESULT hr;
2704 TRACE("%p (%p)\n", This, ppsi);
2706 if(!ppsi)
2707 return E_INVALIDARG;
2709 if(This->psia_selection)
2711 /* FIXME: Check filename edit box */
2712 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2713 return hr;
2716 return E_FAIL;
2719 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
2721 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2722 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2724 set_file_name(This, pszName);
2726 return S_OK;
2729 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
2731 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2732 TRACE("%p (%p)\n", iface, pszName);
2734 if(!pszName)
2735 return E_INVALIDARG;
2737 *pszName = NULL;
2738 get_file_name(This, pszName);
2739 return *pszName ? S_OK : E_FAIL;
2742 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
2744 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2745 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2747 LocalFree(This->custom_title);
2748 This->custom_title = StrDupW(pszTitle);
2749 update_control_text(This);
2751 return S_OK;
2754 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
2756 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2757 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2759 LocalFree(This->custom_okbutton);
2760 This->custom_okbutton = StrDupW(pszText);
2761 update_control_text(This);
2762 update_layout(This);
2764 return S_OK;
2767 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2769 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2770 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2772 LocalFree(This->custom_filenamelabel);
2773 This->custom_filenamelabel = StrDupW(pszLabel);
2774 update_control_text(This);
2775 update_layout(This);
2777 return S_OK;
2780 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
2782 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2783 HRESULT hr;
2784 TRACE("%p (%p)\n", This, ppsi);
2786 if(!ppsi)
2787 return E_INVALIDARG;
2789 if(This->psia_results)
2791 DWORD item_count;
2792 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2793 if(SUCCEEDED(hr))
2795 if(item_count != 1)
2796 return E_FAIL;
2798 /* Adds a reference. */
2799 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2802 return hr;
2805 return E_UNEXPECTED;
2808 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2810 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2811 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2812 return S_OK;
2815 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2817 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2818 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2820 LocalFree(This->default_ext);
2821 This->default_ext = StrDupW(pszDefaultExtension);
2823 return S_OK;
2826 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2828 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2829 TRACE("%p (0x%08lx)\n", This, hr);
2831 if(This->dlg_hwnd)
2832 EndDialog(This->dlg_hwnd, hr);
2834 return S_OK;
2837 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2839 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2840 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2841 This->client_guid = *guid;
2842 return S_OK;
2845 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2847 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2848 FIXME("stub - %p\n", This);
2849 return E_NOTIMPL;
2852 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2854 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2855 FIXME("stub - %p (%p)\n", This, pFilter);
2856 return E_NOTIMPL;
2859 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2861 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2862 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2864 LocalFree(This->custom_cancelbutton);
2865 This->custom_cancelbutton = StrDupW(pszLabel);
2866 update_control_text(This);
2867 update_layout(This);
2869 return S_OK;
2872 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2874 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2875 FIXME("stub - %p (%p)\n", This, psi);
2876 return E_NOTIMPL;
2879 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2880 IFileDialog2_fnQueryInterface,
2881 IFileDialog2_fnAddRef,
2882 IFileDialog2_fnRelease,
2883 IFileDialog2_fnShow,
2884 IFileDialog2_fnSetFileTypes,
2885 IFileDialog2_fnSetFileTypeIndex,
2886 IFileDialog2_fnGetFileTypeIndex,
2887 IFileDialog2_fnAdvise,
2888 IFileDialog2_fnUnadvise,
2889 IFileDialog2_fnSetOptions,
2890 IFileDialog2_fnGetOptions,
2891 IFileDialog2_fnSetDefaultFolder,
2892 IFileDialog2_fnSetFolder,
2893 IFileDialog2_fnGetFolder,
2894 IFileDialog2_fnGetCurrentSelection,
2895 IFileDialog2_fnSetFileName,
2896 IFileDialog2_fnGetFileName,
2897 IFileDialog2_fnSetTitle,
2898 IFileDialog2_fnSetOkButtonLabel,
2899 IFileDialog2_fnSetFileNameLabel,
2900 IFileDialog2_fnGetResult,
2901 IFileDialog2_fnAddPlace,
2902 IFileDialog2_fnSetDefaultExtension,
2903 IFileDialog2_fnClose,
2904 IFileDialog2_fnSetClientGuid,
2905 IFileDialog2_fnClearClientData,
2906 IFileDialog2_fnSetFilter,
2907 IFileDialog2_fnSetCancelButtonLabel,
2908 IFileDialog2_fnSetNavigationRoot
2911 /**************************************************************************
2912 * IFileOpenDialog
2914 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2916 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2919 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2920 REFIID riid, void **ppvObject)
2922 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2923 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2926 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2928 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2929 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2932 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2934 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2935 return IFileDialog2_Release(&This->IFileDialog2_iface);
2938 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2940 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2941 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2944 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2945 const COMDLG_FILTERSPEC *rgFilterSpec)
2947 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2948 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2951 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2953 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2954 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2957 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2959 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2960 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2963 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2964 DWORD *pdwCookie)
2966 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2967 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2970 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2972 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2973 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2976 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2978 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2979 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2982 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2984 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2985 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2988 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2990 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2991 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2994 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2996 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2997 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
3000 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
3002 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3003 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
3006 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
3008 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3009 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
3012 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
3014 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3015 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
3018 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
3020 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3021 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
3024 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
3026 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3027 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
3030 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
3032 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3033 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
3036 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
3038 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3039 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
3042 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
3044 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3045 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
3048 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
3050 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3051 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
3054 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
3055 LPCWSTR pszDefaultExtension)
3057 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3058 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
3061 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
3063 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3064 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
3067 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
3069 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3070 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
3073 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
3075 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3076 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
3079 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
3081 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3082 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
3085 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
3087 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3088 TRACE("%p (%p)\n", This, ppenum);
3090 *ppenum = This->psia_results;
3092 if(*ppenum)
3094 IShellItemArray_AddRef(*ppenum);
3095 return S_OK;
3098 return E_FAIL;
3101 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
3103 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3104 TRACE("%p (%p)\n", This, ppsai);
3106 if(This->psia_selection)
3108 *ppsai = This->psia_selection;
3109 IShellItemArray_AddRef(*ppsai);
3110 return S_OK;
3113 return E_FAIL;
3116 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
3117 IFileOpenDialog_fnQueryInterface,
3118 IFileOpenDialog_fnAddRef,
3119 IFileOpenDialog_fnRelease,
3120 IFileOpenDialog_fnShow,
3121 IFileOpenDialog_fnSetFileTypes,
3122 IFileOpenDialog_fnSetFileTypeIndex,
3123 IFileOpenDialog_fnGetFileTypeIndex,
3124 IFileOpenDialog_fnAdvise,
3125 IFileOpenDialog_fnUnadvise,
3126 IFileOpenDialog_fnSetOptions,
3127 IFileOpenDialog_fnGetOptions,
3128 IFileOpenDialog_fnSetDefaultFolder,
3129 IFileOpenDialog_fnSetFolder,
3130 IFileOpenDialog_fnGetFolder,
3131 IFileOpenDialog_fnGetCurrentSelection,
3132 IFileOpenDialog_fnSetFileName,
3133 IFileOpenDialog_fnGetFileName,
3134 IFileOpenDialog_fnSetTitle,
3135 IFileOpenDialog_fnSetOkButtonLabel,
3136 IFileOpenDialog_fnSetFileNameLabel,
3137 IFileOpenDialog_fnGetResult,
3138 IFileOpenDialog_fnAddPlace,
3139 IFileOpenDialog_fnSetDefaultExtension,
3140 IFileOpenDialog_fnClose,
3141 IFileOpenDialog_fnSetClientGuid,
3142 IFileOpenDialog_fnClearClientData,
3143 IFileOpenDialog_fnSetFilter,
3144 IFileOpenDialog_fnGetResults,
3145 IFileOpenDialog_fnGetSelectedItems
3148 /**************************************************************************
3149 * IFileSaveDialog
3151 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
3153 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
3156 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
3157 REFIID riid,
3158 void **ppvObject)
3160 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3161 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3164 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
3166 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3167 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3170 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
3172 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3173 return IFileDialog2_Release(&This->IFileDialog2_iface);
3176 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
3178 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3179 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
3182 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
3183 const COMDLG_FILTERSPEC *rgFilterSpec)
3185 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3186 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
3189 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
3191 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3192 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
3195 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
3197 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3198 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
3201 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
3202 DWORD *pdwCookie)
3204 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3205 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
3208 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
3210 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3211 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
3214 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
3216 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3217 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
3220 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
3222 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3223 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
3226 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
3228 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3229 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
3232 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
3234 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3235 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
3238 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
3240 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3241 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
3244 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
3246 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3247 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
3250 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
3252 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3253 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
3256 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
3258 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3259 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
3262 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
3264 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3265 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
3268 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
3270 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3271 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
3274 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
3276 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3277 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
3280 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
3282 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3283 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
3286 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
3288 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3289 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
3292 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
3293 LPCWSTR pszDefaultExtension)
3295 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3296 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
3299 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
3301 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3302 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
3305 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
3307 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3308 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
3311 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
3313 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3314 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
3317 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
3319 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3320 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
3323 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
3325 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3326 FIXME("stub - %p (%p)\n", This, psi);
3327 return E_NOTIMPL;
3330 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
3332 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3333 FIXME("stub - %p (%p)\n", This, pStore);
3334 return E_NOTIMPL;
3337 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
3338 IPropertyDescriptionList *pList,
3339 BOOL fAppendDefault)
3341 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3342 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
3343 return E_NOTIMPL;
3346 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
3348 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3349 FIXME("stub - %p (%p)\n", This, ppStore);
3350 return E_NOTIMPL;
3353 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
3354 IShellItem *psi,
3355 IPropertyStore *pStore,
3356 HWND hwnd,
3357 IFileOperationProgressSink *pSink)
3359 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3360 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
3361 return E_NOTIMPL;
3364 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
3365 IFileSaveDialog_fnQueryInterface,
3366 IFileSaveDialog_fnAddRef,
3367 IFileSaveDialog_fnRelease,
3368 IFileSaveDialog_fnShow,
3369 IFileSaveDialog_fnSetFileTypes,
3370 IFileSaveDialog_fnSetFileTypeIndex,
3371 IFileSaveDialog_fnGetFileTypeIndex,
3372 IFileSaveDialog_fnAdvise,
3373 IFileSaveDialog_fnUnadvise,
3374 IFileSaveDialog_fnSetOptions,
3375 IFileSaveDialog_fnGetOptions,
3376 IFileSaveDialog_fnSetDefaultFolder,
3377 IFileSaveDialog_fnSetFolder,
3378 IFileSaveDialog_fnGetFolder,
3379 IFileSaveDialog_fnGetCurrentSelection,
3380 IFileSaveDialog_fnSetFileName,
3381 IFileSaveDialog_fnGetFileName,
3382 IFileSaveDialog_fnSetTitle,
3383 IFileSaveDialog_fnSetOkButtonLabel,
3384 IFileSaveDialog_fnSetFileNameLabel,
3385 IFileSaveDialog_fnGetResult,
3386 IFileSaveDialog_fnAddPlace,
3387 IFileSaveDialog_fnSetDefaultExtension,
3388 IFileSaveDialog_fnClose,
3389 IFileSaveDialog_fnSetClientGuid,
3390 IFileSaveDialog_fnClearClientData,
3391 IFileSaveDialog_fnSetFilter,
3392 IFileSaveDialog_fnSetSaveAsItem,
3393 IFileSaveDialog_fnSetProperties,
3394 IFileSaveDialog_fnSetCollectedProperties,
3395 IFileSaveDialog_fnGetProperties,
3396 IFileSaveDialog_fnApplyProperties
3399 /**************************************************************************
3400 * IExplorerBrowserEvents implementation
3402 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
3404 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
3407 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
3408 REFIID riid, void **ppvObject)
3410 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3411 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
3413 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3416 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
3418 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3419 TRACE("%p\n", This);
3420 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3423 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
3425 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3426 TRACE("%p\n", This);
3427 return IFileDialog2_Release(&This->IFileDialog2_iface);
3430 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
3431 PCIDLIST_ABSOLUTE pidlFolder)
3433 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3434 IShellItem *psi;
3435 HRESULT hr;
3436 TRACE("%p (%p)\n", This, pidlFolder);
3438 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
3439 if(SUCCEEDED(hr))
3441 hr = events_OnFolderChanging(This, psi);
3442 IShellItem_Release(psi);
3444 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
3445 if(hr == S_FALSE)
3446 hr = E_FAIL;
3448 return hr;
3450 else
3451 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
3453 return S_OK;
3456 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
3457 IShellView *psv)
3459 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3460 TRACE("%p (%p)\n", This, psv);
3461 return S_OK;
3464 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
3465 PCIDLIST_ABSOLUTE pidlFolder)
3467 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3468 HRESULT hr;
3469 TRACE("%p (%p)\n", This, pidlFolder);
3471 if(This->psi_folder)
3472 IShellItem_Release(This->psi_folder);
3474 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
3475 if(FAILED(hr))
3477 ERR("Failed to get the current folder.\n");
3478 This->psi_folder = NULL;
3481 events_OnFolderChange(This);
3483 return S_OK;
3486 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
3487 PCIDLIST_ABSOLUTE pidlFolder)
3489 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3490 TRACE("%p (%p)\n", This, pidlFolder);
3491 return S_OK;
3494 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
3495 IExplorerBrowserEvents_fnQueryInterface,
3496 IExplorerBrowserEvents_fnAddRef,
3497 IExplorerBrowserEvents_fnRelease,
3498 IExplorerBrowserEvents_fnOnNavigationPending,
3499 IExplorerBrowserEvents_fnOnViewCreated,
3500 IExplorerBrowserEvents_fnOnNavigationComplete,
3501 IExplorerBrowserEvents_fnOnNavigationFailed
3504 /**************************************************************************
3505 * IServiceProvider implementation
3507 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
3509 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
3512 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
3513 REFIID riid, void **ppvObject)
3515 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3516 TRACE("%p\n", This);
3517 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3520 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
3522 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3523 TRACE("%p\n", This);
3524 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3527 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
3529 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3530 TRACE("%p\n", This);
3531 return IFileDialog2_Release(&This->IFileDialog2_iface);
3534 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
3535 REFGUID guidService,
3536 REFIID riid, void **ppv)
3538 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3539 HRESULT hr = E_NOTIMPL;
3540 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
3542 *ppv = NULL;
3543 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
3544 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
3545 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
3546 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
3547 else
3548 FIXME("Interface %s requested from unknown service %s\n",
3549 debugstr_guid(riid), debugstr_guid(guidService));
3551 return hr;
3554 static const IServiceProviderVtbl vt_IServiceProvider = {
3555 IServiceProvider_fnQueryInterface,
3556 IServiceProvider_fnAddRef,
3557 IServiceProvider_fnRelease,
3558 IServiceProvider_fnQueryService
3561 /**************************************************************************
3562 * ICommDlgBrowser3 implementation
3564 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
3566 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
3569 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
3570 REFIID riid, void **ppvObject)
3572 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3573 TRACE("%p\n", This);
3574 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3577 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
3579 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3580 TRACE("%p\n", This);
3581 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3584 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
3586 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3587 TRACE("%p\n", This);
3588 return IFileDialog2_Release(&This->IFileDialog2_iface);
3591 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
3592 IShellView *shv)
3594 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3595 HRESULT hr;
3596 TRACE("%p (%p)\n", This, shv);
3598 hr = on_default_action(This);
3600 if(SUCCEEDED(hr))
3601 EndDialog(This->dlg_hwnd, S_OK);
3603 return S_OK;
3606 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
3607 IShellView *shv, ULONG uChange )
3609 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3610 IDataObject *new_selection;
3611 HRESULT hr;
3612 TRACE("%p (%p, %lx)\n", This, shv, uChange);
3614 switch(uChange)
3616 case CDBOSC_SELCHANGE:
3617 if(This->psia_selection)
3619 IShellItemArray_Release(This->psia_selection);
3620 This->psia_selection = NULL;
3623 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
3624 if(SUCCEEDED(hr))
3626 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
3627 (void**)&This->psia_selection);
3628 if(SUCCEEDED(hr))
3630 fill_filename_from_selection(This);
3631 events_OnSelectionChange(This);
3634 IDataObject_Release(new_selection);
3636 break;
3637 default:
3638 TRACE("Unhandled state change\n");
3640 return S_OK;
3643 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
3644 IShellView *shv, LPCITEMIDLIST pidl)
3646 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3647 IShellItem *psi;
3648 LPWSTR filename;
3649 LPITEMIDLIST parent_pidl;
3650 HRESULT hr;
3651 ULONG attr;
3652 TRACE("%p (%p, %p)\n", This, shv, pidl);
3654 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
3655 return S_OK;
3657 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3658 if(SUCCEEDED(hr))
3660 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3661 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3662 ILFree(parent_pidl);
3663 ILFree(full_pidl);
3665 if(FAILED(hr))
3667 ERR("Failed to get shellitem (%08lx).\n", hr);
3668 return S_OK;
3671 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3672 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3674 IShellItem_Release(psi);
3675 return S_OK;
3678 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
3680 IShellItem_Release(psi);
3681 return S_FALSE;
3684 hr = S_OK;
3685 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
3687 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
3688 hr = S_FALSE;
3689 CoTaskMemFree(filename);
3692 IShellItem_Release(psi);
3693 return hr;
3696 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
3697 IShellView *ppshv, DWORD dwNotifyType)
3699 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3700 FIXME("Stub: %p (%p, 0x%lx)\n", This, ppshv, dwNotifyType);
3701 return E_NOTIMPL;
3704 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
3705 IShellView *pshv,
3706 LPWSTR pszText, int cchMax)
3708 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3709 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
3710 return E_NOTIMPL;
3713 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
3715 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3716 FIXME("Stub: %p (%p)\n", This, pdwFlags);
3717 return E_NOTIMPL;
3720 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
3721 IShellView *pshv, int iColumn)
3723 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3724 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
3725 return E_NOTIMPL;
3728 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
3729 LPWSTR pszFileSpec, int cchFileSpec)
3731 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3732 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
3733 return E_NOTIMPL;
3736 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
3737 IShellView *pshv)
3739 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3740 FIXME("Stub: %p (%p)\n", This, pshv);
3741 return E_NOTIMPL;
3744 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
3745 ICommDlgBrowser3_fnQueryInterface,
3746 ICommDlgBrowser3_fnAddRef,
3747 ICommDlgBrowser3_fnRelease,
3748 ICommDlgBrowser3_fnOnDefaultCommand,
3749 ICommDlgBrowser3_fnOnStateChange,
3750 ICommDlgBrowser3_fnIncludeObject,
3751 ICommDlgBrowser3_fnNotify,
3752 ICommDlgBrowser3_fnGetDefaultMenuText,
3753 ICommDlgBrowser3_fnGetViewFlags,
3754 ICommDlgBrowser3_fnOnColumnClicked,
3755 ICommDlgBrowser3_fnGetCurrentFilter,
3756 ICommDlgBrowser3_fnOnPreviewCreated
3759 /**************************************************************************
3760 * IOleWindow implementation
3762 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
3764 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
3767 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
3769 FileDialogImpl *This = impl_from_IOleWindow(iface);
3770 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3773 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
3775 FileDialogImpl *This = impl_from_IOleWindow(iface);
3776 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3779 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
3781 FileDialogImpl *This = impl_from_IOleWindow(iface);
3782 return IFileDialog2_Release(&This->IFileDialog2_iface);
3785 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
3787 FileDialogImpl *This = impl_from_IOleWindow(iface);
3788 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
3789 return E_NOTIMPL;
3792 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
3794 FileDialogImpl *This = impl_from_IOleWindow(iface);
3795 TRACE("%p (%p)\n", This, phwnd);
3796 *phwnd = This->dlg_hwnd;
3797 return S_OK;
3800 static const IOleWindowVtbl vt_IOleWindow = {
3801 IOleWindow_fnQueryInterface,
3802 IOleWindow_fnAddRef,
3803 IOleWindow_fnRelease,
3804 IOleWindow_fnGetWindow,
3805 IOleWindow_fnContextSensitiveHelp
3808 /**************************************************************************
3809 * IFileDialogCustomize implementation
3811 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3813 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3816 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3817 REFIID riid, void **ppvObject)
3819 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3820 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3823 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3825 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3826 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3829 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3831 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3832 return IFileDialog2_Release(&This->IFileDialog2_iface);
3835 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3836 DWORD dwIDCtl)
3838 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3839 MENUINFO mi;
3840 TRACE("%p (%ld)\n", This, dwIDCtl);
3842 if (This->hmenu_opendropdown || get_cctrl(This, dwIDCtl))
3843 return E_UNEXPECTED;
3845 This->hmenu_opendropdown = CreatePopupMenu();
3847 if (!This->hmenu_opendropdown)
3848 return E_OUTOFMEMORY;
3850 mi.cbSize = sizeof(mi);
3851 mi.fMask = MIM_STYLE;
3852 mi.dwStyle = MNS_NOTIFYBYPOS;
3853 SetMenuInfo(This->hmenu_opendropdown, &mi);
3855 This->cctrl_opendropdown.hwnd = NULL;
3856 This->cctrl_opendropdown.wrapper_hwnd = NULL;
3857 This->cctrl_opendropdown.id = dwIDCtl;
3858 This->cctrl_opendropdown.dlgid = 0;
3859 This->cctrl_opendropdown.type = IDLG_CCTRL_OPENDROPDOWN;
3860 This->cctrl_opendropdown.cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
3861 list_init(&This->cctrl_opendropdown.sub_cctrls);
3862 list_init(&This->cctrl_opendropdown.sub_items);
3864 return S_OK;
3867 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3868 DWORD dwIDCtl,
3869 LPCWSTR pszLabel)
3871 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3872 customctrl *ctrl;
3873 TBBUTTON tbb;
3874 HRESULT hr;
3875 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszLabel);
3877 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3878 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3879 This->cctrl_def_height, &ctrl);
3880 if(SUCCEEDED(hr))
3882 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3883 ctrl->type = IDLG_CCTRL_MENU;
3885 /* Add the actual button with a popup menu. */
3886 tbb.iBitmap = I_IMAGENONE;
3887 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3888 tbb.iString = (DWORD_PTR)pszLabel;
3889 tbb.fsState = TBSTATE_ENABLED;
3890 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3891 tbb.idCommand = 1;
3893 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3896 return hr;
3899 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3900 DWORD dwIDCtl,
3901 LPCWSTR pszLabel)
3903 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3904 customctrl *ctrl;
3905 HRESULT hr;
3906 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszLabel);
3908 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3909 This->cctrl_def_height, &ctrl);
3910 if(SUCCEEDED(hr))
3911 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3913 return hr;
3916 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3917 DWORD dwIDCtl)
3919 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3920 customctrl *ctrl;
3921 HRESULT hr;
3922 TRACE("%p (%ld)\n", This, dwIDCtl);
3924 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3925 This->cctrl_def_height, &ctrl);
3926 if(SUCCEEDED(hr))
3927 ctrl->type = IDLG_CCTRL_COMBOBOX;
3929 return hr;
3932 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3933 DWORD dwIDCtl)
3935 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3936 customctrl *ctrl;
3937 HRESULT hr;
3938 TRACE("%p (%ld)\n", This, dwIDCtl);
3940 hr = cctrl_create_new(This, dwIDCtl, NULL, L"RadioButtonList", 0, 0, 0, &ctrl);
3941 if(SUCCEEDED(hr))
3943 ctrl->type = IDLG_CCTRL_RADIOBUTTONLIST;
3944 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)This);
3947 return hr;
3950 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3951 DWORD dwIDCtl,
3952 LPCWSTR pszLabel,
3953 BOOL bChecked)
3955 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3956 customctrl *ctrl;
3957 HRESULT hr;
3958 TRACE("%p (%ld, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3960 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0,
3961 This->cctrl_def_height, &ctrl);
3962 if(SUCCEEDED(hr))
3964 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3965 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3968 return hr;
3971 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3972 DWORD dwIDCtl,
3973 LPCWSTR pszText)
3975 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3976 customctrl *ctrl;
3977 HRESULT hr;
3978 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszText);
3980 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3981 This->cctrl_def_height, &ctrl);
3982 if(SUCCEEDED(hr))
3983 ctrl->type = IDLG_CCTRL_EDITBOX;
3985 return hr;
3988 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3989 DWORD dwIDCtl)
3991 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3992 customctrl *ctrl;
3993 HRESULT hr;
3994 TRACE("%p (%ld)\n", This, dwIDCtl);
3996 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3997 GetSystemMetrics(SM_CYEDGE), &ctrl);
3998 if(SUCCEEDED(hr))
3999 ctrl->type = IDLG_CCTRL_SEPARATOR;
4001 return hr;
4004 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
4005 DWORD dwIDCtl,
4006 LPCWSTR pszText)
4008 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4009 customctrl *ctrl;
4010 HRESULT hr;
4011 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszText);
4013 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
4014 This->cctrl_def_height, &ctrl);
4015 if(SUCCEEDED(hr))
4016 ctrl->type = IDLG_CCTRL_TEXT;
4018 return hr;
4021 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
4022 DWORD dwIDCtl,
4023 LPCWSTR pszLabel)
4025 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4026 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4027 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszLabel);
4029 if(!ctrl) return E_INVALIDARG;
4031 switch(ctrl->type)
4033 case IDLG_CCTRL_MENU:
4034 case IDLG_CCTRL_PUSHBUTTON:
4035 case IDLG_CCTRL_CHECKBUTTON:
4036 case IDLG_CCTRL_TEXT:
4037 case IDLG_CCTRL_VISUALGROUP:
4038 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
4039 break;
4040 case IDLG_CCTRL_OPENDROPDOWN:
4041 return E_NOTIMPL;
4042 default:
4043 break;
4046 return S_OK;
4049 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
4050 DWORD dwIDCtl,
4051 CDCONTROLSTATEF *pdwState)
4053 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4054 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4055 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pdwState);
4057 if(!ctrl || ctrl->type == IDLG_CCTRL_OPENDROPDOWN) return E_NOTIMPL;
4059 *pdwState = ctrl->cdcstate;
4060 return S_OK;
4063 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
4064 DWORD dwIDCtl,
4065 CDCONTROLSTATEF dwState)
4067 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4068 customctrl *ctrl = get_cctrl(This,dwIDCtl);
4069 TRACE("%p (%ld, %x)\n", This, dwIDCtl, dwState);
4071 if(ctrl && ctrl->hwnd)
4073 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
4075 if(dwState & CDCS_ENABLED)
4076 wndstyle &= ~(WS_DISABLED);
4077 else
4078 wndstyle |= WS_DISABLED;
4080 if(dwState & CDCS_VISIBLE)
4081 wndstyle |= WS_VISIBLE;
4082 else
4083 wndstyle &= ~(WS_VISIBLE);
4085 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
4087 /* We save the state separately since at least one application
4088 * relies on being able to hide a control. */
4089 ctrl->cdcstate = dwState;
4092 return S_OK;
4095 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
4096 DWORD dwIDCtl,
4097 WCHAR **ppszText)
4099 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4100 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4101 WCHAR len, *text;
4102 TRACE("%p (%ld, %p)\n", This, dwIDCtl, ppszText);
4104 if(!ctrl || !ctrl->hwnd || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
4105 return E_FAIL;
4107 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
4108 if(!text) return E_FAIL;
4110 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
4111 *ppszText = text;
4112 return S_OK;
4115 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
4116 DWORD dwIDCtl,
4117 LPCWSTR pszText)
4119 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4120 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4121 TRACE("%p (%ld, %s)\n", This, dwIDCtl, debugstr_w(pszText));
4123 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
4124 return E_FAIL;
4126 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
4127 return S_OK;
4130 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
4131 DWORD dwIDCtl,
4132 BOOL *pbChecked)
4134 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4135 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4136 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pbChecked);
4138 if(ctrl && ctrl->hwnd)
4139 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
4141 return S_OK;
4144 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
4145 DWORD dwIDCtl,
4146 BOOL bChecked)
4148 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4149 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4150 TRACE("%p (%ld, %d)\n", This, dwIDCtl, bChecked);
4152 if(ctrl && ctrl->hwnd)
4153 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
4155 return S_OK;
4158 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
4160 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
4161 UINT i;
4162 if(!count || (count == CB_ERR))
4163 return -1;
4165 for(i = 0; i < count; i++)
4166 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
4167 return i;
4169 TRACE("Item with id %ld not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
4170 return -1;
4173 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
4174 DWORD dwIDCtl,
4175 DWORD dwIDItem,
4176 LPCWSTR pszLabel)
4178 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4179 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4180 HRESULT hr;
4181 TRACE("%p (%ld, %ld, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4183 if(!ctrl) return E_FAIL;
4185 switch(ctrl->type)
4187 case IDLG_CCTRL_COMBOBOX:
4189 UINT index;
4190 cctrl_item* item;
4192 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4194 if (FAILED(hr)) return hr;
4196 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
4197 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
4199 return S_OK;
4201 case IDLG_CCTRL_MENU:
4202 case IDLG_CCTRL_OPENDROPDOWN:
4204 cctrl_item* item;
4205 HMENU hmenu;
4207 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4209 if (FAILED(hr)) return hr;
4211 if (ctrl->type == IDLG_CCTRL_MENU)
4213 TBBUTTON tbb;
4214 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4215 hmenu = (HMENU)tbb.dwData;
4217 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4218 hmenu = This->hmenu_opendropdown;
4220 AppendMenuW(hmenu, MF_STRING, dwIDItem, pszLabel);
4221 return S_OK;
4223 case IDLG_CCTRL_RADIOBUTTONLIST:
4225 cctrl_item* item;
4227 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4229 if (SUCCEEDED(hr))
4231 item->hwnd = CreateWindowExW(0, WC_BUTTONW, pszLabel,
4232 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|BS_RADIOBUTTON|BS_MULTILINE,
4233 0, 0, 0, 0, ctrl->hwnd, ULongToHandle(dwIDItem), COMDLG32_hInstance, 0);
4235 if (!item->hwnd)
4237 ERR("Failed to create radio button\n");
4238 list_remove(&item->entry);
4239 item_free(item);
4240 return E_FAIL;
4244 return hr;
4246 default:
4247 break;
4250 return E_NOINTERFACE; /* win7 */
4253 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
4254 DWORD dwIDCtl,
4255 DWORD dwIDItem)
4257 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4258 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4259 TRACE("%p (%ld, %ld)\n", This, dwIDCtl, dwIDItem);
4261 if(!ctrl) return E_FAIL;
4263 switch(ctrl->type)
4265 case IDLG_CCTRL_COMBOBOX:
4267 cctrl_item* item;
4268 DWORD position;
4270 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4272 if (!item)
4273 return E_INVALIDARG;
4275 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
4277 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0) == CB_ERR)
4278 return E_FAIL;
4281 list_remove(&item->entry);
4282 item_free(item);
4284 return S_OK;
4286 case IDLG_CCTRL_MENU:
4287 case IDLG_CCTRL_OPENDROPDOWN:
4289 HMENU hmenu;
4290 cctrl_item* item;
4292 item = get_item(ctrl, dwIDItem, 0, NULL);
4294 if (!item)
4295 return E_UNEXPECTED;
4297 if (item->cdcstate & CDCS_VISIBLE)
4299 if (ctrl->type == IDLG_CCTRL_MENU)
4301 TBBUTTON tbb;
4302 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4303 hmenu = (HMENU)tbb.dwData;
4305 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4306 hmenu = This->hmenu_opendropdown;
4308 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
4309 return E_UNEXPECTED;
4312 list_remove(&item->entry);
4313 item_free(item);
4315 return S_OK;
4317 case IDLG_CCTRL_RADIOBUTTONLIST:
4319 cctrl_item* item;
4321 item = get_item(ctrl, dwIDItem, 0, NULL);
4323 if (!item)
4324 return E_UNEXPECTED;
4326 list_remove(&item->entry);
4327 item_free(item);
4329 return S_OK;
4331 default:
4332 break;
4335 return E_FAIL;
4338 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
4339 DWORD dwIDCtl)
4341 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4342 TRACE("%p (%ld)\n", This, dwIDCtl);
4344 /* Not implemented by native */
4345 return E_NOTIMPL;
4348 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
4349 DWORD dwIDCtl,
4350 DWORD dwIDItem,
4351 CDCONTROLSTATEF *pdwState)
4353 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4354 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4355 TRACE("%p (%ld, %ld, %p)\n", This, dwIDCtl, dwIDItem, pdwState);
4357 if(!ctrl) return E_FAIL;
4359 switch(ctrl->type)
4361 case IDLG_CCTRL_COMBOBOX:
4362 case IDLG_CCTRL_MENU:
4363 case IDLG_CCTRL_OPENDROPDOWN:
4364 case IDLG_CCTRL_RADIOBUTTONLIST:
4366 cctrl_item* item;
4368 item = get_item(ctrl, dwIDItem, 0, NULL);
4370 if (!item)
4371 return E_UNEXPECTED;
4373 *pdwState = item->cdcstate;
4375 return S_OK;
4377 default:
4378 break;
4381 return E_FAIL;
4384 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
4385 DWORD dwIDCtl,
4386 DWORD dwIDItem,
4387 CDCONTROLSTATEF dwState)
4389 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4390 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4391 TRACE("%p (%ld, %ld, %x)\n", This, dwIDCtl, dwIDItem, dwState);
4393 if(!ctrl) return E_FAIL;
4395 switch(ctrl->type)
4397 case IDLG_CCTRL_COMBOBOX:
4399 cctrl_item* item;
4400 BOOL visible, was_visible;
4401 DWORD position;
4403 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4405 if (!item)
4406 return E_UNEXPECTED;
4408 visible = ((dwState & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4409 was_visible = ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4411 if (visible && !was_visible)
4413 SendMessageW(ctrl->hwnd, CB_INSERTSTRING, position, (LPARAM)item->label);
4414 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, position, dwIDItem);
4416 else if (!visible && was_visible)
4418 SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0);
4421 item->cdcstate = dwState;
4423 return S_OK;
4425 case IDLG_CCTRL_MENU:
4426 case IDLG_CCTRL_OPENDROPDOWN:
4428 HMENU hmenu;
4429 cctrl_item* item;
4430 CDCONTROLSTATEF prev_state;
4431 DWORD position;
4433 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, &position);
4435 if (!item)
4436 return E_UNEXPECTED;
4438 prev_state = item->cdcstate;
4440 if (ctrl->type == IDLG_CCTRL_MENU)
4442 TBBUTTON tbb;
4443 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4444 hmenu = (HMENU)tbb.dwData;
4446 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4447 hmenu = This->hmenu_opendropdown;
4449 if (dwState & CDCS_VISIBLE)
4451 if (prev_state & CDCS_VISIBLE)
4453 /* change state */
4454 EnableMenuItem(hmenu, dwIDItem,
4455 MF_BYCOMMAND|((dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED));
4457 else
4459 /* show item */
4460 MENUITEMINFOW mii;
4462 mii.cbSize = sizeof(mii);
4463 mii.fMask = MIIM_ID|MIIM_STATE|MIIM_STRING;
4464 mii.fState = (dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED;
4465 mii.wID = dwIDItem;
4466 mii.dwTypeData = item->label;
4468 InsertMenuItemW(hmenu, position, TRUE, &mii);
4471 else if (prev_state & CDCS_VISIBLE)
4473 /* hide item */
4474 DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND);
4477 item->cdcstate = dwState;
4479 if (ctrl->type == IDLG_CCTRL_OPENDROPDOWN)
4481 update_control_text(This);
4482 update_layout(This);
4485 return S_OK;
4487 case IDLG_CCTRL_RADIOBUTTONLIST:
4489 cctrl_item* item;
4491 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, NULL);
4493 if (!item)
4494 return E_UNEXPECTED;
4496 /* Oddly, native allows setting this but doesn't seem to do anything with it. */
4497 item->cdcstate = dwState;
4499 return S_OK;
4501 default:
4502 break;
4505 return E_FAIL;
4508 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
4509 DWORD dwIDCtl,
4510 DWORD *pdwIDItem)
4512 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4513 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4514 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pdwIDItem);
4516 if(!ctrl) return E_FAIL;
4518 switch(ctrl->type)
4520 case IDLG_CCTRL_COMBOBOX:
4522 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
4523 if(index == CB_ERR)
4524 return E_FAIL;
4526 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
4527 return S_OK;
4529 case IDLG_CCTRL_OPENDROPDOWN:
4530 if (This->opendropdown_has_selection)
4532 *pdwIDItem = This->opendropdown_selection;
4533 return S_OK;
4535 else
4537 /* Return first enabled item. */
4538 cctrl_item* item = get_first_item(ctrl);
4540 if (item)
4542 *pdwIDItem = item->id;
4543 return S_OK;
4546 WARN("no enabled items in open dropdown\n");
4547 return E_FAIL;
4549 case IDLG_CCTRL_RADIOBUTTONLIST:
4551 cctrl_item* item;
4553 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
4555 if (SendMessageW(item->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED)
4557 *pdwIDItem = item->id;
4558 return S_OK;
4562 WARN("no checked items in radio button list\n");
4563 return E_FAIL;
4565 default:
4566 FIXME("Unsupported control type %d\n", ctrl->type);
4569 return E_NOTIMPL;
4572 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
4573 DWORD dwIDCtl,
4574 DWORD dwIDItem)
4576 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4577 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4578 TRACE("%p (%ld, %ld)\n", This, dwIDCtl, dwIDItem);
4580 if(!ctrl) return E_INVALIDARG;
4582 switch(ctrl->type)
4584 case IDLG_CCTRL_COMBOBOX:
4586 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
4588 if(index == -1)
4589 return E_INVALIDARG;
4591 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
4592 return E_FAIL;
4594 return S_OK;
4596 case IDLG_CCTRL_RADIOBUTTONLIST:
4598 cctrl_item* item;
4600 item = get_item(ctrl, dwIDItem, 0, NULL);
4602 if (item)
4604 radiobuttonlist_set_selected_item(This, ctrl, item);
4605 return S_OK;
4608 return E_INVALIDARG;
4610 default:
4611 FIXME("Unsupported control type %d\n", ctrl->type);
4614 return E_INVALIDARG;
4617 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
4618 DWORD dwIDCtl,
4619 LPCWSTR pszLabel)
4621 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4622 customctrl *vg;
4623 HRESULT hr;
4624 TRACE("%p (%ld, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
4626 if(This->cctrl_active_vg)
4627 return E_UNEXPECTED;
4629 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0,
4630 This->cctrl_def_height, &vg);
4631 if(SUCCEEDED(hr))
4633 vg->type = IDLG_CCTRL_VISUALGROUP;
4634 This->cctrl_active_vg = vg;
4637 return hr;
4640 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
4642 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4643 TRACE("%p\n", This);
4645 This->cctrl_active_vg = NULL;
4647 return S_OK;
4650 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
4651 DWORD dwIDCtl)
4653 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4654 FIXME("stub - %p (%ld)\n", This, dwIDCtl);
4655 return S_OK;
4658 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
4659 DWORD dwIDCtl,
4660 DWORD dwIDItem,
4661 LPCWSTR pszLabel)
4663 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4664 FIXME("stub - %p (%ld, %ld, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4665 return E_NOTIMPL;
4668 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
4669 IFileDialogCustomize_fnQueryInterface,
4670 IFileDialogCustomize_fnAddRef,
4671 IFileDialogCustomize_fnRelease,
4672 IFileDialogCustomize_fnEnableOpenDropDown,
4673 IFileDialogCustomize_fnAddMenu,
4674 IFileDialogCustomize_fnAddPushButton,
4675 IFileDialogCustomize_fnAddComboBox,
4676 IFileDialogCustomize_fnAddRadioButtonList,
4677 IFileDialogCustomize_fnAddCheckButton,
4678 IFileDialogCustomize_fnAddEditBox,
4679 IFileDialogCustomize_fnAddSeparator,
4680 IFileDialogCustomize_fnAddText,
4681 IFileDialogCustomize_fnSetControlLabel,
4682 IFileDialogCustomize_fnGetControlState,
4683 IFileDialogCustomize_fnSetControlState,
4684 IFileDialogCustomize_fnGetEditBoxText,
4685 IFileDialogCustomize_fnSetEditBoxText,
4686 IFileDialogCustomize_fnGetCheckButtonState,
4687 IFileDialogCustomize_fnSetCheckButtonState,
4688 IFileDialogCustomize_fnAddControlItem,
4689 IFileDialogCustomize_fnRemoveControlItem,
4690 IFileDialogCustomize_fnRemoveAllControlItems,
4691 IFileDialogCustomize_fnGetControlItemState,
4692 IFileDialogCustomize_fnSetControlItemState,
4693 IFileDialogCustomize_fnGetSelectedControlItem,
4694 IFileDialogCustomize_fnSetSelectedControlItem,
4695 IFileDialogCustomize_fnStartVisualGroup,
4696 IFileDialogCustomize_fnEndVisualGroup,
4697 IFileDialogCustomize_fnMakeProminent,
4698 IFileDialogCustomize_fnSetControlItemText
4701 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
4703 FileDialogImpl *fdimpl;
4704 HRESULT hr;
4705 IShellFolder *psf;
4706 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
4708 if(!ppv)
4709 return E_POINTER;
4710 if(pUnkOuter)
4711 return CLASS_E_NOAGGREGATION;
4713 fdimpl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FileDialogImpl));
4714 if(!fdimpl)
4715 return E_OUTOFMEMORY;
4717 fdimpl->ref = 1;
4718 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
4719 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
4720 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
4721 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
4722 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
4723 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
4725 if(type == ITEMDLG_TYPE_OPEN)
4727 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
4728 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
4729 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
4730 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
4732 else
4734 WCHAR buf[16];
4735 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
4736 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
4737 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
4739 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, ARRAY_SIZE(buf));
4740 fdimpl->custom_title = StrDupW(buf);
4741 fdimpl->custom_okbutton = StrDupW(buf);
4744 list_init(&fdimpl->events_clients);
4746 /* FIXME: The default folder setting should be restored for the
4747 * application if it was previously set. */
4748 SHGetDesktopFolder(&psf);
4749 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
4750 IShellFolder_Release(psf);
4752 hr = init_custom_controls(fdimpl);
4753 if(FAILED(hr))
4755 ERR("Failed to initialize custom controls (0x%08lx).\n", hr);
4756 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4757 return E_FAIL;
4760 fdimpl->user_actctx = INVALID_HANDLE_VALUE;
4762 hr = IFileDialog2_QueryInterface(&fdimpl->IFileDialog2_iface, riid, ppv);
4763 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4764 return hr;
4767 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4769 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
4772 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4774 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);