TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / comdlg32 / itemdlg.c
blobf9a7707048f0308704413f349a2d27634447a5fc
1 /*
2 * Common Item Dialog
4 * Copyright 2010,2011 David Hedberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "wingdi.h"
30 #include "winreg.h"
31 #include "shlwapi.h"
33 #include "commdlg.h"
34 #include "cdlg.h"
35 #include "filedlgbrowser.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
40 #define IDC_NAV_TOOLBAR 200
41 #define IDC_NAVBACK 201
42 #define IDC_NAVFORWARD 202
44 #include <initguid.h>
45 /* This seems to be another version of IID_IFileDialogCustomize. If
46 * there is any difference I have yet to find it. */
47 DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F);
49 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
51 static const WCHAR notifysink_childW[] = {'n','f','s','_','c','h','i','l','d',0};
52 static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0};
53 static const WCHAR radiobuttonlistW[] = {'R','a','d','i','o','B','u','t','t','o','n','L','i','s','t',0};
55 enum ITEMDLG_TYPE {
56 ITEMDLG_TYPE_OPEN,
57 ITEMDLG_TYPE_SAVE
60 enum ITEMDLG_CCTRL_TYPE {
61 IDLG_CCTRL_MENU,
62 IDLG_CCTRL_PUSHBUTTON,
63 IDLG_CCTRL_COMBOBOX,
64 IDLG_CCTRL_RADIOBUTTONLIST,
65 IDLG_CCTRL_CHECKBUTTON,
66 IDLG_CCTRL_EDITBOX,
67 IDLG_CCTRL_SEPARATOR,
68 IDLG_CCTRL_TEXT,
69 IDLG_CCTRL_OPENDROPDOWN,
70 IDLG_CCTRL_VISUALGROUP
73 typedef struct cctrl_item {
74 DWORD id, parent_id;
75 LPWSTR label;
76 CDCONTROLSTATEF cdcstate;
77 HWND hwnd;
78 struct list entry;
79 } cctrl_item;
81 typedef struct {
82 HWND hwnd, wrapper_hwnd;
83 UINT id, dlgid;
84 enum ITEMDLG_CCTRL_TYPE type;
85 CDCONTROLSTATEF cdcstate;
86 struct list entry;
88 struct list sub_cctrls;
89 struct list sub_cctrls_entry;
90 struct list sub_items;
91 } customctrl;
93 typedef struct {
94 struct list entry;
95 IFileDialogEvents *pfde;
96 DWORD cookie;
97 } events_client;
99 typedef struct FileDialogImpl {
100 IFileDialog2 IFileDialog2_iface;
101 union {
102 IFileOpenDialog IFileOpenDialog_iface;
103 IFileSaveDialog IFileSaveDialog_iface;
104 } u;
105 enum ITEMDLG_TYPE dlg_type;
106 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
107 IServiceProvider IServiceProvider_iface;
108 ICommDlgBrowser3 ICommDlgBrowser3_iface;
109 IOleWindow IOleWindow_iface;
110 IFileDialogCustomize IFileDialogCustomize_iface;
111 LONG ref;
113 FILEOPENDIALOGOPTIONS options;
114 COMDLG_FILTERSPEC *filterspecs;
115 UINT filterspec_count;
116 UINT filetypeindex;
118 struct list events_clients;
119 DWORD events_next_cookie;
121 IShellItemArray *psia_selection;
122 IShellItemArray *psia_results;
123 IShellItem *psi_defaultfolder;
124 IShellItem *psi_setfolder;
125 IShellItem *psi_folder;
127 HWND dlg_hwnd;
128 IExplorerBrowser *peb;
129 DWORD ebevents_cookie;
131 LPWSTR set_filename;
132 LPWSTR default_ext;
133 LPWSTR custom_title;
134 LPWSTR custom_okbutton;
135 LPWSTR custom_cancelbutton;
136 LPWSTR custom_filenamelabel;
138 UINT cctrl_width, cctrl_def_height, cctrls_cols;
139 UINT cctrl_indent;
140 HWND cctrls_hwnd;
141 struct list cctrls;
142 UINT_PTR cctrl_next_dlgid;
143 customctrl *cctrl_active_vg;
145 HMENU hmenu_opendropdown;
146 customctrl cctrl_opendropdown;
147 HFONT hfont_opendropdown;
148 BOOL opendropdown_has_selection;
149 DWORD opendropdown_selection;
151 GUID client_guid;
152 } FileDialogImpl;
154 /**************************************************************************
155 * Event wrappers.
157 static HRESULT events_OnFileOk(FileDialogImpl *This)
159 events_client *cursor;
160 HRESULT hr = S_OK;
161 TRACE("%p\n", This);
163 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
165 TRACE("Notifying %p\n", cursor);
166 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
167 if(FAILED(hr) && hr != E_NOTIMPL)
168 break;
171 if(hr == E_NOTIMPL)
172 hr = S_OK;
174 return hr;
177 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
179 events_client *cursor;
180 HRESULT hr = S_OK;
181 TRACE("%p (%p)\n", This, folder);
183 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
185 TRACE("Notifying %p\n", cursor);
186 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
187 if(FAILED(hr) && hr != E_NOTIMPL)
188 break;
191 if(hr == E_NOTIMPL)
192 hr = S_OK;
194 return hr;
197 static void events_OnFolderChange(FileDialogImpl *This)
199 events_client *cursor;
200 TRACE("%p\n", This);
202 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
204 TRACE("Notifying %p\n", cursor);
205 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
209 static void events_OnSelectionChange(FileDialogImpl *This)
211 events_client *cursor;
212 TRACE("%p\n", This);
214 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
216 TRACE("Notifying %p\n", cursor);
217 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
221 static void events_OnTypeChange(FileDialogImpl *This)
223 events_client *cursor;
224 TRACE("%p\n", This);
226 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
228 TRACE("Notifying %p\n", cursor);
229 IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
233 static HRESULT events_OnOverwrite(FileDialogImpl *This, IShellItem *shellitem)
235 events_client *cursor;
236 HRESULT hr = S_OK;
237 FDE_OVERWRITE_RESPONSE response = FDEOR_DEFAULT;
238 TRACE("%p %p\n", This, shellitem);
240 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
242 TRACE("Notifying %p\n", cursor);
243 hr = IFileDialogEvents_OnOverwrite(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, shellitem, &response);
244 TRACE("<-- hr=%x response=%u\n", hr, response);
245 if(FAILED(hr) && hr != E_NOTIMPL)
246 break;
249 if(hr == E_NOTIMPL)
250 hr = S_OK;
252 if(SUCCEEDED(hr))
254 if (response == FDEOR_DEFAULT)
256 WCHAR buf[100];
257 int answer;
259 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, buf, 100);
260 answer = MessageBoxW(This->dlg_hwnd, buf, This->custom_title,
261 MB_YESNO | MB_ICONEXCLAMATION);
262 if (answer == IDNO || answer == IDCANCEL)
264 hr = E_FAIL;
267 else if (response == FDEOR_REFUSE)
268 hr = E_FAIL;
271 return hr;
274 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
276 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
279 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
281 events_client *cursor;
282 TRACE("%p\n", This);
284 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
286 IFileDialogControlEvents *pfdce;
287 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
289 TRACE("Notifying %p\n", cursor);
290 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
291 IFileDialogControlEvents_Release(pfdce);
295 return S_OK;
298 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
300 events_client *cursor;
301 TRACE("%p %i %i\n", This, ctl_id, item_id);
303 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
305 IFileDialogControlEvents *pfdce;
306 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
308 TRACE("Notifying %p\n", cursor);
309 IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
310 IFileDialogControlEvents_Release(pfdce);
314 return S_OK;
317 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
319 events_client *cursor;
320 TRACE("%p\n", This);
322 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
324 IFileDialogControlEvents *pfdce;
325 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
327 TRACE("Notifying %p\n", cursor);
328 IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
329 IFileDialogControlEvents_Release(pfdce);
333 return S_OK;
336 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
337 DWORD ctl_id)
339 events_client *cursor;
340 TRACE("%p\n", This);
342 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
344 IFileDialogControlEvents *pfdce;
345 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
347 TRACE("Notifying %p\n", cursor);
348 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
349 IFileDialogControlEvents_Release(pfdce);
353 return S_OK;
356 /**************************************************************************
357 * Helper functions.
359 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
361 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
362 UINT len;
364 if(!hwnd_edit)
366 if(This->set_filename)
368 len = lstrlenW(This->set_filename);
369 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
370 lstrcpyW(*str, This->set_filename);
371 return len;
373 return FALSE;
376 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
377 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
378 if(!*str)
379 return FALSE;
381 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
382 return len;
385 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
387 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
389 if(This->set_filename)
390 LocalFree(This->set_filename);
392 This->set_filename = StrDupW(str);
394 return SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str);
397 static void fill_filename_from_selection(FileDialogImpl *This)
399 IShellItem *psi;
400 LPWSTR *names;
401 HRESULT hr;
402 UINT item_count, valid_count;
403 UINT len_total, i;
405 if(!This->psia_selection)
406 return;
408 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
409 if(FAILED(hr) || !item_count)
410 return;
412 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
414 /* Get names of the selected items */
415 valid_count = 0; len_total = 0;
416 for(i = 0; i < item_count; i++)
418 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
419 if(SUCCEEDED(hr))
421 UINT attr;
423 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
424 if(SUCCEEDED(hr) &&
425 (( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
426 (!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
427 continue;
429 hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
430 if(SUCCEEDED(hr))
432 len_total += lstrlenW(names[valid_count]) + 3;
433 valid_count++;
435 IShellItem_Release(psi);
439 if(valid_count == 1)
441 set_file_name(This, names[0]);
442 CoTaskMemFree(names[0]);
444 else if(valid_count > 1)
446 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
447 LPWSTR cur_point = string;
449 for(i = 0; i < valid_count; i++)
451 LPWSTR file = names[i];
452 *cur_point++ = '\"';
453 lstrcpyW(cur_point, file);
454 cur_point += lstrlenW(file);
455 *cur_point++ = '\"';
456 *cur_point++ = ' ';
457 CoTaskMemFree(file);
459 *(cur_point-1) = '\0';
461 set_file_name(This, string);
462 HeapFree(GetProcessHeap(), 0, string);
465 HeapFree(GetProcessHeap(), 0, names);
466 return;
469 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
471 WCHAR *endpos, *ext;
473 lstrcpyW(buf, spec);
474 if( (endpos = StrChrW(buf, ';')) )
475 *endpos = '\0';
477 ext = PathFindExtensionW(buf);
478 if(StrChrW(ext, '*'))
479 return NULL;
481 return ext;
484 static BOOL shell_item_exists(IShellItem* shellitem)
486 LPWSTR filename;
487 HRESULT hr;
488 BOOL result;
490 hr = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &filename);
491 if (SUCCEEDED(hr))
493 /* FIXME: Implement SFGAO_VALIDATE in Wine and use it instead. */
494 result = (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES);
495 CoTaskMemFree(filename);
497 else
499 SFGAOF attributes;
500 result = SUCCEEDED(IShellItem_GetAttributes(shellitem, SFGAO_VALIDATE, &attributes));
503 return result;
506 static HRESULT on_default_action(FileDialogImpl *This)
508 IShellFolder *psf_parent, *psf_desktop;
509 LPITEMIDLIST *pidla;
510 LPITEMIDLIST current_folder;
511 LPWSTR fn_iter, files = NULL, tmp_files;
512 UINT file_count = 0, len, i;
513 int open_action;
514 HRESULT hr, ret = E_FAIL;
516 len = get_file_name(This, &tmp_files);
517 if(len)
519 UINT size_used;
520 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
521 CoTaskMemFree(tmp_files);
523 if(!file_count) return E_FAIL;
525 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
526 if(FAILED(hr))
528 ERR("Failed to get pidl for current directory.\n");
529 HeapFree(GetProcessHeap(), 0, files);
530 return hr;
533 TRACE("Acting on %d file(s).\n", file_count);
535 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
536 open_action = ONOPEN_OPEN;
537 fn_iter = files;
539 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
541 WCHAR canon_filename[MAX_PATH];
542 psf_parent = NULL;
544 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
546 if( (This->options & FOS_NOVALIDATE) &&
547 !(This->options & FOS_FILEMUSTEXIST) )
548 open_action = ONOPEN_OPEN;
549 else
550 open_action = ONOPEN_BROWSE;
552 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
553 This->options & ~FOS_FILEMUSTEXIST,
554 (This->dlg_type == ITEMDLG_TYPE_SAVE),
555 open_action);
557 /* Add the proper extension */
558 if(open_action == ONOPEN_OPEN)
560 static const WCHAR dotW[] = {'.',0};
562 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
564 WCHAR extbuf[MAX_PATH], *newext = NULL;
566 if(This->filterspec_count)
568 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
570 else if(This->default_ext)
572 lstrcpyW(extbuf, dotW);
573 lstrcatW(extbuf, This->default_ext);
574 newext = extbuf;
577 if(newext)
579 WCHAR *ext = PathFindExtensionW(canon_filename);
580 if(lstrcmpW(ext, newext))
581 lstrcatW(canon_filename, newext);
584 else
586 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
587 !PathFileExistsW(canon_filename))
589 if(This->default_ext)
591 lstrcatW(canon_filename, dotW);
592 lstrcatW(canon_filename, This->default_ext);
594 if(!PathFileExistsW(canon_filename))
596 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
597 open_action = ONOPEN_BROWSE;
600 else
602 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
603 open_action = ONOPEN_BROWSE;
609 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
611 if(psf_parent && !(open_action == ONOPEN_BROWSE))
612 IShellFolder_Release(psf_parent);
614 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
617 HeapFree(GetProcessHeap(), 0, files);
618 ILFree(current_folder);
620 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
621 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
623 switch(open_action)
625 case ONOPEN_SEARCH:
626 FIXME("Filtering not implemented.\n");
627 break;
629 case ONOPEN_BROWSE:
630 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
631 if(FAILED(hr))
632 ERR("Failed to browse to directory: %08x\n", hr);
634 IShellFolder_Release(psf_parent);
635 break;
637 case ONOPEN_OPEN:
638 hr = SHGetDesktopFolder(&psf_desktop);
639 if(SUCCEEDED(hr))
641 if(This->psia_results)
643 IShellItemArray_Release(This->psia_results);
644 This->psia_results = NULL;
647 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
648 &This->psia_results);
650 IShellFolder_Release(psf_desktop);
652 if(FAILED(hr))
653 break;
655 if(This->options & FOS_PICKFOLDERS)
657 SFGAOF attributes;
658 hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
659 if(hr != S_OK)
661 WCHAR buf[64];
662 LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, sizeof(buf)/sizeof(WCHAR));
664 MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
666 IShellItemArray_Release(This->psia_results);
667 This->psia_results = NULL;
668 break;
672 if((This->options & FOS_OVERWRITEPROMPT) && This->dlg_type == ITEMDLG_TYPE_SAVE)
674 IShellItem *shellitem;
676 for (i=0; SUCCEEDED(hr) && i<file_count; i++)
678 hr = IShellItemArray_GetItemAt(This->psia_results, i, &shellitem);
679 if (SUCCEEDED(hr))
681 if (shell_item_exists(shellitem))
682 hr = events_OnOverwrite(This, shellitem);
684 IShellItem_Release(shellitem);
688 if (FAILED(hr))
689 break;
692 if(events_OnFileOk(This) == S_OK)
693 ret = S_OK;
695 break;
697 default:
698 ERR("Failed.\n");
699 break;
702 /* Clean up */
703 for(i = 0; i < file_count; i++)
704 ILFree(pidla[i]);
705 HeapFree(GetProcessHeap(), 0, pidla);
707 /* Success closes the dialog */
708 return ret;
711 static void show_opendropdown(FileDialogImpl *This)
713 HWND open_hwnd;
714 RECT open_rc;
715 MSG msg;
717 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
719 GetWindowRect(open_hwnd, &open_rc);
721 if (TrackPopupMenu(This->hmenu_opendropdown, 0, open_rc.left, open_rc.bottom, 0, This->dlg_hwnd, NULL) &&
722 PeekMessageW(&msg, This->dlg_hwnd, WM_MENUCOMMAND, WM_MENUCOMMAND, PM_REMOVE))
724 MENUITEMINFOW mii;
726 This->opendropdown_has_selection = TRUE;
728 mii.cbSize = sizeof(mii);
729 mii.fMask = MIIM_ID;
730 GetMenuItemInfoW((HMENU)msg.lParam, msg.wParam, TRUE, &mii);
731 This->opendropdown_selection = mii.wID;
733 if(SUCCEEDED(on_default_action(This)))
734 EndDialog(This->dlg_hwnd, S_OK);
735 else
736 This->opendropdown_has_selection = FALSE;
740 /**************************************************************************
741 * Control item functions.
744 static void item_free(cctrl_item *item)
746 DestroyWindow(item->hwnd);
747 HeapFree(GetProcessHeap(), 0, item->label);
748 HeapFree(GetProcessHeap(), 0, item);
751 static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF visible_flags, DWORD* position)
753 DWORD dummy;
754 cctrl_item* item;
756 if (!position) position = &dummy;
758 *position = 0;
760 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
762 if (item->id == itemid)
763 return item;
765 if ((item->cdcstate & visible_flags) == visible_flags)
766 (*position)++;
769 return NULL;
772 static cctrl_item* get_first_item(customctrl* parent)
774 cctrl_item* item;
776 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
778 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
779 return item;
782 return NULL;
785 static HRESULT add_item(customctrl* parent, DWORD itemid, LPCWSTR label, cctrl_item** result)
787 cctrl_item* item;
788 LPWSTR label_copy;
790 if (get_item(parent, itemid, 0, NULL))
791 return E_INVALIDARG;
793 item = HeapAlloc(GetProcessHeap(), 0, sizeof(*item));
794 label_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(label)+1)*sizeof(WCHAR));
796 if (!item || !label_copy)
798 HeapFree(GetProcessHeap(), 0, item);
799 HeapFree(GetProcessHeap(), 0, label_copy);
800 return E_OUTOFMEMORY;
803 item->id = itemid;
804 item->parent_id = parent->id;
805 lstrcpyW(label_copy, label);
806 item->label = label_copy;
807 item->cdcstate = CDCS_VISIBLE|CDCS_ENABLED;
808 item->hwnd = NULL;
809 list_add_tail(&parent->sub_items, &item->entry);
811 *result = item;
813 return S_OK;
816 /**************************************************************************
817 * Control functions.
819 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
821 customctrl *ctrl, *sub_ctrl;
823 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
825 if(ctrl->dlgid == dlgid)
826 return ctrl;
828 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
829 if(sub_ctrl->dlgid == dlgid)
830 return sub_ctrl;
833 ERR("Failed to find control with dialog id %d\n", dlgid);
834 return NULL;
837 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
839 customctrl *ctrl, *sub_ctrl;
841 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
843 if(ctrl->id == ctlid)
844 return ctrl;
846 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
847 if(sub_ctrl->id == ctlid)
848 return sub_ctrl;
851 if (This->hmenu_opendropdown && This->cctrl_opendropdown.id == ctlid)
852 return &This->cctrl_opendropdown;
854 TRACE("No existing control with control id %d\n", ctlid);
855 return NULL;
858 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
860 LPWSTR text;
861 UINT len, final_width;
862 UINT lines, final_height;
863 SIZE size;
864 RECT rc;
865 HDC hdc;
866 WCHAR *c;
868 TRACE("\n");
870 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
871 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
872 if(!text) return;
873 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
875 hdc = GetDC(hctrl);
876 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
877 ReleaseDC(hctrl, hdc);
879 if(len && multiline)
881 /* FIXME: line-wrap */
882 for(lines = 1, c = text; *c != '\0'; c++)
883 if(*c == '\n') lines++;
885 final_height = size.cy*lines + 2*4;
887 else
889 GetWindowRect(hctrl, &rc);
890 final_height = rc.bottom - rc.top;
893 final_width = min(max(size.cx, min_width) + 4, max_width);
894 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
895 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
897 HeapFree(GetProcessHeap(), 0, text);
900 static UINT ctrl_get_height(customctrl *ctrl) {
901 RECT rc;
902 GetWindowRect(ctrl->wrapper_hwnd, &rc);
903 return rc.bottom - rc.top;
906 static void ctrl_free(customctrl *ctrl)
908 customctrl *sub_cur1, *sub_cur2;
909 cctrl_item *item_cur1, *item_cur2;
911 TRACE("Freeing control %p\n", ctrl);
912 if(ctrl->type == IDLG_CCTRL_MENU)
914 TBBUTTON tbb;
915 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
916 DestroyMenu((HMENU)tbb.dwData);
919 LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
921 list_remove(&sub_cur1->sub_cctrls_entry);
922 ctrl_free(sub_cur1);
925 LIST_FOR_EACH_ENTRY_SAFE(item_cur1, item_cur2, &ctrl->sub_items, cctrl_item, entry)
927 list_remove(&item_cur1->entry);
928 item_free(item_cur1);
931 DestroyWindow(ctrl->hwnd);
932 HeapFree(GetProcessHeap(), 0, ctrl);
935 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
937 RECT rc;
938 UINT total_height;
939 UINT max_width;
940 customctrl *sub_ctrl;
942 switch(ctrl->type)
944 case IDLG_CCTRL_PUSHBUTTON:
945 case IDLG_CCTRL_COMBOBOX:
946 case IDLG_CCTRL_CHECKBUTTON:
947 case IDLG_CCTRL_TEXT:
948 ctrl_resize(ctrl->hwnd, 160, 160, TRUE);
949 GetWindowRect(ctrl->hwnd, &rc);
950 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
951 SWP_NOZORDER|SWP_NOMOVE);
952 break;
953 case IDLG_CCTRL_VISUALGROUP:
954 total_height = 0;
955 ctrl_resize(ctrl->hwnd, 0, This->cctrl_indent, TRUE);
957 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
959 customctrl_resize(This, sub_ctrl);
960 SetWindowPos(sub_ctrl->wrapper_hwnd, NULL, This->cctrl_indent, total_height, 0, 0,
961 SWP_NOZORDER|SWP_NOSIZE);
963 total_height += ctrl_get_height(sub_ctrl);
966 /* The label should be right adjusted */
968 UINT width, height;
970 GetWindowRect(ctrl->hwnd, &rc);
971 width = rc.right - rc.left;
972 height = rc.bottom - rc.top;
974 SetWindowPos(ctrl->hwnd, NULL, This->cctrl_indent - width, 0, width, height, SWP_NOZORDER);
977 /* Resize the wrapper window to fit all the sub controls */
978 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, This->cctrl_width + This->cctrl_indent, total_height,
979 SWP_NOZORDER|SWP_NOMOVE);
980 break;
981 case IDLG_CCTRL_RADIOBUTTONLIST:
983 cctrl_item* item;
985 total_height = 0;
986 max_width = 0;
988 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
990 ctrl_resize(item->hwnd, 160, 160, TRUE);
991 SetWindowPos(item->hwnd, NULL, 0, total_height, 0, 0,
992 SWP_NOZORDER|SWP_NOSIZE);
994 GetWindowRect(item->hwnd, &rc);
996 total_height += rc.bottom - rc.top;
997 max_width = max(rc.right - rc.left, max_width);
1000 SetWindowPos(ctrl->hwnd, NULL, 0, 0, max_width, total_height,
1001 SWP_NOZORDER|SWP_NOMOVE);
1003 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, max_width, total_height,
1004 SWP_NOZORDER|SWP_NOMOVE);
1006 break;
1008 case IDLG_CCTRL_EDITBOX:
1009 case IDLG_CCTRL_SEPARATOR:
1010 case IDLG_CCTRL_MENU:
1011 case IDLG_CCTRL_OPENDROPDOWN:
1012 /* Nothing */
1013 break;
1017 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
1019 FileDialogImpl *This = crs->lpCreateParams;
1020 TRACE("%p\n", This);
1022 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1023 return TRUE;
1026 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1028 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1030 TRACE("%p, %lx\n", This, wparam);
1032 if(ctrl)
1034 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
1036 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
1037 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
1039 else
1040 cctrl_event_OnButtonClicked(This, ctrl->id);
1043 return TRUE;
1046 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1048 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1049 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
1051 if(ctrl)
1053 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
1054 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
1056 cctrl_event_OnItemSelected(This, ctrl->id, selid);
1058 return TRUE;
1061 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
1063 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
1064 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
1065 POINT pt = { 0, nmtb->rcButton.bottom };
1066 TBBUTTON tbb;
1067 UINT idcmd;
1069 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
1071 if(ctrl)
1073 cctrl_event_OnControlActivating(This,ctrl->id);
1075 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1076 ClientToScreen(ctrl->hwnd, &pt);
1077 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
1078 if(idcmd)
1079 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
1082 return TBDDRET_DEFAULT;
1085 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1087 switch(HIWORD(wparam))
1089 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
1090 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
1093 return FALSE;
1096 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1098 NMHDR *nmhdr = (NMHDR*)lparam;
1100 switch(nmhdr->code)
1102 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
1105 return FALSE;
1108 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1110 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1111 customctrl *ctrl;
1112 HWND hwnd_child;
1113 RECT rc;
1115 switch(message)
1117 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
1118 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
1119 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
1120 case WM_SIZE:
1121 hwnd_child = GetPropW(hwnd, notifysink_childW);
1122 ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA);
1123 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
1125 GetClientRect(hwnd, &rc);
1126 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1128 return TRUE;
1131 return DefWindowProcW(hwnd, message, wparam, lparam);
1134 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
1135 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
1136 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
1138 HWND ns_hwnd, control_hwnd, parent_hwnd;
1139 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
1140 customctrl *ctrl;
1142 if(get_cctrl(This, id))
1143 return E_UNEXPECTED; /* Duplicate id */
1145 if(This->cctrl_active_vg)
1146 parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
1147 else
1148 parent_hwnd = This->cctrls_hwnd;
1150 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
1151 0, 0, This->cctrl_width, height, parent_hwnd,
1152 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
1153 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
1154 0, 0, This->cctrl_width, height, ns_hwnd,
1155 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
1157 if(!ns_hwnd || !control_hwnd)
1159 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
1160 DestroyWindow(ns_hwnd);
1161 DestroyWindow(control_hwnd);
1163 return E_FAIL;
1166 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
1168 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
1169 if(!ctrl)
1170 return E_OUTOFMEMORY;
1172 ctrl->hwnd = control_hwnd;
1173 ctrl->wrapper_hwnd = ns_hwnd;
1174 ctrl->id = id;
1175 ctrl->dlgid = This->cctrl_next_dlgid;
1176 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
1177 list_init(&ctrl->sub_cctrls);
1178 list_init(&ctrl->sub_items);
1180 if(This->cctrl_active_vg)
1181 list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
1182 else
1183 list_add_tail(&This->cctrls, &ctrl->entry);
1185 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl);
1187 if(ppctrl) *ppctrl = ctrl;
1189 This->cctrl_next_dlgid++;
1190 return S_OK;
1193 /**************************************************************************
1194 * Container functions.
1196 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
1198 UINT container_height;
1199 UINT column_width;
1200 UINT nr_of_cols;
1201 UINT max_control_height, total_height = 0;
1202 UINT cur_col_pos, cur_row_pos;
1203 customctrl *ctrl;
1204 BOOL fits_height;
1205 static const UINT cspacing = 90; /* Columns are spaced with 90px */
1206 static const UINT rspacing = 4; /* Rows are spaced with 4 px. */
1208 /* Given the new width of the container, this function determines the
1209 * needed height of the container and places the controls according to
1210 * the new layout. Returns the new height.
1213 TRACE("%p\n", This);
1215 column_width = This->cctrl_width + cspacing;
1216 nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
1218 /* We don't need to do anything unless the number of visible columns has changed. */
1219 if(nr_of_cols == This->cctrls_cols)
1221 RECT rc;
1222 GetWindowRect(This->cctrls_hwnd, &rc);
1223 return rc.bottom - rc.top;
1226 This->cctrls_cols = nr_of_cols;
1228 /* Get the size of the tallest control, and the total size of
1229 * all the controls to figure out the number of slots we need.
1231 max_control_height = 0;
1232 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1234 if(ctrl->cdcstate & CDCS_VISIBLE)
1236 UINT control_height = ctrl_get_height(ctrl);
1237 max_control_height = max(max_control_height, control_height);
1239 total_height += control_height + rspacing;
1243 if(!total_height)
1244 return 0;
1246 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
1247 TRACE("Guess: container_height: %d\n",container_height);
1249 /* Incrementally increase container_height until all the controls
1250 * fit.
1252 do {
1253 UINT columns_needed = 1;
1254 cur_row_pos = 0;
1256 fits_height = TRUE;
1257 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1259 if(ctrl->cdcstate & CDCS_VISIBLE)
1261 UINT control_height = ctrl_get_height(ctrl);
1263 if(cur_row_pos + control_height > container_height)
1265 if(++columns_needed > nr_of_cols)
1267 container_height += 1;
1268 fits_height = FALSE;
1269 break;
1271 cur_row_pos = 0;
1274 cur_row_pos += control_height + rspacing;
1277 } while(!fits_height);
1279 TRACE("Final container height: %d\n", container_height);
1281 /* Move the controls to their final destination
1283 cur_col_pos = 0, cur_row_pos = 0;
1284 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1286 if(ctrl->cdcstate & CDCS_VISIBLE)
1288 RECT rc;
1289 UINT control_height, control_indent;
1290 GetWindowRect(ctrl->wrapper_hwnd, &rc);
1291 control_height = rc.bottom - rc.top;
1293 if(cur_row_pos + control_height > container_height)
1295 cur_row_pos = 0;
1296 cur_col_pos += This->cctrl_width + cspacing;
1300 if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
1301 control_indent = 0;
1302 else
1303 control_indent = This->cctrl_indent;
1305 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
1306 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1308 cur_row_pos += control_height + rspacing;
1312 /* Sanity check */
1313 if(cur_row_pos + This->cctrl_width > container_width)
1314 ERR("-- Failed to place controls properly.\n");
1316 return container_height;
1319 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
1321 LONG wndstyle;
1323 if(parent)
1325 customctrl *ctrl, *sub_ctrl;
1326 HFONT font;
1328 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1329 wndstyle &= ~(WS_POPUP);
1330 wndstyle |= WS_CHILD;
1331 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1333 SetParent(This->cctrls_hwnd, parent);
1334 ShowWindow(This->cctrls_hwnd, TRUE);
1336 /* Set the fonts to match the dialog font. */
1337 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
1338 if(!font)
1339 ERR("Failed to get font handle from dialog.\n");
1341 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1343 if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1345 /* If this is a VisualGroup */
1346 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1348 if(font) SendMessageW(sub_ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1351 if (ctrl->type == IDLG_CCTRL_RADIOBUTTONLIST)
1353 cctrl_item* item;
1354 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1356 if (font) SendMessageW(item->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1360 customctrl_resize(This, ctrl);
1363 else
1365 ShowWindow(This->cctrls_hwnd, FALSE);
1367 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1368 wndstyle &= ~(WS_CHILD);
1369 wndstyle |= WS_POPUP;
1370 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1372 SetParent(This->cctrls_hwnd, NULL);
1376 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
1378 FileDialogImpl *This = crs->lpCreateParams;
1379 TRACE("%p\n", This);
1381 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1382 return TRUE;
1385 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
1387 customctrl *cur1, *cur2;
1388 TRACE("%p\n", This);
1390 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1392 list_remove(&cur1->entry);
1393 ctrl_free(cur1);
1396 return TRUE;
1399 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1401 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1403 switch(umessage)
1405 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1406 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1407 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1410 return FALSE;
1413 static void radiobuttonlist_set_selected_item(FileDialogImpl *This, customctrl *ctrl, cctrl_item *item)
1415 cctrl_item *cursor;
1417 LIST_FOR_EACH_ENTRY(cursor, &ctrl->sub_items, cctrl_item, entry)
1419 SendMessageW(cursor->hwnd, BM_SETCHECK, (cursor == item) ? BST_CHECKED : BST_UNCHECKED, 0);
1423 static LRESULT radiobuttonlist_on_bn_clicked(FileDialogImpl *This, HWND hwnd, HWND child)
1425 DWORD ctrl_id = (DWORD)GetWindowLongPtrW(hwnd, GWLP_ID);
1426 customctrl *ctrl;
1427 cctrl_item *item;
1428 BOOL found_item=FALSE;
1430 ctrl = get_cctrl_from_dlgid(This, ctrl_id);
1432 if (!ctrl)
1434 ERR("Can't find this control\n");
1435 return 0;
1438 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1440 if (item->hwnd == child)
1442 found_item = TRUE;
1443 break;
1447 if (!found_item)
1449 ERR("Can't find control item\n");
1450 return 0;
1453 radiobuttonlist_set_selected_item(This, ctrl, item);
1455 cctrl_event_OnItemSelected(This, ctrl->id, item->id);
1457 return 0;
1460 static LRESULT radiobuttonlist_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1462 switch(HIWORD(wparam))
1464 case BN_CLICKED: return radiobuttonlist_on_bn_clicked(This, hwnd, (HWND)lparam);
1467 return FALSE;
1470 static LRESULT CALLBACK radiobuttonlist_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1472 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1474 switch(message)
1476 case WM_COMMAND: return radiobuttonlist_on_wm_command(This, hwnd, wparam, lparam);
1479 return DefWindowProcW(hwnd, message, wparam, lparam);
1482 static HRESULT init_custom_controls(FileDialogImpl *This)
1484 WNDCLASSW wc;
1485 static const WCHAR ctrl_container_classname[] =
1486 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1488 InitCommonControlsEx(NULL);
1490 This->cctrl_width = 160; /* Controls have a fixed width */
1491 This->cctrl_indent = 100;
1492 This->cctrl_def_height = 23;
1493 This->cctrls_cols = 0;
1495 This->cctrl_next_dlgid = 0x2000;
1496 list_init(&This->cctrls);
1497 This->cctrl_active_vg = NULL;
1499 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1501 wc.style = CS_HREDRAW | CS_VREDRAW;
1502 wc.lpfnWndProc = ctrl_container_wndproc;
1503 wc.cbClsExtra = 0;
1504 wc.cbWndExtra = 0;
1505 wc.hInstance = COMDLG32_hInstance;
1506 wc.hIcon = 0;
1507 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1508 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1509 wc.lpszMenuName = NULL;
1510 wc.lpszClassName = ctrl_container_classname;
1512 if(!RegisterClassW(&wc)) return E_FAIL;
1515 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1516 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1517 0, 0, 0, 0, NULL, 0,
1518 COMDLG32_hInstance, This);
1519 if(!This->cctrls_hwnd)
1520 return E_FAIL;
1522 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1524 /* Register class for */
1525 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1526 wc.hInstance != COMDLG32_hInstance)
1528 wc.style = CS_HREDRAW | CS_VREDRAW;
1529 wc.lpfnWndProc = notifysink_proc;
1530 wc.cbClsExtra = 0;
1531 wc.cbWndExtra = 0;
1532 wc.hInstance = COMDLG32_hInstance;
1533 wc.hIcon = 0;
1534 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1535 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1536 wc.lpszMenuName = NULL;
1537 wc.lpszClassName = floatnotifysinkW;
1539 if (!RegisterClassW(&wc))
1540 ERR("Failed to register FloatNotifySink window class.\n");
1543 if( !GetClassInfoW(COMDLG32_hInstance, radiobuttonlistW, &wc) ||
1544 wc.hInstance != COMDLG32_hInstance)
1546 wc.style = CS_HREDRAW | CS_VREDRAW;
1547 wc.lpfnWndProc = radiobuttonlist_proc;
1548 wc.cbClsExtra = 0;
1549 wc.cbWndExtra = 0;
1550 wc.hInstance = COMDLG32_hInstance;
1551 wc.hIcon = 0;
1552 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1553 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1554 wc.lpszMenuName = NULL;
1555 wc.lpszClassName = radiobuttonlistW;
1557 if (!RegisterClassW(&wc))
1558 ERR("Failed to register RadioButtonList window class.\n");
1561 return S_OK;
1564 /**************************************************************************
1565 * Window related functions.
1567 static BOOL update_open_dropdown(FileDialogImpl *This)
1569 /* Show or hide the open dropdown button as appropriate */
1570 BOOL show=FALSE, showing;
1571 HWND open_hwnd, dropdown_hwnd;
1573 if (This->hmenu_opendropdown)
1575 INT num_visible_items=0;
1576 cctrl_item* item;
1578 LIST_FOR_EACH_ENTRY(item, &This->cctrl_opendropdown.sub_items, cctrl_item, entry)
1580 if (item->cdcstate & CDCS_VISIBLE)
1582 num_visible_items++;
1583 if (num_visible_items >= 2)
1585 show = TRUE;
1586 break;
1592 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1593 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1595 showing = (GetWindowLongPtrW(dropdown_hwnd, GWL_STYLE) & WS_VISIBLE) != 0;
1597 if (showing != show)
1599 RECT open_rc, dropdown_rc;
1601 GetWindowRect(open_hwnd, &open_rc);
1602 GetWindowRect(dropdown_hwnd, &dropdown_rc);
1604 if (show)
1606 ShowWindow(dropdown_hwnd, SW_SHOW);
1608 SetWindowPos(open_hwnd, NULL, 0, 0,
1609 (open_rc.right - open_rc.left) - (dropdown_rc.right - dropdown_rc.left),
1610 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1612 else
1614 ShowWindow(dropdown_hwnd, SW_HIDE);
1616 SetWindowPos(open_hwnd, NULL, 0, 0,
1617 (open_rc.right - open_rc.left) + (dropdown_rc.right - dropdown_rc.left),
1618 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1622 return show;
1625 static void update_layout(FileDialogImpl *This)
1627 HDWP hdwp;
1628 HWND hwnd;
1629 RECT dialog_rc;
1630 RECT cancel_rc, dropdown_rc, open_rc;
1631 RECT filetype_rc, filename_rc, filenamelabel_rc;
1632 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1633 static const UINT vspacing = 4, hspacing = 4;
1634 static const UINT min_width = 320, min_height = 200;
1635 BOOL show_dropdown;
1637 if (!GetClientRect(This->dlg_hwnd, &dialog_rc))
1639 TRACE("Invalid dialog window, not updating layout\n");
1640 return;
1643 if(dialog_rc.right < min_width || dialog_rc.bottom < min_height)
1645 TRACE("Dialog size (%d, %d) too small, not updating layout\n", dialog_rc.right, dialog_rc.bottom);
1646 return;
1649 /****
1650 * Calculate the size of the dialog and all the parts.
1653 /* Cancel button */
1654 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1655 if(hwnd)
1657 int cancel_width, cancel_height;
1658 GetWindowRect(hwnd, &cancel_rc);
1659 cancel_width = cancel_rc.right - cancel_rc.left;
1660 cancel_height = cancel_rc.bottom - cancel_rc.top;
1662 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1663 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1664 cancel_rc.right = cancel_rc.left + cancel_width;
1665 cancel_rc.bottom = cancel_rc.top + cancel_height;
1668 /* Open/Save dropdown */
1669 show_dropdown = update_open_dropdown(This);
1671 if(show_dropdown)
1673 int dropdown_width, dropdown_height;
1674 hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1676 GetWindowRect(hwnd, &dropdown_rc);
1677 dropdown_width = dropdown_rc.right - dropdown_rc.left;
1678 dropdown_height = dropdown_rc.bottom - dropdown_rc.top;
1680 dropdown_rc.left = cancel_rc.left - dropdown_width - hspacing;
1681 dropdown_rc.top = cancel_rc.top;
1682 dropdown_rc.right = dropdown_rc.left + dropdown_width;
1683 dropdown_rc.bottom = dropdown_rc.top + dropdown_height;
1685 else
1687 dropdown_rc.left = dropdown_rc.right = cancel_rc.left - hspacing;
1688 dropdown_rc.top = cancel_rc.top;
1689 dropdown_rc.bottom = cancel_rc.bottom;
1692 /* Open/Save button */
1693 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1694 if(hwnd)
1696 int open_width, open_height;
1697 GetWindowRect(hwnd, &open_rc);
1698 open_width = open_rc.right - open_rc.left;
1699 open_height = open_rc.bottom - open_rc.top;
1701 open_rc.left = dropdown_rc.left - open_width;
1702 open_rc.top = dropdown_rc.top;
1703 open_rc.right = open_rc.left + open_width;
1704 open_rc.bottom = open_rc.top + open_height;
1707 /* The filetype combobox. */
1708 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1709 if(hwnd)
1711 int filetype_width, filetype_height;
1712 GetWindowRect(hwnd, &filetype_rc);
1714 filetype_width = filetype_rc.right - filetype_rc.left;
1715 filetype_height = filetype_rc.bottom - filetype_rc.top;
1717 filetype_rc.right = cancel_rc.right;
1719 filetype_rc.left = filetype_rc.right - filetype_width;
1720 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1721 filetype_rc.bottom = filetype_rc.top + filetype_height;
1723 if(!This->filterspec_count)
1724 filetype_rc.left = filetype_rc.right;
1727 /* Filename label. */
1728 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1729 if(hwnd)
1731 int filetypelabel_width, filetypelabel_height;
1732 GetWindowRect(hwnd, &filenamelabel_rc);
1734 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1735 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1737 filenamelabel_rc.left = 160; /* FIXME */
1738 filenamelabel_rc.top = filetype_rc.top;
1739 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1740 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1743 /* Filename edit box. */
1744 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1745 if(hwnd)
1747 int filename_width, filename_height;
1748 GetWindowRect(hwnd, &filename_rc);
1750 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1751 filename_height = filename_rc.bottom - filename_rc.top;
1753 filename_rc.left = filenamelabel_rc.right + hspacing;
1754 filename_rc.top = filetype_rc.top;
1755 filename_rc.right = filename_rc.left + filename_width;
1756 filename_rc.bottom = filename_rc.top + filename_height;
1759 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1760 if(hwnd)
1762 GetWindowRect(hwnd, &toolbar_rc);
1763 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1766 /* The custom controls */
1767 customctrls_rc.left = dialog_rc.left + hspacing;
1768 customctrls_rc.right = dialog_rc.right - hspacing;
1769 customctrls_rc.bottom = filename_rc.top - vspacing;
1770 customctrls_rc.top = customctrls_rc.bottom -
1771 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1773 /* The ExplorerBrowser control. */
1774 ebrowser_rc.left = dialog_rc.left + hspacing;
1775 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1776 ebrowser_rc.right = dialog_rc.right - hspacing;
1777 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1779 /****
1780 * Move everything to the right place.
1783 /* FIXME: The Save Dialog uses a slightly different layout. */
1784 hdwp = BeginDeferWindowPos(7);
1786 if(hdwp && This->peb)
1787 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1789 if(hdwp && This->cctrls_hwnd)
1790 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1791 customctrls_rc.left, customctrls_rc.top,
1792 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1793 SWP_NOZORDER | SWP_NOACTIVATE);
1795 /* The default controls */
1796 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1797 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1798 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1800 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1801 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1802 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1803 SWP_NOZORDER | SWP_NOACTIVATE);
1805 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1806 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1807 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1809 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1810 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1811 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1813 if(hdwp && This->hmenu_opendropdown && (hwnd = GetDlgItem(This->dlg_hwnd, psh1)))
1814 DeferWindowPos(hdwp, hwnd, NULL, dropdown_rc.left, dropdown_rc.top, 0, 0,
1815 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1817 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1818 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1819 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1821 if(hdwp)
1822 EndDeferWindowPos(hdwp);
1823 else
1824 ERR("Failed to position dialog controls.\n");
1826 return;
1829 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1831 IShellItem *psi_folder;
1832 IObjectWithSite *client;
1833 FOLDERSETTINGS fos;
1834 RECT rc = {0};
1835 HRESULT hr;
1837 /* Create ExplorerBrowser instance */
1838 OleInitialize(NULL);
1840 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1841 &IID_IExplorerBrowser, (void**)&This->peb);
1842 if(FAILED(hr))
1844 ERR("Failed to instantiate ExplorerBrowser control.\n");
1845 return hr;
1848 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES | EBO_NOBORDER);
1850 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1851 if(FAILED(hr))
1853 ERR("Failed to initialize the ExplorerBrowser control.\n");
1854 IExplorerBrowser_Release(This->peb);
1855 This->peb = NULL;
1856 return hr;
1858 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1859 if(FAILED(hr))
1860 ERR("Advise (ExplorerBrowser) failed.\n");
1862 /* Get previous options? */
1863 fos.ViewMode = fos.fFlags = 0;
1864 if(!(This->options & FOS_ALLOWMULTISELECT))
1865 fos.fFlags |= FWF_SINGLESEL;
1867 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1869 hr = IExplorerBrowser_QueryInterface(This->peb, &IID_IObjectWithSite, (void**)&client);
1870 if (hr == S_OK)
1872 hr = IObjectWithSite_SetSite(client, (IUnknown*)&This->IFileDialog2_iface);
1873 IObjectWithSite_Release(client);
1874 if(FAILED(hr))
1875 ERR("SetSite failed, 0x%08x\n", hr);
1878 /* Browse somewhere */
1879 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1880 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1882 return S_OK;
1885 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1887 HWND htoolbar;
1888 TBADDBITMAP tbab;
1889 TBBUTTON button[2];
1891 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1892 0, 0, 0, 0,
1893 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1895 tbab.hInst = HINST_COMMCTRL;
1896 tbab.nID = IDB_HIST_LARGE_COLOR;
1897 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1899 button[0].iBitmap = HIST_BACK;
1900 button[0].idCommand = IDC_NAVBACK;
1901 button[0].fsState = TBSTATE_ENABLED;
1902 button[0].fsStyle = BTNS_BUTTON;
1903 button[0].dwData = 0;
1904 button[0].iString = 0;
1906 button[1].iBitmap = HIST_FORWARD;
1907 button[1].idCommand = IDC_NAVFORWARD;
1908 button[1].fsState = TBSTATE_ENABLED;
1909 button[1].fsStyle = BTNS_BUTTON;
1910 button[1].dwData = 0;
1911 button[1].iString = 0;
1913 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1914 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1915 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1918 static void update_control_text(FileDialogImpl *This)
1920 HWND hitem;
1921 LPCWSTR custom_okbutton;
1922 cctrl_item* item;
1924 if(This->custom_title)
1925 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1927 if(This->hmenu_opendropdown && (item = get_first_item(&This->cctrl_opendropdown)))
1928 custom_okbutton = item->label;
1929 else
1930 custom_okbutton = This->custom_okbutton;
1932 if(custom_okbutton &&
1933 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1935 SetWindowTextW(hitem, custom_okbutton);
1936 ctrl_resize(hitem, 50, 250, FALSE);
1939 if(This->custom_cancelbutton &&
1940 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1942 SetWindowTextW(hitem, This->custom_cancelbutton);
1943 ctrl_resize(hitem, 50, 250, FALSE);
1946 if(This->custom_filenamelabel &&
1947 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1949 SetWindowTextW(hitem, This->custom_filenamelabel);
1950 ctrl_resize(hitem, 50, 250, FALSE);
1954 static LRESULT CALLBACK dropdown_subclass_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1956 static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
1957 static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
1959 if (umessage == WM_LBUTTONDOWN)
1961 FileDialogImpl *This = (FileDialogImpl*)GetPropW(hwnd, prop_this);
1963 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
1964 show_opendropdown(This);
1965 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
1967 return 0;
1970 return CallWindowProcW((WNDPROC)GetPropW(hwnd, prop_oldwndproc), hwnd, umessage, wparam, lparam);
1973 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1975 FileDialogImpl *This = (FileDialogImpl*)lParam;
1976 HWND hitem;
1978 TRACE("(%p, %p)\n", This, hwnd);
1980 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1981 This->dlg_hwnd = hwnd;
1983 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1984 if(hitem) ShowWindow(hitem, SW_HIDE);
1986 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1987 if(hitem) ShowWindow(hitem, SW_HIDE);
1989 /* Fill filetypes combobox, or hide it. */
1990 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1991 if(This->filterspec_count)
1993 HDC hdc;
1994 HFONT font;
1995 SIZE size;
1996 UINT i, maxwidth = 0;
1998 hdc = GetDC(hitem);
1999 font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
2000 SelectObject(hdc, font);
2002 for(i = 0; i < This->filterspec_count; i++)
2004 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
2006 if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
2007 maxwidth = max(maxwidth, size.cx);
2009 ReleaseDC(hitem, hdc);
2011 if(maxwidth > 0)
2013 maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
2014 SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
2016 else
2017 ERR("Failed to calculate width of filetype dropdown\n");
2019 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
2021 else
2022 ShowWindow(hitem, SW_HIDE);
2024 if(This->set_filename &&
2025 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
2026 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
2028 if(This->hmenu_opendropdown)
2030 HWND dropdown_hwnd;
2031 LOGFONTW lfw, lfw_marlett;
2032 HFONT dialog_font;
2033 static const WCHAR marlett[] = {'M','a','r','l','e','t','t',0};
2034 static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
2035 static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
2037 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
2039 /* Change dropdown button font to Marlett */
2040 dialog_font = (HFONT)SendMessageW(dropdown_hwnd, WM_GETFONT, 0, 0);
2042 GetObjectW(dialog_font, sizeof(lfw), &lfw);
2044 memset(&lfw_marlett, 0, sizeof(lfw_marlett));
2045 lstrcpyW(lfw_marlett.lfFaceName, marlett);
2046 lfw_marlett.lfHeight = lfw.lfHeight;
2047 lfw_marlett.lfCharSet = SYMBOL_CHARSET;
2049 This->hfont_opendropdown = CreateFontIndirectW(&lfw_marlett);
2051 SendMessageW(dropdown_hwnd, WM_SETFONT, (LPARAM)This->hfont_opendropdown, 0);
2053 /* Subclass button so we can handle LBUTTONDOWN */
2054 SetPropW(dropdown_hwnd, prop_this, (HANDLE)This);
2055 SetPropW(dropdown_hwnd, prop_oldwndproc,
2056 (HANDLE)SetWindowLongPtrW(dropdown_hwnd, GWLP_WNDPROC, (LONG_PTR)dropdown_subclass_proc));
2059 ctrl_container_reparent(This, This->dlg_hwnd);
2060 init_explorerbrowser(This);
2061 init_toolbar(This, hwnd);
2062 update_control_text(This);
2063 update_layout(This);
2065 if(This->filterspec_count)
2066 events_OnTypeChange(This);
2068 if ((hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)))
2069 SetFocus(hitem);
2071 return FALSE;
2074 static LRESULT on_wm_size(FileDialogImpl *This)
2076 update_layout(This);
2077 return FALSE;
2080 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
2082 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
2083 TRACE("%p (%p)\n", This, mmi);
2085 /* FIXME */
2086 mmi->ptMinTrackSize.x = 640;
2087 mmi->ptMinTrackSize.y = 480;
2089 return FALSE;
2092 static LRESULT on_wm_destroy(FileDialogImpl *This)
2094 TRACE("%p\n", This);
2096 if(This->peb)
2098 IExplorerBrowser_Destroy(This->peb);
2099 IExplorerBrowser_Release(This->peb);
2100 This->peb = NULL;
2103 ctrl_container_reparent(This, NULL);
2104 This->dlg_hwnd = NULL;
2106 DeleteObject(This->hfont_opendropdown);
2107 This->hfont_opendropdown = NULL;
2109 return TRUE;
2112 static LRESULT on_idok(FileDialogImpl *This)
2114 TRACE("%p\n", This);
2116 if(SUCCEEDED(on_default_action(This)))
2117 EndDialog(This->dlg_hwnd, S_OK);
2119 return FALSE;
2122 static LRESULT on_idcancel(FileDialogImpl *This)
2124 TRACE("%p\n", This);
2126 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
2128 return FALSE;
2131 static LRESULT on_command_opendropdown(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2133 if(HIWORD(wparam) == BN_CLICKED)
2135 HWND hwnd = (HWND)lparam;
2136 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
2137 show_opendropdown(This);
2138 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
2141 return FALSE;
2144 static LRESULT on_browse_back(FileDialogImpl *This)
2146 TRACE("%p\n", This);
2147 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
2148 return FALSE;
2151 static LRESULT on_browse_forward(FileDialogImpl *This)
2153 TRACE("%p\n", This);
2154 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
2155 return FALSE;
2158 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2160 if(HIWORD(wparam) == CBN_SELCHANGE)
2162 IShellView *psv;
2163 HRESULT hr;
2164 LPWSTR filename;
2165 UINT prev_index = This->filetypeindex;
2167 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
2168 TRACE("File type selection changed to %d.\n", This->filetypeindex);
2170 if(prev_index == This->filetypeindex)
2171 return FALSE;
2173 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
2174 if(SUCCEEDED(hr))
2176 IShellView_Refresh(psv);
2177 IShellView_Release(psv);
2180 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
2182 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
2184 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
2185 if(ext)
2187 lstrcpyW(buf, filename);
2189 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
2190 PathRemoveExtensionW(buf);
2192 lstrcatW(buf, ext);
2193 set_file_name(This, buf);
2195 CoTaskMemFree(filename);
2198 /* The documentation claims that OnTypeChange is called only
2199 * when the dialog is opened, but this is obviously not the
2200 * case. */
2201 events_OnTypeChange(This);
2204 return FALSE;
2207 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2209 switch(LOWORD(wparam))
2211 case IDOK: return on_idok(This);
2212 case IDCANCEL: return on_idcancel(This);
2213 case psh1: return on_command_opendropdown(This, wparam, lparam);
2214 case IDC_NAVBACK: return on_browse_back(This);
2215 case IDC_NAVFORWARD: return on_browse_forward(This);
2216 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
2217 default: TRACE("Unknown command.\n");
2219 return FALSE;
2222 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
2224 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
2226 switch(umessage)
2228 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
2229 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
2230 case WM_SIZE: return on_wm_size(This);
2231 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
2232 case WM_DESTROY: return on_wm_destroy(This);
2235 return FALSE;
2238 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
2240 INT_PTR res;
2242 SetLastError(0);
2243 res = DialogBoxParamW(COMDLG32_hInstance,
2244 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
2245 parent, itemdlg_dlgproc, (LPARAM)This);
2246 This->dlg_hwnd = NULL;
2247 if(res == -1)
2249 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
2250 return E_FAIL;
2253 TRACE("Returning 0x%08x\n", (HRESULT)res);
2254 return (HRESULT)res;
2257 /**************************************************************************
2258 * IFileDialog implementation
2260 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
2262 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
2265 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
2266 REFIID riid,
2267 void **ppvObject)
2269 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2270 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2272 *ppvObject = NULL;
2273 if(IsEqualGUID(riid, &IID_IUnknown) ||
2274 IsEqualGUID(riid, &IID_IFileDialog) ||
2275 IsEqualGUID(riid, &IID_IFileDialog2))
2277 *ppvObject = iface;
2279 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
2281 *ppvObject = &This->u.IFileOpenDialog_iface;
2283 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
2285 *ppvObject = &This->u.IFileSaveDialog_iface;
2287 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
2289 *ppvObject = &This->IExplorerBrowserEvents_iface;
2291 else if(IsEqualGUID(riid, &IID_IServiceProvider))
2293 *ppvObject = &This->IServiceProvider_iface;
2295 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
2296 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
2297 IsEqualGUID(&IID_ICommDlgBrowser, riid))
2299 *ppvObject = &This->ICommDlgBrowser3_iface;
2301 else if(IsEqualGUID(&IID_IOleWindow, riid))
2303 *ppvObject = &This->IOleWindow_iface;
2305 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
2306 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
2308 *ppvObject = &This->IFileDialogCustomize_iface;
2310 else
2311 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
2313 if(*ppvObject)
2315 IUnknown_AddRef((IUnknown*)*ppvObject);
2316 return S_OK;
2319 return E_NOINTERFACE;
2322 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
2324 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2325 LONG ref = InterlockedIncrement(&This->ref);
2326 TRACE("%p - ref %d\n", This, ref);
2328 return ref;
2331 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
2333 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2334 LONG ref = InterlockedDecrement(&This->ref);
2335 TRACE("%p - ref %d\n", This, ref);
2337 if(!ref)
2339 UINT i;
2340 for(i = 0; i < This->filterspec_count; i++)
2342 LocalFree((void*)This->filterspecs[i].pszName);
2343 LocalFree((void*)This->filterspecs[i].pszSpec);
2345 HeapFree(GetProcessHeap(), 0, This->filterspecs);
2347 DestroyWindow(This->cctrls_hwnd);
2349 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
2350 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
2351 if(This->psi_folder) IShellItem_Release(This->psi_folder);
2352 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
2353 if(This->psia_results) IShellItemArray_Release(This->psia_results);
2355 LocalFree(This->set_filename);
2356 LocalFree(This->default_ext);
2357 LocalFree(This->custom_title);
2358 LocalFree(This->custom_okbutton);
2359 LocalFree(This->custom_cancelbutton);
2360 LocalFree(This->custom_filenamelabel);
2362 DestroyMenu(This->hmenu_opendropdown);
2363 DeleteObject(This->hfont_opendropdown);
2365 HeapFree(GetProcessHeap(), 0, This);
2368 return ref;
2371 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
2373 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2374 TRACE("%p (%p)\n", iface, hwndOwner);
2376 This->opendropdown_has_selection = FALSE;
2378 return create_dialog(This, hwndOwner);
2381 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
2382 const COMDLG_FILTERSPEC *rgFilterSpec)
2384 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2385 UINT i;
2386 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
2388 if(This->filterspecs)
2389 return E_UNEXPECTED;
2391 if(!rgFilterSpec)
2392 return E_INVALIDARG;
2394 if(!cFileTypes)
2395 return S_OK;
2397 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
2398 for(i = 0; i < cFileTypes; i++)
2400 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
2401 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
2403 This->filterspec_count = cFileTypes;
2405 return S_OK;
2408 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
2410 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2411 TRACE("%p (%d)\n", This, iFileType);
2413 if(!This->filterspecs)
2414 return E_FAIL;
2416 iFileType = max(iFileType, 1);
2417 iFileType = min(iFileType, This->filterspec_count);
2418 This->filetypeindex = iFileType-1;
2420 return S_OK;
2423 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
2425 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2426 TRACE("%p (%p)\n", This, piFileType);
2428 if(!piFileType)
2429 return E_INVALIDARG;
2431 if(This->filterspec_count == 0)
2432 *piFileType = 0;
2433 else
2434 *piFileType = This->filetypeindex + 1;
2436 return S_OK;
2439 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
2441 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2442 events_client *client;
2443 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
2445 if(!pfde || !pdwCookie)
2446 return E_INVALIDARG;
2448 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
2449 client->pfde = pfde;
2450 client->cookie = ++This->events_next_cookie;
2452 IFileDialogEvents_AddRef(pfde);
2453 *pdwCookie = client->cookie;
2455 list_add_tail(&This->events_clients, &client->entry);
2457 return S_OK;
2460 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
2462 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2463 events_client *client, *found = NULL;
2464 TRACE("%p (%d)\n", This, dwCookie);
2466 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
2468 if(client->cookie == dwCookie)
2470 found = client;
2471 break;
2475 if(found)
2477 list_remove(&found->entry);
2478 IFileDialogEvents_Release(found->pfde);
2479 HeapFree(GetProcessHeap(), 0, found);
2480 return S_OK;
2483 return E_INVALIDARG;
2486 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
2488 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2489 TRACE("%p (0x%x)\n", This, fos);
2491 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
2493 WCHAR buf[30];
2494 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, sizeof(buf)/sizeof(WCHAR));
2495 IFileDialog2_SetTitle(iface, buf);
2498 This->options = fos;
2500 return S_OK;
2503 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
2505 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2506 TRACE("%p (%p)\n", This, pfos);
2508 if(!pfos)
2509 return E_INVALIDARG;
2511 *pfos = This->options;
2513 return S_OK;
2516 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
2518 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2519 TRACE("%p (%p)\n", This, psi);
2520 if(This->psi_defaultfolder)
2521 IShellItem_Release(This->psi_defaultfolder);
2523 This->psi_defaultfolder = psi;
2525 if(This->psi_defaultfolder)
2526 IShellItem_AddRef(This->psi_defaultfolder);
2528 return S_OK;
2531 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
2533 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2534 TRACE("%p (%p)\n", This, psi);
2535 if(This->psi_setfolder)
2536 IShellItem_Release(This->psi_setfolder);
2538 This->psi_setfolder = psi;
2540 if(This->psi_setfolder)
2541 IShellItem_AddRef(This->psi_setfolder);
2543 return S_OK;
2546 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
2548 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2549 TRACE("%p (%p)\n", This, ppsi);
2550 if(!ppsi)
2551 return E_INVALIDARG;
2553 /* FIXME:
2554 If the dialog is shown, return the current(ly selected) folder. */
2556 *ppsi = NULL;
2557 if(This->psi_folder)
2558 *ppsi = This->psi_folder;
2559 else if(This->psi_setfolder)
2560 *ppsi = This->psi_setfolder;
2561 else if(This->psi_defaultfolder)
2562 *ppsi = This->psi_defaultfolder;
2564 if(*ppsi)
2566 IShellItem_AddRef(*ppsi);
2567 return S_OK;
2570 return E_FAIL;
2573 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
2575 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2576 HRESULT hr;
2577 TRACE("%p (%p)\n", This, ppsi);
2579 if(!ppsi)
2580 return E_INVALIDARG;
2582 if(This->psia_selection)
2584 /* FIXME: Check filename edit box */
2585 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2586 return hr;
2589 return E_FAIL;
2592 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
2594 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2595 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2597 set_file_name(This, pszName);
2599 return S_OK;
2602 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
2604 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2605 TRACE("%p (%p)\n", iface, pszName);
2607 if(!pszName)
2608 return E_INVALIDARG;
2610 *pszName = NULL;
2611 if(get_file_name(This, pszName))
2612 return S_OK;
2613 else
2614 return E_FAIL;
2617 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
2619 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2620 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2622 LocalFree(This->custom_title);
2623 This->custom_title = StrDupW(pszTitle);
2624 update_control_text(This);
2626 return S_OK;
2629 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
2631 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2632 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2634 LocalFree(This->custom_okbutton);
2635 This->custom_okbutton = StrDupW(pszText);
2636 update_control_text(This);
2637 update_layout(This);
2639 return S_OK;
2642 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2644 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2645 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2647 LocalFree(This->custom_filenamelabel);
2648 This->custom_filenamelabel = StrDupW(pszLabel);
2649 update_control_text(This);
2650 update_layout(This);
2652 return S_OK;
2655 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
2657 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2658 HRESULT hr;
2659 TRACE("%p (%p)\n", This, ppsi);
2661 if(!ppsi)
2662 return E_INVALIDARG;
2664 if(This->psia_results)
2666 UINT item_count;
2667 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2668 if(SUCCEEDED(hr))
2670 if(item_count != 1)
2671 return E_FAIL;
2673 /* Adds a reference. */
2674 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2677 return hr;
2680 return E_UNEXPECTED;
2683 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2685 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2686 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2687 return S_OK;
2690 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2692 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2693 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2695 LocalFree(This->default_ext);
2696 This->default_ext = StrDupW(pszDefaultExtension);
2698 return S_OK;
2701 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2703 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2704 TRACE("%p (0x%08x)\n", This, hr);
2706 if(This->dlg_hwnd)
2707 EndDialog(This->dlg_hwnd, hr);
2709 return S_OK;
2712 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2714 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2715 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2716 This->client_guid = *guid;
2717 return S_OK;
2720 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2722 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2723 FIXME("stub - %p\n", This);
2724 return E_NOTIMPL;
2727 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2729 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2730 FIXME("stub - %p (%p)\n", This, pFilter);
2731 return E_NOTIMPL;
2734 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2736 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2737 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2739 LocalFree(This->custom_cancelbutton);
2740 This->custom_cancelbutton = StrDupW(pszLabel);
2741 update_control_text(This);
2742 update_layout(This);
2744 return S_OK;
2747 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2749 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2750 FIXME("stub - %p (%p)\n", This, psi);
2751 return E_NOTIMPL;
2754 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2755 IFileDialog2_fnQueryInterface,
2756 IFileDialog2_fnAddRef,
2757 IFileDialog2_fnRelease,
2758 IFileDialog2_fnShow,
2759 IFileDialog2_fnSetFileTypes,
2760 IFileDialog2_fnSetFileTypeIndex,
2761 IFileDialog2_fnGetFileTypeIndex,
2762 IFileDialog2_fnAdvise,
2763 IFileDialog2_fnUnadvise,
2764 IFileDialog2_fnSetOptions,
2765 IFileDialog2_fnGetOptions,
2766 IFileDialog2_fnSetDefaultFolder,
2767 IFileDialog2_fnSetFolder,
2768 IFileDialog2_fnGetFolder,
2769 IFileDialog2_fnGetCurrentSelection,
2770 IFileDialog2_fnSetFileName,
2771 IFileDialog2_fnGetFileName,
2772 IFileDialog2_fnSetTitle,
2773 IFileDialog2_fnSetOkButtonLabel,
2774 IFileDialog2_fnSetFileNameLabel,
2775 IFileDialog2_fnGetResult,
2776 IFileDialog2_fnAddPlace,
2777 IFileDialog2_fnSetDefaultExtension,
2778 IFileDialog2_fnClose,
2779 IFileDialog2_fnSetClientGuid,
2780 IFileDialog2_fnClearClientData,
2781 IFileDialog2_fnSetFilter,
2782 IFileDialog2_fnSetCancelButtonLabel,
2783 IFileDialog2_fnSetNavigationRoot
2786 /**************************************************************************
2787 * IFileOpenDialog
2789 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2791 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2794 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2795 REFIID riid, void **ppvObject)
2797 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2798 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2801 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2803 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2804 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2807 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2809 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2810 return IFileDialog2_Release(&This->IFileDialog2_iface);
2813 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2815 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2816 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2819 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2820 const COMDLG_FILTERSPEC *rgFilterSpec)
2822 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2823 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2826 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2828 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2829 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2832 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2834 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2835 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2838 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2839 DWORD *pdwCookie)
2841 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2842 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2845 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2847 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2848 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2851 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2853 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2854 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2857 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2859 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2860 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2863 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2865 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2866 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2869 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2871 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2872 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2875 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2877 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2878 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2881 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2883 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2884 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2887 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2889 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2890 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2893 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2895 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2896 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2899 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2901 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2902 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2905 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2907 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2908 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2911 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2913 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2914 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2917 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2919 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2920 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2923 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2925 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2926 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2929 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2930 LPCWSTR pszDefaultExtension)
2932 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2933 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2936 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2938 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2939 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2942 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2944 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2945 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2948 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2950 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2951 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2954 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2956 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2957 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2960 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2962 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2963 TRACE("%p (%p)\n", This, ppenum);
2965 *ppenum = This->psia_results;
2967 if(*ppenum)
2969 IShellItemArray_AddRef(*ppenum);
2970 return S_OK;
2973 return E_FAIL;
2976 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2978 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2979 TRACE("%p (%p)\n", This, ppsai);
2981 if(This->psia_selection)
2983 *ppsai = This->psia_selection;
2984 IShellItemArray_AddRef(*ppsai);
2985 return S_OK;
2988 return E_FAIL;
2991 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2992 IFileOpenDialog_fnQueryInterface,
2993 IFileOpenDialog_fnAddRef,
2994 IFileOpenDialog_fnRelease,
2995 IFileOpenDialog_fnShow,
2996 IFileOpenDialog_fnSetFileTypes,
2997 IFileOpenDialog_fnSetFileTypeIndex,
2998 IFileOpenDialog_fnGetFileTypeIndex,
2999 IFileOpenDialog_fnAdvise,
3000 IFileOpenDialog_fnUnadvise,
3001 IFileOpenDialog_fnSetOptions,
3002 IFileOpenDialog_fnGetOptions,
3003 IFileOpenDialog_fnSetDefaultFolder,
3004 IFileOpenDialog_fnSetFolder,
3005 IFileOpenDialog_fnGetFolder,
3006 IFileOpenDialog_fnGetCurrentSelection,
3007 IFileOpenDialog_fnSetFileName,
3008 IFileOpenDialog_fnGetFileName,
3009 IFileOpenDialog_fnSetTitle,
3010 IFileOpenDialog_fnSetOkButtonLabel,
3011 IFileOpenDialog_fnSetFileNameLabel,
3012 IFileOpenDialog_fnGetResult,
3013 IFileOpenDialog_fnAddPlace,
3014 IFileOpenDialog_fnSetDefaultExtension,
3015 IFileOpenDialog_fnClose,
3016 IFileOpenDialog_fnSetClientGuid,
3017 IFileOpenDialog_fnClearClientData,
3018 IFileOpenDialog_fnSetFilter,
3019 IFileOpenDialog_fnGetResults,
3020 IFileOpenDialog_fnGetSelectedItems
3023 /**************************************************************************
3024 * IFileSaveDialog
3026 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
3028 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
3031 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
3032 REFIID riid,
3033 void **ppvObject)
3035 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3036 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3039 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
3041 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3042 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3045 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
3047 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3048 return IFileDialog2_Release(&This->IFileDialog2_iface);
3051 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
3053 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3054 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
3057 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
3058 const COMDLG_FILTERSPEC *rgFilterSpec)
3060 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3061 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
3064 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
3066 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3067 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
3070 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
3072 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3073 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
3076 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
3077 DWORD *pdwCookie)
3079 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3080 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
3083 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
3085 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3086 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
3089 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
3091 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3092 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
3095 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
3097 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3098 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
3101 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
3103 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3104 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
3107 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
3109 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3110 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
3113 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
3115 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3116 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
3119 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
3121 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3122 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
3125 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
3127 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3128 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
3131 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
3133 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3134 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
3137 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
3139 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3140 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
3143 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
3145 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3146 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
3149 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
3151 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3152 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
3155 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
3157 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3158 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
3161 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
3163 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3164 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
3167 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
3168 LPCWSTR pszDefaultExtension)
3170 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3171 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
3174 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
3176 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3177 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
3180 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
3182 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3183 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
3186 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
3188 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3189 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
3192 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
3194 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3195 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
3198 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
3200 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3201 FIXME("stub - %p (%p)\n", This, psi);
3202 return E_NOTIMPL;
3205 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
3207 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3208 FIXME("stub - %p (%p)\n", This, pStore);
3209 return E_NOTIMPL;
3212 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
3213 IPropertyDescriptionList *pList,
3214 BOOL fAppendDefault)
3216 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3217 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
3218 return E_NOTIMPL;
3221 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
3223 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3224 FIXME("stub - %p (%p)\n", This, ppStore);
3225 return E_NOTIMPL;
3228 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
3229 IShellItem *psi,
3230 IPropertyStore *pStore,
3231 HWND hwnd,
3232 IFileOperationProgressSink *pSink)
3234 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3235 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
3236 return E_NOTIMPL;
3239 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
3240 IFileSaveDialog_fnQueryInterface,
3241 IFileSaveDialog_fnAddRef,
3242 IFileSaveDialog_fnRelease,
3243 IFileSaveDialog_fnShow,
3244 IFileSaveDialog_fnSetFileTypes,
3245 IFileSaveDialog_fnSetFileTypeIndex,
3246 IFileSaveDialog_fnGetFileTypeIndex,
3247 IFileSaveDialog_fnAdvise,
3248 IFileSaveDialog_fnUnadvise,
3249 IFileSaveDialog_fnSetOptions,
3250 IFileSaveDialog_fnGetOptions,
3251 IFileSaveDialog_fnSetDefaultFolder,
3252 IFileSaveDialog_fnSetFolder,
3253 IFileSaveDialog_fnGetFolder,
3254 IFileSaveDialog_fnGetCurrentSelection,
3255 IFileSaveDialog_fnSetFileName,
3256 IFileSaveDialog_fnGetFileName,
3257 IFileSaveDialog_fnSetTitle,
3258 IFileSaveDialog_fnSetOkButtonLabel,
3259 IFileSaveDialog_fnSetFileNameLabel,
3260 IFileSaveDialog_fnGetResult,
3261 IFileSaveDialog_fnAddPlace,
3262 IFileSaveDialog_fnSetDefaultExtension,
3263 IFileSaveDialog_fnClose,
3264 IFileSaveDialog_fnSetClientGuid,
3265 IFileSaveDialog_fnClearClientData,
3266 IFileSaveDialog_fnSetFilter,
3267 IFileSaveDialog_fnSetSaveAsItem,
3268 IFileSaveDialog_fnSetProperties,
3269 IFileSaveDialog_fnSetCollectedProperties,
3270 IFileSaveDialog_fnGetProperties,
3271 IFileSaveDialog_fnApplyProperties
3274 /**************************************************************************
3275 * IExplorerBrowserEvents implementation
3277 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
3279 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
3282 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
3283 REFIID riid, void **ppvObject)
3285 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3286 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
3288 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3291 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
3293 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3294 TRACE("%p\n", This);
3295 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3298 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
3300 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3301 TRACE("%p\n", This);
3302 return IFileDialog2_Release(&This->IFileDialog2_iface);
3305 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
3306 PCIDLIST_ABSOLUTE pidlFolder)
3308 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3309 IShellItem *psi;
3310 HRESULT hr;
3311 TRACE("%p (%p)\n", This, pidlFolder);
3313 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
3314 if(SUCCEEDED(hr))
3316 hr = events_OnFolderChanging(This, psi);
3317 IShellItem_Release(psi);
3319 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
3320 if(hr == S_FALSE)
3321 hr = E_FAIL;
3323 return hr;
3325 else
3326 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
3328 return S_OK;
3331 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
3332 IShellView *psv)
3334 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3335 TRACE("%p (%p)\n", This, psv);
3336 return S_OK;
3339 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
3340 PCIDLIST_ABSOLUTE pidlFolder)
3342 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3343 HRESULT hr;
3344 TRACE("%p (%p)\n", This, pidlFolder);
3346 if(This->psi_folder)
3347 IShellItem_Release(This->psi_folder);
3349 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
3350 if(FAILED(hr))
3352 ERR("Failed to get the current folder.\n");
3353 This->psi_folder = NULL;
3356 events_OnFolderChange(This);
3358 return S_OK;
3361 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
3362 PCIDLIST_ABSOLUTE pidlFolder)
3364 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3365 TRACE("%p (%p)\n", This, pidlFolder);
3366 return S_OK;
3369 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
3370 IExplorerBrowserEvents_fnQueryInterface,
3371 IExplorerBrowserEvents_fnAddRef,
3372 IExplorerBrowserEvents_fnRelease,
3373 IExplorerBrowserEvents_fnOnNavigationPending,
3374 IExplorerBrowserEvents_fnOnViewCreated,
3375 IExplorerBrowserEvents_fnOnNavigationComplete,
3376 IExplorerBrowserEvents_fnOnNavigationFailed
3379 /**************************************************************************
3380 * IServiceProvider implementation
3382 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
3384 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
3387 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
3388 REFIID riid, void **ppvObject)
3390 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3391 TRACE("%p\n", This);
3392 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3395 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
3397 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3398 TRACE("%p\n", This);
3399 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3402 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
3404 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3405 TRACE("%p\n", This);
3406 return IFileDialog2_Release(&This->IFileDialog2_iface);
3409 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
3410 REFGUID guidService,
3411 REFIID riid, void **ppv)
3413 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3414 HRESULT hr = E_NOTIMPL;
3415 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
3417 *ppv = NULL;
3418 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
3419 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
3420 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
3421 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
3422 else
3423 FIXME("Interface %s requested from unknown service %s\n",
3424 debugstr_guid(riid), debugstr_guid(guidService));
3426 return hr;
3429 static const IServiceProviderVtbl vt_IServiceProvider = {
3430 IServiceProvider_fnQueryInterface,
3431 IServiceProvider_fnAddRef,
3432 IServiceProvider_fnRelease,
3433 IServiceProvider_fnQueryService
3436 /**************************************************************************
3437 * ICommDlgBrowser3 implementation
3439 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
3441 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
3444 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
3445 REFIID riid, void **ppvObject)
3447 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3448 TRACE("%p\n", This);
3449 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3452 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
3454 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3455 TRACE("%p\n", This);
3456 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3459 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
3461 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3462 TRACE("%p\n", This);
3463 return IFileDialog2_Release(&This->IFileDialog2_iface);
3466 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
3467 IShellView *shv)
3469 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3470 HRESULT hr;
3471 TRACE("%p (%p)\n", This, shv);
3473 hr = on_default_action(This);
3475 if(SUCCEEDED(hr))
3476 EndDialog(This->dlg_hwnd, S_OK);
3478 return S_OK;
3481 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
3482 IShellView *shv, ULONG uChange )
3484 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3485 IDataObject *new_selection;
3486 HRESULT hr;
3487 TRACE("%p (%p, %x)\n", This, shv, uChange);
3489 switch(uChange)
3491 case CDBOSC_SELCHANGE:
3492 if(This->psia_selection)
3494 IShellItemArray_Release(This->psia_selection);
3495 This->psia_selection = NULL;
3498 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
3499 if(SUCCEEDED(hr))
3501 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
3502 (void**)&This->psia_selection);
3503 if(SUCCEEDED(hr))
3505 fill_filename_from_selection(This);
3506 events_OnSelectionChange(This);
3509 IDataObject_Release(new_selection);
3511 break;
3512 default:
3513 TRACE("Unhandled state change\n");
3515 return S_OK;
3518 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
3519 IShellView *shv, LPCITEMIDLIST pidl)
3521 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3522 IShellItem *psi;
3523 LPWSTR filename;
3524 LPITEMIDLIST parent_pidl;
3525 HRESULT hr;
3526 ULONG attr;
3527 TRACE("%p (%p, %p)\n", This, shv, pidl);
3529 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
3530 return S_OK;
3532 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3533 if(SUCCEEDED(hr))
3535 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3536 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3537 ILFree(parent_pidl);
3538 ILFree(full_pidl);
3540 if(FAILED(hr))
3542 ERR("Failed to get shellitem (%08x).\n", hr);
3543 return S_OK;
3546 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3547 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3549 IShellItem_Release(psi);
3550 return S_OK;
3553 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
3555 IShellItem_Release(psi);
3556 return S_FALSE;
3559 hr = S_OK;
3560 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
3562 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
3563 hr = S_FALSE;
3564 CoTaskMemFree(filename);
3567 IShellItem_Release(psi);
3568 return hr;
3571 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
3572 IShellView *ppshv, DWORD dwNotifyType)
3574 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3575 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
3576 return E_NOTIMPL;
3579 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
3580 IShellView *pshv,
3581 LPWSTR pszText, int cchMax)
3583 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3584 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
3585 return E_NOTIMPL;
3588 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
3590 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3591 FIXME("Stub: %p (%p)\n", This, pdwFlags);
3592 return E_NOTIMPL;
3595 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
3596 IShellView *pshv, int iColumn)
3598 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3599 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
3600 return E_NOTIMPL;
3603 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
3604 LPWSTR pszFileSpec, int cchFileSpec)
3606 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3607 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
3608 return E_NOTIMPL;
3611 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
3612 IShellView *pshv)
3614 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3615 FIXME("Stub: %p (%p)\n", This, pshv);
3616 return E_NOTIMPL;
3619 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
3620 ICommDlgBrowser3_fnQueryInterface,
3621 ICommDlgBrowser3_fnAddRef,
3622 ICommDlgBrowser3_fnRelease,
3623 ICommDlgBrowser3_fnOnDefaultCommand,
3624 ICommDlgBrowser3_fnOnStateChange,
3625 ICommDlgBrowser3_fnIncludeObject,
3626 ICommDlgBrowser3_fnNotify,
3627 ICommDlgBrowser3_fnGetDefaultMenuText,
3628 ICommDlgBrowser3_fnGetViewFlags,
3629 ICommDlgBrowser3_fnOnColumnClicked,
3630 ICommDlgBrowser3_fnGetCurrentFilter,
3631 ICommDlgBrowser3_fnOnPreviewCreated
3634 /**************************************************************************
3635 * IOleWindow implementation
3637 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
3639 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
3642 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
3644 FileDialogImpl *This = impl_from_IOleWindow(iface);
3645 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3648 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
3650 FileDialogImpl *This = impl_from_IOleWindow(iface);
3651 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3654 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
3656 FileDialogImpl *This = impl_from_IOleWindow(iface);
3657 return IFileDialog2_Release(&This->IFileDialog2_iface);
3660 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
3662 FileDialogImpl *This = impl_from_IOleWindow(iface);
3663 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
3664 return E_NOTIMPL;
3667 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
3669 FileDialogImpl *This = impl_from_IOleWindow(iface);
3670 TRACE("%p (%p)\n", This, phwnd);
3671 *phwnd = This->dlg_hwnd;
3672 return S_OK;
3675 static const IOleWindowVtbl vt_IOleWindow = {
3676 IOleWindow_fnQueryInterface,
3677 IOleWindow_fnAddRef,
3678 IOleWindow_fnRelease,
3679 IOleWindow_fnGetWindow,
3680 IOleWindow_fnContextSensitiveHelp
3683 /**************************************************************************
3684 * IFileDialogCustomize implementation
3686 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3688 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3691 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3692 REFIID riid, void **ppvObject)
3694 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3695 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3698 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3700 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3701 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3704 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3706 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3707 return IFileDialog2_Release(&This->IFileDialog2_iface);
3710 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3711 DWORD dwIDCtl)
3713 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3714 MENUINFO mi;
3715 TRACE("%p (%d)\n", This, dwIDCtl);
3717 if (This->hmenu_opendropdown || get_cctrl(This, dwIDCtl))
3718 return E_UNEXPECTED;
3720 This->hmenu_opendropdown = CreatePopupMenu();
3722 if (!This->hmenu_opendropdown)
3723 return E_OUTOFMEMORY;
3725 mi.cbSize = sizeof(mi);
3726 mi.fMask = MIM_STYLE;
3727 mi.dwStyle = MNS_NOTIFYBYPOS;
3728 SetMenuInfo(This->hmenu_opendropdown, &mi);
3730 This->cctrl_opendropdown.hwnd = NULL;
3731 This->cctrl_opendropdown.wrapper_hwnd = NULL;
3732 This->cctrl_opendropdown.id = dwIDCtl;
3733 This->cctrl_opendropdown.dlgid = 0;
3734 This->cctrl_opendropdown.type = IDLG_CCTRL_OPENDROPDOWN;
3735 This->cctrl_opendropdown.cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
3736 list_init(&This->cctrl_opendropdown.sub_cctrls);
3737 list_init(&This->cctrl_opendropdown.sub_items);
3739 return S_OK;
3742 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3743 DWORD dwIDCtl,
3744 LPCWSTR pszLabel)
3746 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3747 customctrl *ctrl;
3748 TBBUTTON tbb;
3749 HRESULT hr;
3750 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3752 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3753 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3754 This->cctrl_def_height, &ctrl);
3755 if(SUCCEEDED(hr))
3757 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3758 ctrl->type = IDLG_CCTRL_MENU;
3760 /* Add the actual button with a popup menu. */
3761 tbb.iBitmap = I_IMAGENONE;
3762 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3763 tbb.iString = (DWORD_PTR)pszLabel;
3764 tbb.fsState = TBSTATE_ENABLED;
3765 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3766 tbb.idCommand = 1;
3768 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3771 return hr;
3774 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3775 DWORD dwIDCtl,
3776 LPCWSTR pszLabel)
3778 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3779 customctrl *ctrl;
3780 HRESULT hr;
3781 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3783 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3784 This->cctrl_def_height, &ctrl);
3785 if(SUCCEEDED(hr))
3786 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3788 return hr;
3791 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3792 DWORD dwIDCtl)
3794 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3795 customctrl *ctrl;
3796 HRESULT hr;
3797 TRACE("%p (%d)\n", This, dwIDCtl);
3799 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3800 This->cctrl_def_height, &ctrl);
3801 if(SUCCEEDED(hr))
3802 ctrl->type = IDLG_CCTRL_COMBOBOX;
3804 return hr;
3807 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3808 DWORD dwIDCtl)
3810 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3811 customctrl *ctrl;
3812 HRESULT hr;
3813 TRACE("%p (%d)\n", This, dwIDCtl);
3815 hr = cctrl_create_new(This, dwIDCtl, NULL, radiobuttonlistW, 0, 0, 0, &ctrl);
3816 if(SUCCEEDED(hr))
3818 ctrl->type = IDLG_CCTRL_RADIOBUTTONLIST;
3819 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)This);
3822 return hr;
3825 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3826 DWORD dwIDCtl,
3827 LPCWSTR pszLabel,
3828 BOOL bChecked)
3830 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3831 customctrl *ctrl;
3832 HRESULT hr;
3833 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3835 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0,
3836 This->cctrl_def_height, &ctrl);
3837 if(SUCCEEDED(hr))
3839 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3840 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3843 return hr;
3846 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3847 DWORD dwIDCtl,
3848 LPCWSTR pszText)
3850 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3851 customctrl *ctrl;
3852 HRESULT hr;
3853 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3855 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3856 This->cctrl_def_height, &ctrl);
3857 if(SUCCEEDED(hr))
3858 ctrl->type = IDLG_CCTRL_EDITBOX;
3860 return hr;
3863 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3864 DWORD dwIDCtl)
3866 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3867 customctrl *ctrl;
3868 HRESULT hr;
3869 TRACE("%p (%d)\n", This, dwIDCtl);
3871 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3872 GetSystemMetrics(SM_CYEDGE), &ctrl);
3873 if(SUCCEEDED(hr))
3874 ctrl->type = IDLG_CCTRL_SEPARATOR;
3876 return hr;
3879 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3880 DWORD dwIDCtl,
3881 LPCWSTR pszText)
3883 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3884 customctrl *ctrl;
3885 HRESULT hr;
3886 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3888 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3889 This->cctrl_def_height, &ctrl);
3890 if(SUCCEEDED(hr))
3891 ctrl->type = IDLG_CCTRL_TEXT;
3893 return hr;
3896 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3897 DWORD dwIDCtl,
3898 LPCWSTR pszLabel)
3900 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3901 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3902 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3904 if(!ctrl) return E_INVALIDARG;
3906 switch(ctrl->type)
3908 case IDLG_CCTRL_MENU:
3909 case IDLG_CCTRL_PUSHBUTTON:
3910 case IDLG_CCTRL_CHECKBUTTON:
3911 case IDLG_CCTRL_TEXT:
3912 case IDLG_CCTRL_VISUALGROUP:
3913 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3914 break;
3915 case IDLG_CCTRL_OPENDROPDOWN:
3916 return E_NOTIMPL;
3917 default:
3918 break;
3921 return S_OK;
3924 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3925 DWORD dwIDCtl,
3926 CDCONTROLSTATEF *pdwState)
3928 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3929 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3930 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3932 if(!ctrl || ctrl->type == IDLG_CCTRL_OPENDROPDOWN) return E_NOTIMPL;
3934 *pdwState = ctrl->cdcstate;
3935 return S_OK;
3938 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3939 DWORD dwIDCtl,
3940 CDCONTROLSTATEF dwState)
3942 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3943 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3944 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3946 if(ctrl && ctrl->hwnd)
3948 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3950 if(dwState & CDCS_ENABLED)
3951 wndstyle &= ~(WS_DISABLED);
3952 else
3953 wndstyle |= WS_DISABLED;
3955 if(dwState & CDCS_VISIBLE)
3956 wndstyle |= WS_VISIBLE;
3957 else
3958 wndstyle &= ~(WS_VISIBLE);
3960 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3962 /* We save the state separately since at least one application
3963 * relies on being able to hide a control. */
3964 ctrl->cdcstate = dwState;
3967 return S_OK;
3970 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3971 DWORD dwIDCtl,
3972 WCHAR **ppszText)
3974 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3975 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3976 WCHAR len, *text;
3977 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
3979 if(!ctrl || !ctrl->hwnd || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3980 return E_FAIL;
3982 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3983 if(!text) return E_FAIL;
3985 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
3986 *ppszText = text;
3987 return S_OK;
3990 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
3991 DWORD dwIDCtl,
3992 LPCWSTR pszText)
3994 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3995 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3996 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
3998 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
3999 return E_FAIL;
4001 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
4002 return S_OK;
4005 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
4006 DWORD dwIDCtl,
4007 BOOL *pbChecked)
4009 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4010 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4011 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
4013 if(ctrl && ctrl->hwnd)
4014 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
4016 return S_OK;
4019 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
4020 DWORD dwIDCtl,
4021 BOOL bChecked)
4023 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4024 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4025 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
4027 if(ctrl && ctrl->hwnd)
4028 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
4030 return S_OK;
4033 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
4035 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
4036 UINT i;
4037 if(!count || (count == CB_ERR))
4038 return -1;
4040 for(i = 0; i < count; i++)
4041 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
4042 return i;
4044 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
4045 return -1;
4048 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
4049 DWORD dwIDCtl,
4050 DWORD dwIDItem,
4051 LPCWSTR pszLabel)
4053 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4054 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4055 HRESULT hr;
4056 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4058 if(!ctrl) return E_FAIL;
4060 switch(ctrl->type)
4062 case IDLG_CCTRL_COMBOBOX:
4064 UINT index;
4065 cctrl_item* item;
4067 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4069 if (FAILED(hr)) return hr;
4071 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
4072 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
4074 return S_OK;
4076 case IDLG_CCTRL_MENU:
4077 case IDLG_CCTRL_OPENDROPDOWN:
4079 cctrl_item* item;
4080 HMENU hmenu;
4082 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4084 if (FAILED(hr)) return hr;
4086 if (ctrl->type == IDLG_CCTRL_MENU)
4088 TBBUTTON tbb;
4089 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4090 hmenu = (HMENU)tbb.dwData;
4092 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4093 hmenu = This->hmenu_opendropdown;
4095 AppendMenuW(hmenu, MF_STRING, dwIDItem, pszLabel);
4096 return S_OK;
4098 case IDLG_CCTRL_RADIOBUTTONLIST:
4100 cctrl_item* item;
4102 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4104 if (SUCCEEDED(hr))
4106 item->hwnd = CreateWindowExW(0, WC_BUTTONW, pszLabel,
4107 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|BS_RADIOBUTTON|BS_MULTILINE,
4108 0, 0, 0, 0, ctrl->hwnd, ULongToHandle(dwIDItem), COMDLG32_hInstance, 0);
4110 if (!item->hwnd)
4112 ERR("Failed to create radio button\n");
4113 list_remove(&item->entry);
4114 item_free(item);
4115 return E_FAIL;
4119 return hr;
4121 default:
4122 break;
4125 return E_NOINTERFACE; /* win7 */
4128 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
4129 DWORD dwIDCtl,
4130 DWORD dwIDItem)
4132 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4133 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4134 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
4136 if(!ctrl) return E_FAIL;
4138 switch(ctrl->type)
4140 case IDLG_CCTRL_COMBOBOX:
4142 cctrl_item* item;
4143 DWORD position;
4145 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4147 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
4149 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0) == CB_ERR)
4150 return E_FAIL;
4153 list_remove(&item->entry);
4154 item_free(item);
4156 return S_OK;
4158 case IDLG_CCTRL_MENU:
4159 case IDLG_CCTRL_OPENDROPDOWN:
4161 HMENU hmenu;
4162 cctrl_item* item;
4164 item = get_item(ctrl, dwIDItem, 0, NULL);
4166 if (!item)
4167 return E_UNEXPECTED;
4169 if (item->cdcstate & CDCS_VISIBLE)
4171 if (ctrl->type == IDLG_CCTRL_MENU)
4173 TBBUTTON tbb;
4174 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4175 hmenu = (HMENU)tbb.dwData;
4177 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4178 hmenu = This->hmenu_opendropdown;
4180 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
4181 return E_UNEXPECTED;
4184 list_remove(&item->entry);
4185 item_free(item);
4187 return S_OK;
4189 case IDLG_CCTRL_RADIOBUTTONLIST:
4191 cctrl_item* item;
4193 item = get_item(ctrl, dwIDItem, 0, NULL);
4195 if (!item)
4196 return E_UNEXPECTED;
4198 list_remove(&item->entry);
4199 item_free(item);
4201 return S_OK;
4203 default:
4204 break;
4207 return E_FAIL;
4210 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
4211 DWORD dwIDCtl)
4213 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4214 TRACE("%p (%d)\n", This, dwIDCtl);
4216 /* Not implemented by native */
4217 return E_NOTIMPL;
4220 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
4221 DWORD dwIDCtl,
4222 DWORD dwIDItem,
4223 CDCONTROLSTATEF *pdwState)
4225 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4226 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4227 TRACE("%p (%d, %d, %p)\n", This, dwIDCtl, dwIDItem, pdwState);
4229 if(!ctrl) return E_FAIL;
4231 switch(ctrl->type)
4233 case IDLG_CCTRL_COMBOBOX:
4234 case IDLG_CCTRL_MENU:
4235 case IDLG_CCTRL_OPENDROPDOWN:
4236 case IDLG_CCTRL_RADIOBUTTONLIST:
4238 cctrl_item* item;
4240 item = get_item(ctrl, dwIDItem, 0, NULL);
4242 if (!item)
4243 return E_UNEXPECTED;
4245 *pdwState = item->cdcstate;
4247 return S_OK;
4249 default:
4250 break;
4253 return E_FAIL;
4256 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
4257 DWORD dwIDCtl,
4258 DWORD dwIDItem,
4259 CDCONTROLSTATEF dwState)
4261 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4262 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4263 TRACE("%p (%d, %d, %x)\n", This, dwIDCtl, dwIDItem, dwState);
4265 if(!ctrl) return E_FAIL;
4267 switch(ctrl->type)
4269 case IDLG_CCTRL_COMBOBOX:
4271 cctrl_item* item;
4272 BOOL visible, was_visible;
4273 DWORD position;
4275 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4277 if (!item)
4278 return E_UNEXPECTED;
4280 visible = ((dwState & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4281 was_visible = ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4283 if (visible && !was_visible)
4285 SendMessageW(ctrl->hwnd, CB_INSERTSTRING, position, (LPARAM)item->label);
4286 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, position, dwIDItem);
4288 else if (!visible && was_visible)
4290 SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0);
4293 item->cdcstate = dwState;
4295 return S_OK;
4297 case IDLG_CCTRL_MENU:
4298 case IDLG_CCTRL_OPENDROPDOWN:
4300 HMENU hmenu;
4301 cctrl_item* item;
4302 CDCONTROLSTATEF prev_state;
4303 DWORD position;
4305 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, &position);
4307 if (!item)
4308 return E_UNEXPECTED;
4310 prev_state = item->cdcstate;
4312 if (ctrl->type == IDLG_CCTRL_MENU)
4314 TBBUTTON tbb;
4315 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4316 hmenu = (HMENU)tbb.dwData;
4318 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4319 hmenu = This->hmenu_opendropdown;
4321 if (dwState & CDCS_VISIBLE)
4323 if (prev_state & CDCS_VISIBLE)
4325 /* change state */
4326 EnableMenuItem(hmenu, dwIDItem,
4327 MF_BYCOMMAND|((dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED));
4329 else
4331 /* show item */
4332 MENUITEMINFOW mii;
4334 mii.cbSize = sizeof(mii);
4335 mii.fMask = MIIM_ID|MIIM_STATE|MIIM_STRING;
4336 mii.fState = (dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED;
4337 mii.wID = dwIDItem;
4338 mii.dwTypeData = item->label;
4340 InsertMenuItemW(hmenu, position, TRUE, &mii);
4343 else if (prev_state & CDCS_VISIBLE)
4345 /* hide item */
4346 DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND);
4349 item->cdcstate = dwState;
4351 if (ctrl->type == IDLG_CCTRL_OPENDROPDOWN)
4353 update_control_text(This);
4354 update_layout(This);
4357 return S_OK;
4359 case IDLG_CCTRL_RADIOBUTTONLIST:
4361 cctrl_item* item;
4363 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, NULL);
4365 if (!item)
4366 return E_UNEXPECTED;
4368 /* Oddly, native allows setting this but doesn't seem to do anything with it. */
4369 item->cdcstate = dwState;
4371 return S_OK;
4373 default:
4374 break;
4377 return E_FAIL;
4380 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
4381 DWORD dwIDCtl,
4382 DWORD *pdwIDItem)
4384 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4385 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4386 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
4388 if(!ctrl) return E_FAIL;
4390 switch(ctrl->type)
4392 case IDLG_CCTRL_COMBOBOX:
4394 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
4395 if(index == CB_ERR)
4396 return E_FAIL;
4398 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
4399 return S_OK;
4401 case IDLG_CCTRL_OPENDROPDOWN:
4402 if (This->opendropdown_has_selection)
4404 *pdwIDItem = This->opendropdown_selection;
4405 return S_OK;
4407 else
4409 /* Return first enabled item. */
4410 cctrl_item* item = get_first_item(ctrl);
4412 if (item)
4414 *pdwIDItem = item->id;
4415 return S_OK;
4418 WARN("no enabled items in open dropdown\n");
4419 return E_FAIL;
4421 case IDLG_CCTRL_RADIOBUTTONLIST:
4423 cctrl_item* item;
4425 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
4427 if (SendMessageW(item->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED)
4429 *pdwIDItem = item->id;
4430 return S_OK;
4434 WARN("no checked items in radio button list\n");
4435 return E_FAIL;
4437 default:
4438 FIXME("Unsupported control type %d\n", ctrl->type);
4441 return E_NOTIMPL;
4444 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
4445 DWORD dwIDCtl,
4446 DWORD dwIDItem)
4448 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4449 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4450 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
4452 if(!ctrl) return E_INVALIDARG;
4454 switch(ctrl->type)
4456 case IDLG_CCTRL_COMBOBOX:
4458 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
4460 if(index == -1)
4461 return E_INVALIDARG;
4463 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
4464 return E_FAIL;
4466 return S_OK;
4468 case IDLG_CCTRL_RADIOBUTTONLIST:
4470 cctrl_item* item;
4472 item = get_item(ctrl, dwIDItem, 0, NULL);
4474 if (item)
4476 radiobuttonlist_set_selected_item(This, ctrl, item);
4477 return S_OK;
4480 return E_INVALIDARG;
4482 default:
4483 FIXME("Unsupported control type %d\n", ctrl->type);
4486 return E_INVALIDARG;
4489 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
4490 DWORD dwIDCtl,
4491 LPCWSTR pszLabel)
4493 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4494 customctrl *vg;
4495 HRESULT hr;
4496 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
4498 if(This->cctrl_active_vg)
4499 return E_UNEXPECTED;
4501 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0,
4502 This->cctrl_def_height, &vg);
4503 if(SUCCEEDED(hr))
4505 vg->type = IDLG_CCTRL_VISUALGROUP;
4506 This->cctrl_active_vg = vg;
4509 return hr;
4512 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
4514 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4515 TRACE("%p\n", This);
4517 This->cctrl_active_vg = NULL;
4519 return S_OK;
4522 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
4523 DWORD dwIDCtl)
4525 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4526 FIXME("stub - %p (%d)\n", This, dwIDCtl);
4527 return S_OK;
4530 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
4531 DWORD dwIDCtl,
4532 DWORD dwIDItem,
4533 LPCWSTR pszLabel)
4535 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4536 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4537 return E_NOTIMPL;
4540 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
4541 IFileDialogCustomize_fnQueryInterface,
4542 IFileDialogCustomize_fnAddRef,
4543 IFileDialogCustomize_fnRelease,
4544 IFileDialogCustomize_fnEnableOpenDropDown,
4545 IFileDialogCustomize_fnAddMenu,
4546 IFileDialogCustomize_fnAddPushButton,
4547 IFileDialogCustomize_fnAddComboBox,
4548 IFileDialogCustomize_fnAddRadioButtonList,
4549 IFileDialogCustomize_fnAddCheckButton,
4550 IFileDialogCustomize_fnAddEditBox,
4551 IFileDialogCustomize_fnAddSeparator,
4552 IFileDialogCustomize_fnAddText,
4553 IFileDialogCustomize_fnSetControlLabel,
4554 IFileDialogCustomize_fnGetControlState,
4555 IFileDialogCustomize_fnSetControlState,
4556 IFileDialogCustomize_fnGetEditBoxText,
4557 IFileDialogCustomize_fnSetEditBoxText,
4558 IFileDialogCustomize_fnGetCheckButtonState,
4559 IFileDialogCustomize_fnSetCheckButtonState,
4560 IFileDialogCustomize_fnAddControlItem,
4561 IFileDialogCustomize_fnRemoveControlItem,
4562 IFileDialogCustomize_fnRemoveAllControlItems,
4563 IFileDialogCustomize_fnGetControlItemState,
4564 IFileDialogCustomize_fnSetControlItemState,
4565 IFileDialogCustomize_fnGetSelectedControlItem,
4566 IFileDialogCustomize_fnSetSelectedControlItem,
4567 IFileDialogCustomize_fnStartVisualGroup,
4568 IFileDialogCustomize_fnEndVisualGroup,
4569 IFileDialogCustomize_fnMakeProminent,
4570 IFileDialogCustomize_fnSetControlItemText
4573 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
4575 FileDialogImpl *fdimpl;
4576 HRESULT hr;
4577 IShellFolder *psf;
4578 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
4580 if(!ppv)
4581 return E_POINTER;
4582 if(pUnkOuter)
4583 return CLASS_E_NOAGGREGATION;
4585 fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
4586 if(!fdimpl)
4587 return E_OUTOFMEMORY;
4589 fdimpl->ref = 1;
4590 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
4591 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
4592 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
4593 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
4594 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
4595 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
4597 if(type == ITEMDLG_TYPE_OPEN)
4599 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
4600 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
4601 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
4602 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
4604 else
4606 WCHAR buf[16];
4607 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
4608 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
4609 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
4611 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR));
4612 fdimpl->custom_title = StrDupW(buf);
4613 fdimpl->custom_okbutton = StrDupW(buf);
4616 fdimpl->filterspecs = NULL;
4617 fdimpl->filterspec_count = 0;
4618 fdimpl->filetypeindex = 0;
4620 fdimpl->psia_selection = fdimpl->psia_results = NULL;
4621 fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
4623 list_init(&fdimpl->events_clients);
4624 fdimpl->events_next_cookie = 0;
4626 fdimpl->dlg_hwnd = NULL;
4627 fdimpl->peb = NULL;
4629 fdimpl->set_filename = NULL;
4630 fdimpl->default_ext = NULL;
4631 fdimpl->custom_cancelbutton = fdimpl->custom_filenamelabel = NULL;
4633 fdimpl->client_guid = GUID_NULL;
4635 fdimpl->hmenu_opendropdown = NULL;
4636 fdimpl->hfont_opendropdown = NULL;
4638 /* FIXME: The default folder setting should be restored for the
4639 * application if it was previously set. */
4640 SHGetDesktopFolder(&psf);
4641 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
4642 IShellFolder_Release(psf);
4644 hr = init_custom_controls(fdimpl);
4645 if(FAILED(hr))
4647 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
4648 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4649 return E_FAIL;
4652 hr = IFileDialog2_QueryInterface(&fdimpl->IFileDialog2_iface, riid, ppv);
4653 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4654 return hr;
4657 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4659 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
4662 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4664 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);