comdlg32: Avoid crash in RemoveControlItem.
[wine.git] / dlls / comdlg32 / itemdlg.c
blobf3b9a217e79ad4cdc0fde7b94fa142901b3362cc
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 enum ITEMDLG_TYPE {
52 ITEMDLG_TYPE_OPEN,
53 ITEMDLG_TYPE_SAVE
56 enum ITEMDLG_CCTRL_TYPE {
57 IDLG_CCTRL_MENU,
58 IDLG_CCTRL_PUSHBUTTON,
59 IDLG_CCTRL_COMBOBOX,
60 IDLG_CCTRL_RADIOBUTTONLIST,
61 IDLG_CCTRL_CHECKBUTTON,
62 IDLG_CCTRL_EDITBOX,
63 IDLG_CCTRL_SEPARATOR,
64 IDLG_CCTRL_TEXT,
65 IDLG_CCTRL_OPENDROPDOWN,
66 IDLG_CCTRL_VISUALGROUP
69 typedef struct cctrl_item {
70 DWORD id, parent_id;
71 LPWSTR label;
72 CDCONTROLSTATEF cdcstate;
73 HWND hwnd;
74 struct list entry;
75 } cctrl_item;
77 typedef struct {
78 HWND hwnd, wrapper_hwnd;
79 UINT id, dlgid;
80 enum ITEMDLG_CCTRL_TYPE type;
81 CDCONTROLSTATEF cdcstate;
82 struct list entry;
84 struct list sub_cctrls;
85 struct list sub_cctrls_entry;
86 struct list sub_items;
87 } customctrl;
89 typedef struct {
90 struct list entry;
91 IFileDialogEvents *pfde;
92 DWORD cookie;
93 } events_client;
95 typedef struct FileDialogImpl {
96 IFileDialog2 IFileDialog2_iface;
97 union {
98 IFileOpenDialog IFileOpenDialog_iface;
99 IFileSaveDialog IFileSaveDialog_iface;
100 } u;
101 enum ITEMDLG_TYPE dlg_type;
102 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
103 IServiceProvider IServiceProvider_iface;
104 ICommDlgBrowser3 ICommDlgBrowser3_iface;
105 IOleWindow IOleWindow_iface;
106 IFileDialogCustomize IFileDialogCustomize_iface;
107 LONG ref;
109 FILEOPENDIALOGOPTIONS options;
110 COMDLG_FILTERSPEC *filterspecs;
111 UINT filterspec_count;
112 UINT filetypeindex;
114 struct list events_clients;
115 DWORD events_next_cookie;
117 IShellItemArray *psia_selection;
118 IShellItemArray *psia_results;
119 IShellItem *psi_defaultfolder;
120 IShellItem *psi_setfolder;
121 IShellItem *psi_folder;
123 HWND dlg_hwnd;
124 IExplorerBrowser *peb;
125 DWORD ebevents_cookie;
127 LPWSTR set_filename;
128 LPWSTR default_ext;
129 LPWSTR custom_title;
130 LPWSTR custom_okbutton;
131 LPWSTR custom_cancelbutton;
132 LPWSTR custom_filenamelabel;
134 UINT cctrl_width, cctrl_def_height, cctrls_cols;
135 UINT cctrl_indent, dpi_x, dpi_y;
136 HWND cctrls_hwnd;
137 struct list cctrls;
138 UINT_PTR cctrl_next_dlgid;
139 customctrl *cctrl_active_vg;
141 HMENU hmenu_opendropdown;
142 customctrl cctrl_opendropdown;
143 HFONT hfont_opendropdown;
144 BOOL opendropdown_has_selection;
145 DWORD opendropdown_selection;
147 GUID client_guid;
148 } FileDialogImpl;
150 /**************************************************************************
151 * Event wrappers.
153 static HRESULT events_OnFileOk(FileDialogImpl *This)
155 events_client *cursor;
156 HRESULT hr = S_OK;
157 TRACE("%p\n", This);
159 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
161 TRACE("Notifying %p\n", cursor);
162 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
163 if(FAILED(hr) && hr != E_NOTIMPL)
164 break;
167 if(hr == E_NOTIMPL)
168 hr = S_OK;
170 return hr;
173 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
175 events_client *cursor;
176 HRESULT hr = S_OK;
177 TRACE("%p (%p)\n", This, folder);
179 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
181 TRACE("Notifying %p\n", cursor);
182 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
183 if(FAILED(hr) && hr != E_NOTIMPL)
184 break;
187 if(hr == E_NOTIMPL)
188 hr = S_OK;
190 return hr;
193 static void events_OnFolderChange(FileDialogImpl *This)
195 events_client *cursor;
196 TRACE("%p\n", This);
198 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
200 TRACE("Notifying %p\n", cursor);
201 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
205 static void events_OnSelectionChange(FileDialogImpl *This)
207 events_client *cursor;
208 TRACE("%p\n", This);
210 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
212 TRACE("Notifying %p\n", cursor);
213 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
217 static void events_OnTypeChange(FileDialogImpl *This)
219 events_client *cursor;
220 TRACE("%p\n", This);
222 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
224 TRACE("Notifying %p\n", cursor);
225 IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
229 static HRESULT events_OnOverwrite(FileDialogImpl *This, IShellItem *shellitem)
231 events_client *cursor;
232 HRESULT hr = S_OK;
233 FDE_OVERWRITE_RESPONSE response = FDEOR_DEFAULT;
234 TRACE("%p %p\n", This, shellitem);
236 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
238 TRACE("Notifying %p\n", cursor);
239 hr = IFileDialogEvents_OnOverwrite(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, shellitem, &response);
240 TRACE("<-- hr=%lx response=%u\n", hr, response);
241 if(FAILED(hr) && hr != E_NOTIMPL)
242 break;
245 if(hr == E_NOTIMPL)
246 hr = S_OK;
248 if(SUCCEEDED(hr))
250 if (response == FDEOR_DEFAULT)
252 WCHAR buf[100];
253 int answer;
255 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, buf, 100);
256 answer = MessageBoxW(This->dlg_hwnd, buf, This->custom_title,
257 MB_YESNO | MB_ICONEXCLAMATION);
258 if (answer == IDNO || answer == IDCANCEL)
260 hr = E_FAIL;
263 else if (response == FDEOR_REFUSE)
264 hr = E_FAIL;
267 return hr;
270 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
272 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
275 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
277 events_client *cursor;
278 TRACE("%p\n", This);
280 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
282 IFileDialogControlEvents *pfdce;
283 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
285 TRACE("Notifying %p\n", cursor);
286 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
287 IFileDialogControlEvents_Release(pfdce);
291 return S_OK;
294 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
296 events_client *cursor;
297 TRACE("%p %li %li\n", This, ctl_id, item_id);
299 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
301 IFileDialogControlEvents *pfdce;
302 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
304 TRACE("Notifying %p\n", cursor);
305 IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
306 IFileDialogControlEvents_Release(pfdce);
310 return S_OK;
313 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
315 events_client *cursor;
316 TRACE("%p\n", This);
318 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
320 IFileDialogControlEvents *pfdce;
321 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
323 TRACE("Notifying %p\n", cursor);
324 IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
325 IFileDialogControlEvents_Release(pfdce);
329 return S_OK;
332 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
333 DWORD ctl_id)
335 events_client *cursor;
336 TRACE("%p\n", This);
338 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
340 IFileDialogControlEvents *pfdce;
341 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
343 TRACE("Notifying %p\n", cursor);
344 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
345 IFileDialogControlEvents_Release(pfdce);
349 return S_OK;
352 /**************************************************************************
353 * Helper functions.
355 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
357 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
358 UINT len;
360 if(!hwnd_edit)
362 if(This->set_filename)
364 len = lstrlenW(This->set_filename);
365 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
366 lstrcpyW(*str, This->set_filename);
367 return len;
369 return 0;
372 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
373 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
374 if(!*str)
375 return 0;
377 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
378 return len;
381 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
383 if(This->set_filename)
384 LocalFree(This->set_filename);
386 This->set_filename = str ? StrDupW(str) : NULL;
388 return SetDlgItemTextW(This->dlg_hwnd, IDC_FILENAME, This->set_filename);
391 static void fill_filename_from_selection(FileDialogImpl *This)
393 IShellItem *psi;
394 LPWSTR *names;
395 HRESULT hr;
396 DWORD item_count;
397 UINT valid_count;
398 UINT len_total, i;
400 if(!This->psia_selection)
401 return;
403 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
404 if(FAILED(hr) || !item_count)
405 return;
407 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
409 /* Get names of the selected items */
410 valid_count = 0; len_total = 0;
411 for(i = 0; i < item_count; i++)
413 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
414 if(SUCCEEDED(hr))
416 DWORD attr;
418 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
419 if(SUCCEEDED(hr) &&
420 (( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
421 (!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
422 continue;
424 hr = IShellItem_GetDisplayName(psi, (This->options & FOS_PICKFOLDERS) ? SIGDN_FILESYSPATH : SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
425 if(SUCCEEDED(hr))
427 len_total += lstrlenW(names[valid_count]) + 3;
428 valid_count++;
430 IShellItem_Release(psi);
434 if(valid_count == 1)
436 set_file_name(This, names[0]);
437 CoTaskMemFree(names[0]);
439 else if(valid_count > 1)
441 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
442 LPWSTR cur_point = string;
444 for(i = 0; i < valid_count; i++)
446 LPWSTR file = names[i];
447 *cur_point++ = '\"';
448 lstrcpyW(cur_point, file);
449 cur_point += lstrlenW(file);
450 *cur_point++ = '\"';
451 *cur_point++ = ' ';
452 CoTaskMemFree(file);
454 *(cur_point-1) = '\0';
456 set_file_name(This, string);
457 HeapFree(GetProcessHeap(), 0, string);
460 HeapFree(GetProcessHeap(), 0, names);
461 return;
464 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
466 WCHAR *endpos, *ext;
468 lstrcpyW(buf, spec);
469 if( (endpos = StrChrW(buf, ';')) )
470 *endpos = '\0';
472 ext = PathFindExtensionW(buf);
473 if(StrChrW(ext, '*'))
474 return NULL;
476 return ext;
479 static BOOL shell_item_exists(IShellItem* shellitem)
481 LPWSTR filename;
482 HRESULT hr;
483 BOOL result;
485 hr = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &filename);
486 if (SUCCEEDED(hr))
488 /* FIXME: Implement SFGAO_VALIDATE in Wine and use it instead. */
489 result = (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES);
490 CoTaskMemFree(filename);
492 else
494 SFGAOF attributes;
495 result = SUCCEEDED(IShellItem_GetAttributes(shellitem, SFGAO_VALIDATE, &attributes));
498 return result;
501 static HRESULT on_default_action(FileDialogImpl *This)
503 IShellFolder *psf_parent, *psf_desktop;
504 LPITEMIDLIST *pidla;
505 LPITEMIDLIST current_folder;
506 LPWSTR fn_iter, files = NULL, tmp_files;
507 UINT file_count = 0, len, i;
508 int open_action;
509 HRESULT hr, ret = E_FAIL;
511 len = get_file_name(This, &tmp_files);
512 if(len)
514 UINT size_used;
515 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
516 CoTaskMemFree(tmp_files);
518 if(!file_count) return E_FAIL;
520 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
521 if(FAILED(hr))
523 ERR("Failed to get pidl for current directory.\n");
524 HeapFree(GetProcessHeap(), 0, files);
525 return hr;
528 TRACE("Acting on %d file(s).\n", file_count);
530 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
531 open_action = ONOPEN_OPEN;
532 fn_iter = files;
534 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
536 WCHAR canon_filename[MAX_PATH];
537 psf_parent = NULL;
539 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
541 if( (This->options & FOS_NOVALIDATE) &&
542 !(This->options & FOS_FILEMUSTEXIST) )
543 open_action = ONOPEN_OPEN;
544 else
545 open_action = ONOPEN_BROWSE;
547 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
548 This->options & ~FOS_FILEMUSTEXIST,
549 (This->dlg_type == ITEMDLG_TYPE_SAVE),
550 open_action);
552 /* Add the proper extension */
553 if(open_action == ONOPEN_OPEN)
555 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
557 WCHAR extbuf[MAX_PATH], *newext = NULL;
559 if(This->filterspec_count)
561 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
563 else if(This->default_ext)
565 lstrcpyW(extbuf, L".");
566 lstrcatW(extbuf, This->default_ext);
567 newext = extbuf;
570 if(newext)
572 WCHAR *ext = PathFindExtensionW(canon_filename);
573 if(lstrcmpW(ext, newext))
574 lstrcatW(canon_filename, newext);
577 else
579 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
580 !PathFileExistsW(canon_filename))
582 if(This->default_ext)
584 lstrcatW(canon_filename, L".");
585 lstrcatW(canon_filename, This->default_ext);
587 if(!PathFileExistsW(canon_filename))
589 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
590 open_action = ONOPEN_BROWSE;
593 else
595 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
596 open_action = ONOPEN_BROWSE;
602 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
604 if(psf_parent && !(open_action == ONOPEN_BROWSE))
605 IShellFolder_Release(psf_parent);
607 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
610 HeapFree(GetProcessHeap(), 0, files);
611 ILFree(current_folder);
613 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
614 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
616 switch(open_action)
618 case ONOPEN_SEARCH:
619 FIXME("Filtering not implemented.\n");
620 break;
622 case ONOPEN_BROWSE:
623 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
624 if(FAILED(hr))
625 ERR("Failed to browse to directory: %08lx\n", hr);
627 IShellFolder_Release(psf_parent);
628 break;
630 case ONOPEN_OPEN:
631 hr = SHGetDesktopFolder(&psf_desktop);
632 if(SUCCEEDED(hr))
634 if(This->psia_results)
636 IShellItemArray_Release(This->psia_results);
637 This->psia_results = NULL;
640 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
641 &This->psia_results);
643 IShellFolder_Release(psf_desktop);
645 if(FAILED(hr))
646 break;
648 if(This->options & FOS_PICKFOLDERS)
650 SFGAOF attributes;
651 hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
652 if(hr != S_OK)
654 WCHAR buf[64];
655 LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, ARRAY_SIZE(buf));
657 MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
659 IShellItemArray_Release(This->psia_results);
660 This->psia_results = NULL;
661 break;
665 if((This->options & FOS_OVERWRITEPROMPT) && This->dlg_type == ITEMDLG_TYPE_SAVE)
667 IShellItem *shellitem;
669 for (i=0; SUCCEEDED(hr) && i<file_count; i++)
671 hr = IShellItemArray_GetItemAt(This->psia_results, i, &shellitem);
672 if (SUCCEEDED(hr))
674 if (shell_item_exists(shellitem))
675 hr = events_OnOverwrite(This, shellitem);
677 IShellItem_Release(shellitem);
681 if (FAILED(hr))
682 break;
685 if(events_OnFileOk(This) == S_OK)
686 ret = S_OK;
688 break;
690 default:
691 ERR("Failed.\n");
692 break;
695 /* Clean up */
696 for(i = 0; i < file_count; i++)
697 ILFree(pidla[i]);
698 HeapFree(GetProcessHeap(), 0, pidla);
700 /* Success closes the dialog */
701 return ret;
704 static void show_opendropdown(FileDialogImpl *This)
706 HWND open_hwnd;
707 RECT open_rc;
708 MSG msg;
710 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
712 GetWindowRect(open_hwnd, &open_rc);
714 if (TrackPopupMenu(This->hmenu_opendropdown, 0, open_rc.left, open_rc.bottom, 0, This->dlg_hwnd, NULL) &&
715 PeekMessageW(&msg, This->dlg_hwnd, WM_MENUCOMMAND, WM_MENUCOMMAND, PM_REMOVE))
717 MENUITEMINFOW mii;
719 This->opendropdown_has_selection = TRUE;
721 mii.cbSize = sizeof(mii);
722 mii.fMask = MIIM_ID;
723 GetMenuItemInfoW((HMENU)msg.lParam, msg.wParam, TRUE, &mii);
724 This->opendropdown_selection = mii.wID;
726 if(SUCCEEDED(on_default_action(This)))
727 EndDialog(This->dlg_hwnd, S_OK);
728 else
729 This->opendropdown_has_selection = FALSE;
733 /**************************************************************************
734 * Control item functions.
737 static void item_free(cctrl_item *item)
739 DestroyWindow(item->hwnd);
740 HeapFree(GetProcessHeap(), 0, item->label);
741 HeapFree(GetProcessHeap(), 0, item);
744 static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF visible_flags, DWORD* position)
746 DWORD dummy;
747 cctrl_item* item;
749 if (!position) position = &dummy;
751 *position = 0;
753 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
755 if (item->id == itemid)
756 return item;
758 if ((item->cdcstate & visible_flags) == visible_flags)
759 (*position)++;
762 return NULL;
765 static cctrl_item* get_first_item(customctrl* parent)
767 cctrl_item* item;
769 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
771 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
772 return item;
775 return NULL;
778 static HRESULT add_item(customctrl* parent, DWORD itemid, LPCWSTR label, cctrl_item** result)
780 cctrl_item* item;
781 LPWSTR label_copy;
783 if (get_item(parent, itemid, 0, NULL))
784 return E_INVALIDARG;
786 item = HeapAlloc(GetProcessHeap(), 0, sizeof(*item));
787 label_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(label)+1)*sizeof(WCHAR));
789 if (!item || !label_copy)
791 HeapFree(GetProcessHeap(), 0, item);
792 HeapFree(GetProcessHeap(), 0, label_copy);
793 return E_OUTOFMEMORY;
796 item->id = itemid;
797 item->parent_id = parent->id;
798 lstrcpyW(label_copy, label);
799 item->label = label_copy;
800 item->cdcstate = CDCS_VISIBLE|CDCS_ENABLED;
801 item->hwnd = NULL;
802 list_add_tail(&parent->sub_items, &item->entry);
804 *result = item;
806 return S_OK;
809 /**************************************************************************
810 * Control functions.
812 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
814 customctrl *ctrl, *sub_ctrl;
816 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
818 if(ctrl->dlgid == dlgid)
819 return ctrl;
821 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
822 if(sub_ctrl->dlgid == dlgid)
823 return sub_ctrl;
826 ERR("Failed to find control with dialog id %ld\n", dlgid);
827 return NULL;
830 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
832 customctrl *ctrl, *sub_ctrl;
834 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
836 if(ctrl->id == ctlid)
837 return ctrl;
839 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
840 if(sub_ctrl->id == ctlid)
841 return sub_ctrl;
844 if (This->hmenu_opendropdown && This->cctrl_opendropdown.id == ctlid)
845 return &This->cctrl_opendropdown;
847 TRACE("No existing control with control id %ld\n", ctlid);
848 return NULL;
851 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
853 LPWSTR text;
854 UINT len, final_width;
855 UINT lines, final_height;
856 SIZE size;
857 RECT rc;
858 HDC hdc;
859 WCHAR *c;
860 HFONT font;
862 TRACE("\n");
864 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
865 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
866 if(!text) return;
867 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
869 hdc = GetDC(hctrl);
870 font = (HFONT)SendMessageW(hctrl, WM_GETFONT, 0, 0);
871 font = SelectObject(hdc, font);
872 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
873 SelectObject(hdc, font);
874 ReleaseDC(hctrl, hdc);
876 if(len && multiline)
878 /* FIXME: line-wrap */
879 for(lines = 1, c = text; *c != '\0'; c++)
880 if(*c == '\n') lines++;
882 final_height = size.cy*lines + 2*4;
884 else
886 GetWindowRect(hctrl, &rc);
887 final_height = rc.bottom - rc.top;
890 final_width = min(max(size.cx, min_width) + 4, max_width);
891 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
892 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
894 HeapFree(GetProcessHeap(), 0, text);
897 static UINT ctrl_get_height(customctrl *ctrl) {
898 RECT rc;
899 GetWindowRect(ctrl->wrapper_hwnd, &rc);
900 return rc.bottom - rc.top;
903 static void ctrl_free(customctrl *ctrl)
905 customctrl *sub_cur1, *sub_cur2;
906 cctrl_item *item_cur1, *item_cur2;
908 TRACE("Freeing control %p\n", ctrl);
909 if(ctrl->type == IDLG_CCTRL_MENU)
911 TBBUTTON tbb;
912 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
913 DestroyMenu((HMENU)tbb.dwData);
916 LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
918 list_remove(&sub_cur1->sub_cctrls_entry);
919 ctrl_free(sub_cur1);
922 LIST_FOR_EACH_ENTRY_SAFE(item_cur1, item_cur2, &ctrl->sub_items, cctrl_item, entry)
924 list_remove(&item_cur1->entry);
925 item_free(item_cur1);
928 DestroyWindow(ctrl->hwnd);
929 HeapFree(GetProcessHeap(), 0, ctrl);
932 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
934 RECT rc;
935 UINT total_height;
936 UINT max_width, size;
937 customctrl *sub_ctrl;
939 switch(ctrl->type)
941 case IDLG_CCTRL_PUSHBUTTON:
942 case IDLG_CCTRL_COMBOBOX:
943 case IDLG_CCTRL_CHECKBUTTON:
944 case IDLG_CCTRL_TEXT:
945 size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
946 ctrl_resize(ctrl->hwnd, size, size, TRUE);
947 GetWindowRect(ctrl->hwnd, &rc);
948 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
949 SWP_NOZORDER|SWP_NOMOVE);
950 break;
951 case IDLG_CCTRL_VISUALGROUP:
952 total_height = 0;
953 ctrl_resize(ctrl->hwnd, 0, This->cctrl_indent, TRUE);
955 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
957 customctrl_resize(This, sub_ctrl);
958 SetWindowPos(sub_ctrl->wrapper_hwnd, NULL, This->cctrl_indent, total_height, 0, 0,
959 SWP_NOZORDER|SWP_NOSIZE);
961 total_height += ctrl_get_height(sub_ctrl);
964 /* The label should be right adjusted */
966 UINT width, height;
968 GetWindowRect(ctrl->hwnd, &rc);
969 width = rc.right - rc.left;
970 height = rc.bottom - rc.top;
972 SetWindowPos(ctrl->hwnd, NULL, This->cctrl_indent - width, 0, width, height, SWP_NOZORDER);
975 /* Resize the wrapper window to fit all the sub controls */
976 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, This->cctrl_width + This->cctrl_indent, total_height,
977 SWP_NOZORDER|SWP_NOMOVE);
978 break;
979 case IDLG_CCTRL_RADIOBUTTONLIST:
981 cctrl_item* item;
983 total_height = 0;
984 max_width = 0;
986 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
988 size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
989 ctrl_resize(item->hwnd, size, size, TRUE);
990 SetWindowPos(item->hwnd, NULL, 0, total_height, 0, 0,
991 SWP_NOZORDER|SWP_NOSIZE);
993 GetWindowRect(item->hwnd, &rc);
995 total_height += rc.bottom - rc.top;
996 max_width = max(rc.right - rc.left, max_width);
999 SetWindowPos(ctrl->hwnd, NULL, 0, 0, max_width, total_height,
1000 SWP_NOZORDER|SWP_NOMOVE);
1002 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, max_width, total_height,
1003 SWP_NOZORDER|SWP_NOMOVE);
1005 break;
1007 case IDLG_CCTRL_EDITBOX:
1008 case IDLG_CCTRL_SEPARATOR:
1009 case IDLG_CCTRL_MENU:
1010 case IDLG_CCTRL_OPENDROPDOWN:
1011 /* Nothing */
1012 break;
1016 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
1018 FileDialogImpl *This = crs->lpCreateParams;
1019 TRACE("%p\n", This);
1021 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1022 return TRUE;
1025 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1027 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1029 TRACE("%p, %Ix\n", This, wparam);
1031 if(ctrl)
1033 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
1035 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
1036 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
1038 else
1039 cctrl_event_OnButtonClicked(This, ctrl->id);
1042 return TRUE;
1045 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1047 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1048 TRACE("%p, %p (%Ix)\n", This, ctrl, wparam);
1050 if(ctrl)
1052 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
1053 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
1055 cctrl_event_OnItemSelected(This, ctrl->id, selid);
1057 return TRUE;
1060 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
1062 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
1063 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
1064 POINT pt = { 0, nmtb->rcButton.bottom };
1065 TBBUTTON tbb;
1066 UINT idcmd;
1068 TRACE("%p, %p (%Ix)\n", This, ctrl, lparam);
1070 if(ctrl)
1072 cctrl_event_OnControlActivating(This,ctrl->id);
1074 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1075 ClientToScreen(ctrl->hwnd, &pt);
1076 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
1077 if(idcmd)
1078 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
1081 return TBDDRET_DEFAULT;
1084 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1086 switch(HIWORD(wparam))
1088 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
1089 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
1092 return FALSE;
1095 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1097 NMHDR *nmhdr = (NMHDR*)lparam;
1099 switch(nmhdr->code)
1101 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
1104 return FALSE;
1107 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1109 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1110 customctrl *ctrl;
1111 HWND hwnd_child;
1112 RECT rc;
1114 switch(message)
1116 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
1117 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
1118 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
1119 case WM_SIZE:
1120 hwnd_child = GetPropW(hwnd, L"nfs_child");
1121 ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA);
1122 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
1124 GetClientRect(hwnd, &rc);
1125 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1127 return TRUE;
1130 return DefWindowProcW(hwnd, message, wparam, lparam);
1133 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
1134 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
1135 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
1137 HWND ns_hwnd, control_hwnd, parent_hwnd;
1138 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
1139 customctrl *ctrl;
1141 if(get_cctrl(This, id))
1142 return E_UNEXPECTED; /* Duplicate id */
1144 if(This->cctrl_active_vg)
1145 parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
1146 else
1147 parent_hwnd = This->cctrls_hwnd;
1149 ns_hwnd = CreateWindowExW(0, L"FloatNotifySink", NULL, wsflags,
1150 0, 0, This->cctrl_width, height, parent_hwnd,
1151 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
1152 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
1153 0, 0, This->cctrl_width, height, ns_hwnd,
1154 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
1156 if(!ns_hwnd || !control_hwnd)
1158 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
1159 DestroyWindow(ns_hwnd);
1160 DestroyWindow(control_hwnd);
1162 return E_FAIL;
1165 SetPropW(ns_hwnd, L"nfs_child", control_hwnd);
1167 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
1168 if(!ctrl)
1169 return E_OUTOFMEMORY;
1171 ctrl->hwnd = control_hwnd;
1172 ctrl->wrapper_hwnd = ns_hwnd;
1173 ctrl->id = id;
1174 ctrl->dlgid = This->cctrl_next_dlgid;
1175 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
1176 list_init(&ctrl->sub_cctrls);
1177 list_init(&ctrl->sub_items);
1179 if(This->cctrl_active_vg)
1180 list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
1181 else
1182 list_add_tail(&This->cctrls, &ctrl->entry);
1184 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl);
1186 if(ppctrl) *ppctrl = ctrl;
1188 This->cctrl_next_dlgid++;
1189 return S_OK;
1192 /**************************************************************************
1193 * Container functions.
1195 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
1197 UINT container_height;
1198 UINT column_width;
1199 UINT nr_of_cols;
1200 UINT max_control_height, total_height = 0;
1201 UINT cur_col_pos, cur_row_pos;
1202 customctrl *ctrl;
1203 BOOL fits_height;
1204 UINT cspacing = MulDiv(90, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Columns are spaced with 90px */
1205 UINT rspacing = MulDiv(4, This->dpi_y, USER_DEFAULT_SCREEN_DPI); /* Rows are spaced with 4 px. */
1207 /* Given the new width of the container, this function determines the
1208 * needed height of the container and places the controls according to
1209 * the new layout. Returns the new height.
1212 TRACE("%p\n", This);
1214 column_width = This->cctrl_width + cspacing;
1215 nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
1217 /* We don't need to do anything unless the number of visible columns has changed. */
1218 if(nr_of_cols == This->cctrls_cols)
1220 RECT rc;
1221 GetWindowRect(This->cctrls_hwnd, &rc);
1222 return rc.bottom - rc.top;
1225 This->cctrls_cols = nr_of_cols;
1227 /* Get the size of the tallest control, and the total size of
1228 * all the controls to figure out the number of slots we need.
1230 max_control_height = 0;
1231 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1233 if(ctrl->cdcstate & CDCS_VISIBLE)
1235 UINT control_height = ctrl_get_height(ctrl);
1236 max_control_height = max(max_control_height, control_height);
1238 total_height += control_height + rspacing;
1242 if(!total_height)
1243 return 0;
1245 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
1246 TRACE("Guess: container_height: %d\n",container_height);
1248 /* Incrementally increase container_height until all the controls
1249 * fit.
1251 do {
1252 UINT columns_needed = 1;
1253 cur_row_pos = 0;
1255 fits_height = TRUE;
1256 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1258 if(ctrl->cdcstate & CDCS_VISIBLE)
1260 UINT control_height = ctrl_get_height(ctrl);
1262 if(cur_row_pos + control_height > container_height)
1264 if(++columns_needed > nr_of_cols)
1266 container_height += 1;
1267 fits_height = FALSE;
1268 break;
1270 cur_row_pos = 0;
1273 cur_row_pos += control_height + rspacing;
1276 } while(!fits_height);
1278 TRACE("Final container height: %d\n", container_height);
1280 /* Move the controls to their final destination
1282 cur_col_pos = 0; cur_row_pos = 0;
1283 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1285 if(ctrl->cdcstate & CDCS_VISIBLE)
1287 RECT rc;
1288 UINT control_height, control_indent;
1289 GetWindowRect(ctrl->wrapper_hwnd, &rc);
1290 control_height = rc.bottom - rc.top;
1292 if(cur_row_pos + control_height > container_height)
1294 cur_row_pos = 0;
1295 cur_col_pos += This->cctrl_width + cspacing;
1299 if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
1300 control_indent = 0;
1301 else
1302 control_indent = This->cctrl_indent;
1304 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
1305 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1307 cur_row_pos += control_height + rspacing;
1311 /* Sanity check */
1312 if(cur_row_pos + This->cctrl_width > container_width)
1313 ERR("-- Failed to place controls properly.\n");
1315 return container_height;
1318 static void ctrl_set_font(customctrl *ctrl, HFONT font)
1320 customctrl *sub_ctrl;
1321 cctrl_item* item;
1323 SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1325 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1327 ctrl_set_font(sub_ctrl, font);
1330 if (ctrl->type == IDLG_CCTRL_RADIOBUTTONLIST)
1332 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1334 SendMessageW(item->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1339 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
1341 LONG wndstyle;
1343 if(parent)
1345 customctrl *ctrl;
1346 HFONT font;
1348 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1349 wndstyle &= ~(WS_POPUP);
1350 wndstyle |= WS_CHILD;
1351 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1353 SetParent(This->cctrls_hwnd, parent);
1354 ShowWindow(This->cctrls_hwnd, TRUE);
1356 /* Set the fonts to match the dialog font. */
1357 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
1358 if(!font)
1359 ERR("Failed to get font handle from dialog.\n");
1361 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1363 if(font) ctrl_set_font(ctrl, font);
1364 customctrl_resize(This, ctrl);
1367 else
1369 ShowWindow(This->cctrls_hwnd, FALSE);
1371 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1372 wndstyle &= ~(WS_CHILD);
1373 wndstyle |= WS_POPUP;
1374 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1376 SetParent(This->cctrls_hwnd, NULL);
1380 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
1382 FileDialogImpl *This = crs->lpCreateParams;
1383 TRACE("%p\n", This);
1385 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1386 return TRUE;
1389 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
1391 customctrl *cur1, *cur2;
1392 TRACE("%p\n", This);
1394 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1396 list_remove(&cur1->entry);
1397 ctrl_free(cur1);
1400 return TRUE;
1403 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1405 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1407 switch(umessage)
1409 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1410 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1411 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1414 return FALSE;
1417 static void radiobuttonlist_set_selected_item(FileDialogImpl *This, customctrl *ctrl, cctrl_item *item)
1419 cctrl_item *cursor;
1421 LIST_FOR_EACH_ENTRY(cursor, &ctrl->sub_items, cctrl_item, entry)
1423 SendMessageW(cursor->hwnd, BM_SETCHECK, (cursor == item) ? BST_CHECKED : BST_UNCHECKED, 0);
1427 static LRESULT radiobuttonlist_on_bn_clicked(FileDialogImpl *This, HWND hwnd, HWND child)
1429 DWORD ctrl_id = (DWORD)GetWindowLongPtrW(hwnd, GWLP_ID);
1430 customctrl *ctrl;
1431 cctrl_item *item;
1432 BOOL found_item=FALSE;
1434 ctrl = get_cctrl_from_dlgid(This, ctrl_id);
1436 if (!ctrl)
1438 ERR("Can't find this control\n");
1439 return 0;
1442 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1444 if (item->hwnd == child)
1446 found_item = TRUE;
1447 break;
1451 if (!found_item)
1453 ERR("Can't find control item\n");
1454 return 0;
1457 radiobuttonlist_set_selected_item(This, ctrl, item);
1459 cctrl_event_OnItemSelected(This, ctrl->id, item->id);
1461 return 0;
1464 static LRESULT radiobuttonlist_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1466 switch(HIWORD(wparam))
1468 case BN_CLICKED: return radiobuttonlist_on_bn_clicked(This, hwnd, (HWND)lparam);
1471 return FALSE;
1474 static LRESULT CALLBACK radiobuttonlist_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1476 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1478 switch(message)
1480 case WM_COMMAND: return radiobuttonlist_on_wm_command(This, hwnd, wparam, lparam);
1483 return DefWindowProcW(hwnd, message, wparam, lparam);
1486 static HRESULT init_custom_controls(FileDialogImpl *This)
1488 WNDCLASSW wc;
1489 HDC hdc;
1490 static const WCHAR ctrl_container_classname[] = L"idlg_container_pane";
1492 InitCommonControlsEx(NULL);
1494 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1496 wc.style = CS_HREDRAW | CS_VREDRAW;
1497 wc.lpfnWndProc = ctrl_container_wndproc;
1498 wc.cbClsExtra = 0;
1499 wc.cbWndExtra = 0;
1500 wc.hInstance = COMDLG32_hInstance;
1501 wc.hIcon = 0;
1502 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1503 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1504 wc.lpszMenuName = NULL;
1505 wc.lpszClassName = ctrl_container_classname;
1507 if(!RegisterClassW(&wc)) return E_FAIL;
1510 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1511 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1512 0, 0, 0, 0, NULL, 0,
1513 COMDLG32_hInstance, This);
1514 if(!This->cctrls_hwnd)
1515 return E_FAIL;
1517 hdc = GetDC(This->cctrls_hwnd);
1518 This->dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
1519 This->dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
1520 ReleaseDC(This->cctrls_hwnd, hdc);
1522 This->cctrl_width = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Controls have a fixed width */
1523 This->cctrl_indent = MulDiv(100, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1524 This->cctrl_def_height = MulDiv(23, This->dpi_y, USER_DEFAULT_SCREEN_DPI);
1525 This->cctrls_cols = 0;
1527 This->cctrl_next_dlgid = 0x2000;
1528 list_init(&This->cctrls);
1529 This->cctrl_active_vg = NULL;
1531 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1533 /* Register class for */
1534 if (!GetClassInfoW(COMDLG32_hInstance, L"FloatNotifySink", &wc) ||
1535 wc.hInstance != COMDLG32_hInstance)
1537 wc.style = CS_HREDRAW | CS_VREDRAW;
1538 wc.lpfnWndProc = notifysink_proc;
1539 wc.cbClsExtra = 0;
1540 wc.cbWndExtra = 0;
1541 wc.hInstance = COMDLG32_hInstance;
1542 wc.hIcon = 0;
1543 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1544 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1545 wc.lpszMenuName = NULL;
1546 wc.lpszClassName = L"FloatNotifySink";
1548 if (!RegisterClassW(&wc))
1549 ERR("Failed to register FloatNotifySink window class.\n");
1552 if (!GetClassInfoW(COMDLG32_hInstance, L"RadioButtonList", &wc) ||
1553 wc.hInstance != COMDLG32_hInstance)
1555 wc.style = CS_HREDRAW | CS_VREDRAW;
1556 wc.lpfnWndProc = radiobuttonlist_proc;
1557 wc.cbClsExtra = 0;
1558 wc.cbWndExtra = 0;
1559 wc.hInstance = COMDLG32_hInstance;
1560 wc.hIcon = 0;
1561 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1562 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1563 wc.lpszMenuName = NULL;
1564 wc.lpszClassName = L"RadioButtonList";
1566 if (!RegisterClassW(&wc))
1567 ERR("Failed to register RadioButtonList window class.\n");
1570 return S_OK;
1573 /**************************************************************************
1574 * Window related functions.
1576 static BOOL update_open_dropdown(FileDialogImpl *This)
1578 /* Show or hide the open dropdown button as appropriate */
1579 BOOL show=FALSE, showing;
1580 HWND open_hwnd, dropdown_hwnd;
1582 if (This->hmenu_opendropdown)
1584 INT num_visible_items=0;
1585 cctrl_item* item;
1587 LIST_FOR_EACH_ENTRY(item, &This->cctrl_opendropdown.sub_items, cctrl_item, entry)
1589 if (item->cdcstate & CDCS_VISIBLE)
1591 num_visible_items++;
1592 if (num_visible_items >= 2)
1594 show = TRUE;
1595 break;
1601 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1602 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1604 showing = (GetWindowLongPtrW(dropdown_hwnd, GWL_STYLE) & WS_VISIBLE) != 0;
1606 if (showing != show)
1608 RECT open_rc, dropdown_rc;
1610 GetWindowRect(open_hwnd, &open_rc);
1611 GetWindowRect(dropdown_hwnd, &dropdown_rc);
1613 if (show)
1615 ShowWindow(dropdown_hwnd, SW_SHOW);
1617 SetWindowPos(open_hwnd, NULL, 0, 0,
1618 (open_rc.right - open_rc.left) - (dropdown_rc.right - dropdown_rc.left),
1619 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1621 else
1623 ShowWindow(dropdown_hwnd, SW_HIDE);
1625 SetWindowPos(open_hwnd, NULL, 0, 0,
1626 (open_rc.right - open_rc.left) + (dropdown_rc.right - dropdown_rc.left),
1627 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1631 return show;
1634 static void update_layout(FileDialogImpl *This)
1636 HDWP hdwp;
1637 HWND hwnd;
1638 RECT dialog_rc;
1639 RECT cancel_rc, dropdown_rc, open_rc;
1640 RECT filetype_rc, filename_rc, filenamelabel_rc;
1641 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1642 static const UINT vspacing = 4, hspacing = 4;
1643 static const UINT min_width = 320, min_height = 200;
1644 BOOL show_dropdown;
1646 if (!GetClientRect(This->dlg_hwnd, &dialog_rc))
1648 TRACE("Invalid dialog window, not updating layout\n");
1649 return;
1652 if(dialog_rc.right < min_width || dialog_rc.bottom < min_height)
1654 TRACE("Dialog size (%ld, %ld) too small, not updating layout\n", dialog_rc.right, dialog_rc.bottom);
1655 return;
1658 /****
1659 * Calculate the size of the dialog and all the parts.
1662 /* Cancel button */
1663 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1664 if(hwnd)
1666 int cancel_width, cancel_height;
1667 GetWindowRect(hwnd, &cancel_rc);
1668 cancel_width = cancel_rc.right - cancel_rc.left;
1669 cancel_height = cancel_rc.bottom - cancel_rc.top;
1671 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1672 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1673 cancel_rc.right = cancel_rc.left + cancel_width;
1674 cancel_rc.bottom = cancel_rc.top + cancel_height;
1677 /* Open/Save dropdown */
1678 show_dropdown = update_open_dropdown(This);
1680 if(show_dropdown)
1682 int dropdown_width, dropdown_height;
1683 hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1685 GetWindowRect(hwnd, &dropdown_rc);
1686 dropdown_width = dropdown_rc.right - dropdown_rc.left;
1687 dropdown_height = dropdown_rc.bottom - dropdown_rc.top;
1689 dropdown_rc.left = cancel_rc.left - dropdown_width - hspacing;
1690 dropdown_rc.top = cancel_rc.top;
1691 dropdown_rc.right = dropdown_rc.left + dropdown_width;
1692 dropdown_rc.bottom = dropdown_rc.top + dropdown_height;
1694 else
1696 dropdown_rc.left = dropdown_rc.right = cancel_rc.left - hspacing;
1697 dropdown_rc.top = cancel_rc.top;
1698 dropdown_rc.bottom = cancel_rc.bottom;
1701 /* Open/Save button */
1702 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1703 if(hwnd)
1705 int open_width, open_height;
1706 GetWindowRect(hwnd, &open_rc);
1707 open_width = open_rc.right - open_rc.left;
1708 open_height = open_rc.bottom - open_rc.top;
1710 open_rc.left = dropdown_rc.left - open_width;
1711 open_rc.top = dropdown_rc.top;
1712 open_rc.right = open_rc.left + open_width;
1713 open_rc.bottom = open_rc.top + open_height;
1716 /* The filetype combobox. */
1717 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1718 if(hwnd)
1720 int filetype_width, filetype_height;
1721 GetWindowRect(hwnd, &filetype_rc);
1723 filetype_width = filetype_rc.right - filetype_rc.left;
1724 filetype_height = filetype_rc.bottom - filetype_rc.top;
1726 filetype_rc.right = cancel_rc.right;
1728 filetype_rc.left = filetype_rc.right - filetype_width;
1729 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1730 filetype_rc.bottom = filetype_rc.top + filetype_height;
1732 if(!This->filterspec_count)
1733 filetype_rc.left = filetype_rc.right;
1736 /* Filename label. */
1737 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1738 if(hwnd)
1740 int filetypelabel_width, filetypelabel_height;
1741 GetWindowRect(hwnd, &filenamelabel_rc);
1743 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1744 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1746 filenamelabel_rc.left = 160; /* FIXME */
1747 filenamelabel_rc.top = filetype_rc.top;
1748 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1749 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1752 /* Filename edit box. */
1753 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1754 if(hwnd)
1756 int filename_width, filename_height;
1757 GetWindowRect(hwnd, &filename_rc);
1759 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1760 filename_height = filename_rc.bottom - filename_rc.top;
1762 filename_rc.left = filenamelabel_rc.right + hspacing;
1763 filename_rc.top = filetype_rc.top;
1764 filename_rc.right = filename_rc.left + filename_width;
1765 filename_rc.bottom = filename_rc.top + filename_height;
1768 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1769 if(hwnd)
1771 GetWindowRect(hwnd, &toolbar_rc);
1772 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1775 /* The custom controls */
1776 customctrls_rc.left = dialog_rc.left + hspacing;
1777 customctrls_rc.right = dialog_rc.right - hspacing;
1778 customctrls_rc.bottom = filename_rc.top - vspacing;
1779 customctrls_rc.top = customctrls_rc.bottom -
1780 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1782 /* The ExplorerBrowser control. */
1783 ebrowser_rc.left = dialog_rc.left + hspacing;
1784 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1785 ebrowser_rc.right = dialog_rc.right - hspacing;
1786 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1788 /****
1789 * Move everything to the right place.
1792 /* FIXME: The Save Dialog uses a slightly different layout. */
1793 hdwp = BeginDeferWindowPos(7);
1795 if(hdwp && This->peb)
1796 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1798 if(hdwp && This->cctrls_hwnd)
1799 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1800 customctrls_rc.left, customctrls_rc.top,
1801 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1802 SWP_NOZORDER | SWP_NOACTIVATE);
1804 /* The default controls */
1805 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1806 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1807 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1809 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1810 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1811 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1812 SWP_NOZORDER | SWP_NOACTIVATE);
1814 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1815 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1816 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1818 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1819 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1820 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1822 if(hdwp && This->hmenu_opendropdown && (hwnd = GetDlgItem(This->dlg_hwnd, psh1)))
1823 DeferWindowPos(hdwp, hwnd, NULL, dropdown_rc.left, dropdown_rc.top, 0, 0,
1824 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1826 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1827 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1828 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1830 if(hdwp)
1831 EndDeferWindowPos(hdwp);
1832 else
1833 ERR("Failed to position dialog controls.\n");
1835 return;
1838 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1840 IShellItem *psi_folder;
1841 IObjectWithSite *client;
1842 FOLDERSETTINGS fos;
1843 RECT rc = {0};
1844 HRESULT hr;
1846 /* Create ExplorerBrowser instance */
1847 OleInitialize(NULL);
1849 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1850 &IID_IExplorerBrowser, (void**)&This->peb);
1851 if(FAILED(hr))
1853 ERR("Failed to instantiate ExplorerBrowser control.\n");
1854 return hr;
1857 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES | EBO_NOBORDER);
1859 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1860 if(FAILED(hr))
1862 ERR("Failed to initialize the ExplorerBrowser control.\n");
1863 IExplorerBrowser_Release(This->peb);
1864 This->peb = NULL;
1865 return hr;
1867 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1868 if(FAILED(hr))
1869 ERR("Advise (ExplorerBrowser) failed.\n");
1871 /* Get previous options? */
1872 fos.ViewMode = fos.fFlags = 0;
1873 if(!(This->options & FOS_ALLOWMULTISELECT))
1874 fos.fFlags |= FWF_SINGLESEL;
1876 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1878 hr = IExplorerBrowser_QueryInterface(This->peb, &IID_IObjectWithSite, (void**)&client);
1879 if (hr == S_OK)
1881 hr = IObjectWithSite_SetSite(client, (IUnknown*)&This->IFileDialog2_iface);
1882 IObjectWithSite_Release(client);
1883 if(FAILED(hr))
1884 ERR("SetSite failed, 0x%08lx\n", hr);
1887 /* Browse somewhere */
1888 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1889 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1891 return S_OK;
1894 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1896 HWND htoolbar;
1897 TBADDBITMAP tbab;
1898 TBBUTTON button[2];
1899 int height;
1901 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1902 0, 0, 0, 0,
1903 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1905 tbab.hInst = HINST_COMMCTRL;
1906 tbab.nID = IDB_HIST_LARGE_COLOR;
1907 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1909 button[0].iBitmap = HIST_BACK;
1910 button[0].idCommand = IDC_NAVBACK;
1911 button[0].fsState = TBSTATE_ENABLED;
1912 button[0].fsStyle = BTNS_BUTTON;
1913 button[0].dwData = 0;
1914 button[0].iString = 0;
1916 button[1].iBitmap = HIST_FORWARD;
1917 button[1].idCommand = IDC_NAVFORWARD;
1918 button[1].fsState = TBSTATE_ENABLED;
1919 button[1].fsStyle = BTNS_BUTTON;
1920 button[1].dwData = 0;
1921 button[1].iString = 0;
1923 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1924 height = MulDiv(24, This->dpi_y, USER_DEFAULT_SCREEN_DPI);
1925 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(height, height));
1926 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1929 static void update_control_text(FileDialogImpl *This)
1931 HWND hitem;
1932 LPCWSTR custom_okbutton;
1933 cctrl_item* item;
1934 UINT min_width = MulDiv(50, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1935 UINT max_width = MulDiv(250, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1937 if(This->custom_title)
1938 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1940 if(This->hmenu_opendropdown && (item = get_first_item(&This->cctrl_opendropdown)))
1941 custom_okbutton = item->label;
1942 else
1943 custom_okbutton = This->custom_okbutton;
1945 if(custom_okbutton &&
1946 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1948 SetWindowTextW(hitem, custom_okbutton);
1949 ctrl_resize(hitem, min_width, max_width, FALSE);
1952 if(This->custom_cancelbutton &&
1953 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1955 SetWindowTextW(hitem, This->custom_cancelbutton);
1956 ctrl_resize(hitem, min_width, max_width, FALSE);
1959 if(This->custom_filenamelabel &&
1960 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1962 SetWindowTextW(hitem, This->custom_filenamelabel);
1963 ctrl_resize(hitem, min_width, max_width, FALSE);
1967 static LRESULT CALLBACK dropdown_subclass_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1969 if (umessage == WM_LBUTTONDOWN)
1971 FileDialogImpl *This = GetPropW(hwnd, L"itemdlg_This");
1973 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
1974 show_opendropdown(This);
1975 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
1977 return 0;
1980 return CallWindowProcW((WNDPROC)GetPropW(hwnd, L"itemdlg_oldwndproc"), hwnd, umessage, wparam, lparam);
1983 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1985 FileDialogImpl *This = (FileDialogImpl*)lParam;
1986 HWND hitem;
1988 TRACE("(%p, %p)\n", This, hwnd);
1990 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1991 This->dlg_hwnd = hwnd;
1993 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1994 if(hitem) ShowWindow(hitem, SW_HIDE);
1996 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1997 if(hitem) ShowWindow(hitem, SW_HIDE);
1999 /* Fill filetypes combobox, or hide it. */
2000 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
2001 if(This->filterspec_count)
2003 HDC hdc;
2004 HFONT font;
2005 SIZE size;
2006 UINT i, maxwidth = 0;
2008 hdc = GetDC(hitem);
2009 font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
2010 SelectObject(hdc, font);
2012 for(i = 0; i < This->filterspec_count; i++)
2014 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
2016 if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
2017 maxwidth = max(maxwidth, size.cx);
2019 ReleaseDC(hitem, hdc);
2021 if(maxwidth > 0)
2023 maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
2024 SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
2026 else
2027 ERR("Failed to calculate width of filetype dropdown\n");
2029 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
2031 else
2032 ShowWindow(hitem, SW_HIDE);
2034 if(This->set_filename &&
2035 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
2036 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
2038 if(This->hmenu_opendropdown)
2040 HWND dropdown_hwnd;
2041 LOGFONTW lfw, lfw_marlett;
2042 HFONT dialog_font;
2044 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
2046 /* Change dropdown button font to Marlett */
2047 dialog_font = (HFONT)SendMessageW(dropdown_hwnd, WM_GETFONT, 0, 0);
2049 GetObjectW(dialog_font, sizeof(lfw), &lfw);
2051 memset(&lfw_marlett, 0, sizeof(lfw_marlett));
2052 lstrcpyW(lfw_marlett.lfFaceName, L"Marlett");
2053 lfw_marlett.lfHeight = lfw.lfHeight;
2054 lfw_marlett.lfCharSet = SYMBOL_CHARSET;
2056 This->hfont_opendropdown = CreateFontIndirectW(&lfw_marlett);
2058 SendMessageW(dropdown_hwnd, WM_SETFONT, (LPARAM)This->hfont_opendropdown, 0);
2060 /* Subclass button so we can handle LBUTTONDOWN */
2061 SetPropW(dropdown_hwnd, L"itemdlg_This", This);
2062 SetPropW(dropdown_hwnd, L"itemdlg_oldwndproc",
2063 (HANDLE)SetWindowLongPtrW(dropdown_hwnd, GWLP_WNDPROC, (LONG_PTR)dropdown_subclass_proc));
2066 ctrl_container_reparent(This, This->dlg_hwnd);
2067 init_explorerbrowser(This);
2068 init_toolbar(This, hwnd);
2069 update_control_text(This);
2070 update_layout(This);
2072 if(This->filterspec_count)
2073 events_OnTypeChange(This);
2075 if ((hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)))
2076 SetFocus(hitem);
2078 return FALSE;
2081 static LRESULT on_wm_size(FileDialogImpl *This)
2083 update_layout(This);
2084 return FALSE;
2087 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
2089 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
2090 TRACE("%p (%p)\n", This, mmi);
2092 /* FIXME */
2093 mmi->ptMinTrackSize.x = 640;
2094 mmi->ptMinTrackSize.y = 480;
2096 return FALSE;
2099 static LRESULT on_wm_destroy(FileDialogImpl *This)
2101 TRACE("%p\n", This);
2103 if(This->peb)
2105 IExplorerBrowser_Destroy(This->peb);
2106 IExplorerBrowser_Release(This->peb);
2107 This->peb = NULL;
2110 ctrl_container_reparent(This, NULL);
2111 This->dlg_hwnd = NULL;
2113 DeleteObject(This->hfont_opendropdown);
2114 This->hfont_opendropdown = NULL;
2116 return TRUE;
2119 static LRESULT on_idok(FileDialogImpl *This)
2121 TRACE("%p\n", This);
2123 if(SUCCEEDED(on_default_action(This)))
2124 EndDialog(This->dlg_hwnd, S_OK);
2126 return FALSE;
2129 static LRESULT on_idcancel(FileDialogImpl *This)
2131 TRACE("%p\n", This);
2133 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
2135 return FALSE;
2138 static LRESULT on_command_opendropdown(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2140 if(HIWORD(wparam) == BN_CLICKED)
2142 HWND hwnd = (HWND)lparam;
2143 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
2144 show_opendropdown(This);
2145 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
2148 return FALSE;
2151 static LRESULT on_browse_back(FileDialogImpl *This)
2153 TRACE("%p\n", This);
2154 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
2155 return FALSE;
2158 static LRESULT on_browse_forward(FileDialogImpl *This)
2160 TRACE("%p\n", This);
2161 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
2162 return FALSE;
2165 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2167 if(HIWORD(wparam) == CBN_SELCHANGE)
2169 IShellView *psv;
2170 HRESULT hr;
2171 LPWSTR filename;
2172 UINT prev_index = This->filetypeindex;
2174 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
2175 TRACE("File type selection changed to %d.\n", This->filetypeindex);
2177 if(prev_index == This->filetypeindex)
2178 return FALSE;
2180 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
2181 if(SUCCEEDED(hr))
2183 IShellView_Refresh(psv);
2184 IShellView_Release(psv);
2187 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
2189 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
2191 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
2192 if(ext)
2194 lstrcpyW(buf, filename);
2196 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
2197 PathRemoveExtensionW(buf);
2199 lstrcatW(buf, ext);
2200 set_file_name(This, buf);
2202 CoTaskMemFree(filename);
2205 /* The documentation claims that OnTypeChange is called only
2206 * when the dialog is opened, but this is obviously not the
2207 * case. */
2208 events_OnTypeChange(This);
2211 return FALSE;
2214 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2216 switch(LOWORD(wparam))
2218 case IDOK: return on_idok(This);
2219 case IDCANCEL: return on_idcancel(This);
2220 case psh1: return on_command_opendropdown(This, wparam, lparam);
2221 case IDC_NAVBACK: return on_browse_back(This);
2222 case IDC_NAVFORWARD: return on_browse_forward(This);
2223 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
2224 default: TRACE("Unknown command.\n");
2226 return FALSE;
2229 static INT_PTR CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
2231 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
2233 switch(umessage)
2235 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
2236 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
2237 case WM_SIZE: return on_wm_size(This);
2238 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
2239 case WM_DESTROY: return on_wm_destroy(This);
2242 return FALSE;
2245 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
2247 INT_PTR res;
2249 SetLastError(0);
2250 res = DialogBoxParamW(COMDLG32_hInstance,
2251 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
2252 parent, itemdlg_dlgproc, (LPARAM)This);
2253 This->dlg_hwnd = NULL;
2254 if(res == -1)
2256 ERR("Failed to show dialog (LastError: %ld)\n", GetLastError());
2257 return E_FAIL;
2260 TRACE("Returning 0x%08lx\n", (HRESULT)res);
2261 return (HRESULT)res;
2264 /**************************************************************************
2265 * IFileDialog implementation
2267 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
2269 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
2272 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
2273 REFIID riid,
2274 void **ppvObject)
2276 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2277 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2279 *ppvObject = NULL;
2280 if(IsEqualGUID(riid, &IID_IUnknown) ||
2281 IsEqualGUID(riid, &IID_IFileDialog) ||
2282 IsEqualGUID(riid, &IID_IFileDialog2))
2284 *ppvObject = iface;
2286 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
2288 *ppvObject = &This->u.IFileOpenDialog_iface;
2290 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
2292 *ppvObject = &This->u.IFileSaveDialog_iface;
2294 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
2296 *ppvObject = &This->IExplorerBrowserEvents_iface;
2298 else if(IsEqualGUID(riid, &IID_IServiceProvider))
2300 *ppvObject = &This->IServiceProvider_iface;
2302 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
2303 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
2304 IsEqualGUID(&IID_ICommDlgBrowser, riid))
2306 *ppvObject = &This->ICommDlgBrowser3_iface;
2308 else if(IsEqualGUID(&IID_IOleWindow, riid))
2310 *ppvObject = &This->IOleWindow_iface;
2312 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
2313 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
2315 *ppvObject = &This->IFileDialogCustomize_iface;
2317 else
2318 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
2320 if(*ppvObject)
2322 IUnknown_AddRef((IUnknown*)*ppvObject);
2323 return S_OK;
2326 return E_NOINTERFACE;
2329 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
2331 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2332 LONG ref = InterlockedIncrement(&This->ref);
2333 TRACE("%p - ref %ld\n", This, ref);
2335 return ref;
2338 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
2340 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2341 LONG ref = InterlockedDecrement(&This->ref);
2342 TRACE("%p - ref %ld\n", This, ref);
2344 if(!ref)
2346 UINT i;
2347 for(i = 0; i < This->filterspec_count; i++)
2349 LocalFree((void*)This->filterspecs[i].pszName);
2350 LocalFree((void*)This->filterspecs[i].pszSpec);
2352 HeapFree(GetProcessHeap(), 0, This->filterspecs);
2354 DestroyWindow(This->cctrls_hwnd);
2356 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
2357 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
2358 if(This->psi_folder) IShellItem_Release(This->psi_folder);
2359 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
2360 if(This->psia_results) IShellItemArray_Release(This->psia_results);
2362 LocalFree(This->set_filename);
2363 LocalFree(This->default_ext);
2364 LocalFree(This->custom_title);
2365 LocalFree(This->custom_okbutton);
2366 LocalFree(This->custom_cancelbutton);
2367 LocalFree(This->custom_filenamelabel);
2369 DestroyMenu(This->hmenu_opendropdown);
2370 DeleteObject(This->hfont_opendropdown);
2372 HeapFree(GetProcessHeap(), 0, This);
2375 return ref;
2378 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
2380 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2381 TRACE("%p (%p)\n", iface, hwndOwner);
2383 This->opendropdown_has_selection = FALSE;
2385 return create_dialog(This, hwndOwner);
2388 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
2389 const COMDLG_FILTERSPEC *rgFilterSpec)
2391 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2392 UINT i;
2393 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
2395 if(!rgFilterSpec)
2396 return E_INVALIDARG;
2398 if(This->filterspecs)
2399 return E_UNEXPECTED;
2401 if(!cFileTypes)
2402 return S_OK;
2404 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
2405 for(i = 0; i < cFileTypes; i++)
2407 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
2408 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
2410 This->filterspec_count = cFileTypes;
2412 return S_OK;
2415 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
2417 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2418 TRACE("%p (%d)\n", This, iFileType);
2420 if(!This->filterspecs)
2421 return E_FAIL;
2423 iFileType = max(iFileType, 1);
2424 iFileType = min(iFileType, This->filterspec_count);
2425 This->filetypeindex = iFileType-1;
2427 return S_OK;
2430 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
2432 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2433 TRACE("%p (%p)\n", This, piFileType);
2435 if(!piFileType)
2436 return E_INVALIDARG;
2438 if(This->filterspec_count == 0)
2439 *piFileType = 0;
2440 else
2441 *piFileType = This->filetypeindex + 1;
2443 return S_OK;
2446 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
2448 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2449 events_client *client;
2450 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
2452 if(!pfde || !pdwCookie)
2453 return E_INVALIDARG;
2455 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
2456 client->pfde = pfde;
2457 client->cookie = ++This->events_next_cookie;
2459 IFileDialogEvents_AddRef(pfde);
2460 *pdwCookie = client->cookie;
2462 list_add_tail(&This->events_clients, &client->entry);
2464 return S_OK;
2467 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
2469 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2470 events_client *client, *found = NULL;
2471 TRACE("%p (%ld)\n", This, dwCookie);
2473 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
2475 if(client->cookie == dwCookie)
2477 found = client;
2478 break;
2482 if(found)
2484 list_remove(&found->entry);
2485 IFileDialogEvents_Release(found->pfde);
2486 HeapFree(GetProcessHeap(), 0, found);
2487 return S_OK;
2490 return E_INVALIDARG;
2493 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
2495 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2496 TRACE("%p (0x%lx)\n", This, fos);
2498 if (fos & ~(FOS_OVERWRITEPROMPT | FOS_STRICTFILETYPES | FOS_NOCHANGEDIR | FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM
2499 | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_ALLOWMULTISELECT | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST
2500 | FOS_CREATEPROMPT | FOS_SHAREAWARE | FOS_NOREADONLYRETURN | FOS_NOTESTFILECREATE | FOS_HIDEMRUPLACES
2501 | FOS_HIDEPINNEDPLACES | FOS_NODEREFERENCELINKS | FOS_DONTADDTORECENT | FOS_FORCESHOWHIDDEN
2502 | FOS_DEFAULTNOMINIMODE | FOS_FORCEPREVIEWPANEON | FOS_SUPPORTSTREAMABLEITEMS))
2504 WARN("Invalid option %#lx\n", fos);
2505 return E_INVALIDARG;
2508 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
2510 WCHAR buf[30];
2511 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, ARRAY_SIZE(buf));
2512 IFileDialog2_SetTitle(iface, buf);
2515 This->options = fos;
2517 return S_OK;
2520 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
2522 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2523 TRACE("%p (%p)\n", This, pfos);
2525 if(!pfos)
2526 return E_INVALIDARG;
2528 *pfos = This->options;
2530 return S_OK;
2533 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
2535 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2536 TRACE("%p (%p)\n", This, psi);
2537 if(This->psi_defaultfolder)
2538 IShellItem_Release(This->psi_defaultfolder);
2540 This->psi_defaultfolder = psi;
2542 if(This->psi_defaultfolder)
2543 IShellItem_AddRef(This->psi_defaultfolder);
2545 return S_OK;
2548 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
2550 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2551 TRACE("%p (%p)\n", This, psi);
2552 if(This->psi_setfolder)
2553 IShellItem_Release(This->psi_setfolder);
2555 This->psi_setfolder = psi;
2557 if(This->psi_setfolder)
2558 IShellItem_AddRef(This->psi_setfolder);
2560 return S_OK;
2563 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
2565 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2566 TRACE("%p (%p)\n", This, ppsi);
2567 if(!ppsi)
2568 return E_INVALIDARG;
2570 /* FIXME:
2571 If the dialog is shown, return the current(ly selected) folder. */
2573 *ppsi = NULL;
2574 if(This->psi_folder)
2575 *ppsi = This->psi_folder;
2576 else if(This->psi_setfolder)
2577 *ppsi = This->psi_setfolder;
2578 else if(This->psi_defaultfolder)
2579 *ppsi = This->psi_defaultfolder;
2581 if(*ppsi)
2583 IShellItem_AddRef(*ppsi);
2584 return S_OK;
2587 return E_FAIL;
2590 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
2592 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2593 HRESULT hr;
2594 TRACE("%p (%p)\n", This, ppsi);
2596 if(!ppsi)
2597 return E_INVALIDARG;
2599 if(This->psia_selection)
2601 /* FIXME: Check filename edit box */
2602 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2603 return hr;
2606 return E_FAIL;
2609 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
2611 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2612 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2614 set_file_name(This, pszName);
2616 return S_OK;
2619 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
2621 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2622 TRACE("%p (%p)\n", iface, pszName);
2624 if(!pszName)
2625 return E_INVALIDARG;
2627 *pszName = NULL;
2628 get_file_name(This, pszName);
2629 return *pszName ? S_OK : E_FAIL;
2632 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
2634 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2635 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2637 LocalFree(This->custom_title);
2638 This->custom_title = StrDupW(pszTitle);
2639 update_control_text(This);
2641 return S_OK;
2644 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
2646 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2647 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2649 LocalFree(This->custom_okbutton);
2650 This->custom_okbutton = StrDupW(pszText);
2651 update_control_text(This);
2652 update_layout(This);
2654 return S_OK;
2657 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2659 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2660 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2662 LocalFree(This->custom_filenamelabel);
2663 This->custom_filenamelabel = StrDupW(pszLabel);
2664 update_control_text(This);
2665 update_layout(This);
2667 return S_OK;
2670 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
2672 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2673 HRESULT hr;
2674 TRACE("%p (%p)\n", This, ppsi);
2676 if(!ppsi)
2677 return E_INVALIDARG;
2679 if(This->psia_results)
2681 DWORD item_count;
2682 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2683 if(SUCCEEDED(hr))
2685 if(item_count != 1)
2686 return E_FAIL;
2688 /* Adds a reference. */
2689 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2692 return hr;
2695 return E_UNEXPECTED;
2698 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2700 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2701 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2702 return S_OK;
2705 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2707 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2708 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2710 LocalFree(This->default_ext);
2711 This->default_ext = StrDupW(pszDefaultExtension);
2713 return S_OK;
2716 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2718 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2719 TRACE("%p (0x%08lx)\n", This, hr);
2721 if(This->dlg_hwnd)
2722 EndDialog(This->dlg_hwnd, hr);
2724 return S_OK;
2727 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2729 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2730 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2731 This->client_guid = *guid;
2732 return S_OK;
2735 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2737 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2738 FIXME("stub - %p\n", This);
2739 return E_NOTIMPL;
2742 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2744 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2745 FIXME("stub - %p (%p)\n", This, pFilter);
2746 return E_NOTIMPL;
2749 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2751 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2752 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2754 LocalFree(This->custom_cancelbutton);
2755 This->custom_cancelbutton = StrDupW(pszLabel);
2756 update_control_text(This);
2757 update_layout(This);
2759 return S_OK;
2762 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2764 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2765 FIXME("stub - %p (%p)\n", This, psi);
2766 return E_NOTIMPL;
2769 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2770 IFileDialog2_fnQueryInterface,
2771 IFileDialog2_fnAddRef,
2772 IFileDialog2_fnRelease,
2773 IFileDialog2_fnShow,
2774 IFileDialog2_fnSetFileTypes,
2775 IFileDialog2_fnSetFileTypeIndex,
2776 IFileDialog2_fnGetFileTypeIndex,
2777 IFileDialog2_fnAdvise,
2778 IFileDialog2_fnUnadvise,
2779 IFileDialog2_fnSetOptions,
2780 IFileDialog2_fnGetOptions,
2781 IFileDialog2_fnSetDefaultFolder,
2782 IFileDialog2_fnSetFolder,
2783 IFileDialog2_fnGetFolder,
2784 IFileDialog2_fnGetCurrentSelection,
2785 IFileDialog2_fnSetFileName,
2786 IFileDialog2_fnGetFileName,
2787 IFileDialog2_fnSetTitle,
2788 IFileDialog2_fnSetOkButtonLabel,
2789 IFileDialog2_fnSetFileNameLabel,
2790 IFileDialog2_fnGetResult,
2791 IFileDialog2_fnAddPlace,
2792 IFileDialog2_fnSetDefaultExtension,
2793 IFileDialog2_fnClose,
2794 IFileDialog2_fnSetClientGuid,
2795 IFileDialog2_fnClearClientData,
2796 IFileDialog2_fnSetFilter,
2797 IFileDialog2_fnSetCancelButtonLabel,
2798 IFileDialog2_fnSetNavigationRoot
2801 /**************************************************************************
2802 * IFileOpenDialog
2804 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2806 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2809 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2810 REFIID riid, void **ppvObject)
2812 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2813 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2816 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2818 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2819 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2822 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2824 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2825 return IFileDialog2_Release(&This->IFileDialog2_iface);
2828 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2830 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2831 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2834 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2835 const COMDLG_FILTERSPEC *rgFilterSpec)
2837 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2838 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2841 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2843 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2844 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2847 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2849 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2850 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2853 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2854 DWORD *pdwCookie)
2856 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2857 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2860 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2862 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2863 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2866 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2868 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2869 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2872 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2874 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2875 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2878 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2880 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2881 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2884 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2886 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2887 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2890 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2892 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2893 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2896 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2898 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2899 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2902 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2904 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2905 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2908 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2910 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2911 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2914 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2916 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2917 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2920 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2922 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2923 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2926 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2928 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2929 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2932 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2934 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2935 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2938 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2940 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2941 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2944 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2945 LPCWSTR pszDefaultExtension)
2947 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2948 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2951 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2953 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2954 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2957 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2959 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2960 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2963 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2965 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2966 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2969 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2971 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2972 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2975 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2977 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2978 TRACE("%p (%p)\n", This, ppenum);
2980 *ppenum = This->psia_results;
2982 if(*ppenum)
2984 IShellItemArray_AddRef(*ppenum);
2985 return S_OK;
2988 return E_FAIL;
2991 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2993 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2994 TRACE("%p (%p)\n", This, ppsai);
2996 if(This->psia_selection)
2998 *ppsai = This->psia_selection;
2999 IShellItemArray_AddRef(*ppsai);
3000 return S_OK;
3003 return E_FAIL;
3006 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
3007 IFileOpenDialog_fnQueryInterface,
3008 IFileOpenDialog_fnAddRef,
3009 IFileOpenDialog_fnRelease,
3010 IFileOpenDialog_fnShow,
3011 IFileOpenDialog_fnSetFileTypes,
3012 IFileOpenDialog_fnSetFileTypeIndex,
3013 IFileOpenDialog_fnGetFileTypeIndex,
3014 IFileOpenDialog_fnAdvise,
3015 IFileOpenDialog_fnUnadvise,
3016 IFileOpenDialog_fnSetOptions,
3017 IFileOpenDialog_fnGetOptions,
3018 IFileOpenDialog_fnSetDefaultFolder,
3019 IFileOpenDialog_fnSetFolder,
3020 IFileOpenDialog_fnGetFolder,
3021 IFileOpenDialog_fnGetCurrentSelection,
3022 IFileOpenDialog_fnSetFileName,
3023 IFileOpenDialog_fnGetFileName,
3024 IFileOpenDialog_fnSetTitle,
3025 IFileOpenDialog_fnSetOkButtonLabel,
3026 IFileOpenDialog_fnSetFileNameLabel,
3027 IFileOpenDialog_fnGetResult,
3028 IFileOpenDialog_fnAddPlace,
3029 IFileOpenDialog_fnSetDefaultExtension,
3030 IFileOpenDialog_fnClose,
3031 IFileOpenDialog_fnSetClientGuid,
3032 IFileOpenDialog_fnClearClientData,
3033 IFileOpenDialog_fnSetFilter,
3034 IFileOpenDialog_fnGetResults,
3035 IFileOpenDialog_fnGetSelectedItems
3038 /**************************************************************************
3039 * IFileSaveDialog
3041 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
3043 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
3046 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
3047 REFIID riid,
3048 void **ppvObject)
3050 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3051 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3054 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
3056 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3057 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3060 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
3062 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3063 return IFileDialog2_Release(&This->IFileDialog2_iface);
3066 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
3068 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3069 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
3072 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
3073 const COMDLG_FILTERSPEC *rgFilterSpec)
3075 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3076 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
3079 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
3081 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3082 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
3085 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
3087 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3088 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
3091 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
3092 DWORD *pdwCookie)
3094 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3095 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
3098 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
3100 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3101 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
3104 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
3106 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3107 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
3110 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
3112 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3113 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
3116 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
3118 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3119 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
3122 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
3124 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3125 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
3128 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
3130 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3131 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
3134 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
3136 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3137 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
3140 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
3142 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3143 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
3146 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
3148 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3149 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
3152 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
3154 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3155 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
3158 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
3160 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3161 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
3164 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
3166 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3167 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
3170 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
3172 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3173 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
3176 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
3178 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3179 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
3182 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
3183 LPCWSTR pszDefaultExtension)
3185 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3186 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
3189 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
3191 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3192 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
3195 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
3197 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3198 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
3201 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
3203 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3204 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
3207 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
3209 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3210 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
3213 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
3215 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3216 FIXME("stub - %p (%p)\n", This, psi);
3217 return E_NOTIMPL;
3220 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
3222 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3223 FIXME("stub - %p (%p)\n", This, pStore);
3224 return E_NOTIMPL;
3227 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
3228 IPropertyDescriptionList *pList,
3229 BOOL fAppendDefault)
3231 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3232 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
3233 return E_NOTIMPL;
3236 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
3238 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3239 FIXME("stub - %p (%p)\n", This, ppStore);
3240 return E_NOTIMPL;
3243 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
3244 IShellItem *psi,
3245 IPropertyStore *pStore,
3246 HWND hwnd,
3247 IFileOperationProgressSink *pSink)
3249 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3250 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
3251 return E_NOTIMPL;
3254 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
3255 IFileSaveDialog_fnQueryInterface,
3256 IFileSaveDialog_fnAddRef,
3257 IFileSaveDialog_fnRelease,
3258 IFileSaveDialog_fnShow,
3259 IFileSaveDialog_fnSetFileTypes,
3260 IFileSaveDialog_fnSetFileTypeIndex,
3261 IFileSaveDialog_fnGetFileTypeIndex,
3262 IFileSaveDialog_fnAdvise,
3263 IFileSaveDialog_fnUnadvise,
3264 IFileSaveDialog_fnSetOptions,
3265 IFileSaveDialog_fnGetOptions,
3266 IFileSaveDialog_fnSetDefaultFolder,
3267 IFileSaveDialog_fnSetFolder,
3268 IFileSaveDialog_fnGetFolder,
3269 IFileSaveDialog_fnGetCurrentSelection,
3270 IFileSaveDialog_fnSetFileName,
3271 IFileSaveDialog_fnGetFileName,
3272 IFileSaveDialog_fnSetTitle,
3273 IFileSaveDialog_fnSetOkButtonLabel,
3274 IFileSaveDialog_fnSetFileNameLabel,
3275 IFileSaveDialog_fnGetResult,
3276 IFileSaveDialog_fnAddPlace,
3277 IFileSaveDialog_fnSetDefaultExtension,
3278 IFileSaveDialog_fnClose,
3279 IFileSaveDialog_fnSetClientGuid,
3280 IFileSaveDialog_fnClearClientData,
3281 IFileSaveDialog_fnSetFilter,
3282 IFileSaveDialog_fnSetSaveAsItem,
3283 IFileSaveDialog_fnSetProperties,
3284 IFileSaveDialog_fnSetCollectedProperties,
3285 IFileSaveDialog_fnGetProperties,
3286 IFileSaveDialog_fnApplyProperties
3289 /**************************************************************************
3290 * IExplorerBrowserEvents implementation
3292 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
3294 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
3297 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
3298 REFIID riid, void **ppvObject)
3300 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3301 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
3303 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3306 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
3308 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3309 TRACE("%p\n", This);
3310 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3313 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
3315 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3316 TRACE("%p\n", This);
3317 return IFileDialog2_Release(&This->IFileDialog2_iface);
3320 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
3321 PCIDLIST_ABSOLUTE pidlFolder)
3323 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3324 IShellItem *psi;
3325 HRESULT hr;
3326 TRACE("%p (%p)\n", This, pidlFolder);
3328 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
3329 if(SUCCEEDED(hr))
3331 hr = events_OnFolderChanging(This, psi);
3332 IShellItem_Release(psi);
3334 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
3335 if(hr == S_FALSE)
3336 hr = E_FAIL;
3338 return hr;
3340 else
3341 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
3343 return S_OK;
3346 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
3347 IShellView *psv)
3349 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3350 TRACE("%p (%p)\n", This, psv);
3351 return S_OK;
3354 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
3355 PCIDLIST_ABSOLUTE pidlFolder)
3357 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3358 HRESULT hr;
3359 TRACE("%p (%p)\n", This, pidlFolder);
3361 if(This->psi_folder)
3362 IShellItem_Release(This->psi_folder);
3364 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
3365 if(FAILED(hr))
3367 ERR("Failed to get the current folder.\n");
3368 This->psi_folder = NULL;
3371 events_OnFolderChange(This);
3373 return S_OK;
3376 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
3377 PCIDLIST_ABSOLUTE pidlFolder)
3379 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3380 TRACE("%p (%p)\n", This, pidlFolder);
3381 return S_OK;
3384 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
3385 IExplorerBrowserEvents_fnQueryInterface,
3386 IExplorerBrowserEvents_fnAddRef,
3387 IExplorerBrowserEvents_fnRelease,
3388 IExplorerBrowserEvents_fnOnNavigationPending,
3389 IExplorerBrowserEvents_fnOnViewCreated,
3390 IExplorerBrowserEvents_fnOnNavigationComplete,
3391 IExplorerBrowserEvents_fnOnNavigationFailed
3394 /**************************************************************************
3395 * IServiceProvider implementation
3397 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
3399 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
3402 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
3403 REFIID riid, void **ppvObject)
3405 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3406 TRACE("%p\n", This);
3407 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3410 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
3412 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3413 TRACE("%p\n", This);
3414 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3417 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
3419 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3420 TRACE("%p\n", This);
3421 return IFileDialog2_Release(&This->IFileDialog2_iface);
3424 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
3425 REFGUID guidService,
3426 REFIID riid, void **ppv)
3428 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3429 HRESULT hr = E_NOTIMPL;
3430 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
3432 *ppv = NULL;
3433 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
3434 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
3435 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
3436 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
3437 else
3438 FIXME("Interface %s requested from unknown service %s\n",
3439 debugstr_guid(riid), debugstr_guid(guidService));
3441 return hr;
3444 static const IServiceProviderVtbl vt_IServiceProvider = {
3445 IServiceProvider_fnQueryInterface,
3446 IServiceProvider_fnAddRef,
3447 IServiceProvider_fnRelease,
3448 IServiceProvider_fnQueryService
3451 /**************************************************************************
3452 * ICommDlgBrowser3 implementation
3454 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
3456 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
3459 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
3460 REFIID riid, void **ppvObject)
3462 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3463 TRACE("%p\n", This);
3464 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3467 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
3469 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3470 TRACE("%p\n", This);
3471 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3474 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
3476 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3477 TRACE("%p\n", This);
3478 return IFileDialog2_Release(&This->IFileDialog2_iface);
3481 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
3482 IShellView *shv)
3484 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3485 HRESULT hr;
3486 TRACE("%p (%p)\n", This, shv);
3488 hr = on_default_action(This);
3490 if(SUCCEEDED(hr))
3491 EndDialog(This->dlg_hwnd, S_OK);
3493 return S_OK;
3496 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
3497 IShellView *shv, ULONG uChange )
3499 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3500 IDataObject *new_selection;
3501 HRESULT hr;
3502 TRACE("%p (%p, %lx)\n", This, shv, uChange);
3504 switch(uChange)
3506 case CDBOSC_SELCHANGE:
3507 if(This->psia_selection)
3509 IShellItemArray_Release(This->psia_selection);
3510 This->psia_selection = NULL;
3513 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
3514 if(SUCCEEDED(hr))
3516 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
3517 (void**)&This->psia_selection);
3518 if(SUCCEEDED(hr))
3520 fill_filename_from_selection(This);
3521 events_OnSelectionChange(This);
3524 IDataObject_Release(new_selection);
3526 break;
3527 default:
3528 TRACE("Unhandled state change\n");
3530 return S_OK;
3533 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
3534 IShellView *shv, LPCITEMIDLIST pidl)
3536 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3537 IShellItem *psi;
3538 LPWSTR filename;
3539 LPITEMIDLIST parent_pidl;
3540 HRESULT hr;
3541 ULONG attr;
3542 TRACE("%p (%p, %p)\n", This, shv, pidl);
3544 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
3545 return S_OK;
3547 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3548 if(SUCCEEDED(hr))
3550 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3551 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3552 ILFree(parent_pidl);
3553 ILFree(full_pidl);
3555 if(FAILED(hr))
3557 ERR("Failed to get shellitem (%08lx).\n", hr);
3558 return S_OK;
3561 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3562 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3564 IShellItem_Release(psi);
3565 return S_OK;
3568 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
3570 IShellItem_Release(psi);
3571 return S_FALSE;
3574 hr = S_OK;
3575 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
3577 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
3578 hr = S_FALSE;
3579 CoTaskMemFree(filename);
3582 IShellItem_Release(psi);
3583 return hr;
3586 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
3587 IShellView *ppshv, DWORD dwNotifyType)
3589 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3590 FIXME("Stub: %p (%p, 0x%lx)\n", This, ppshv, dwNotifyType);
3591 return E_NOTIMPL;
3594 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
3595 IShellView *pshv,
3596 LPWSTR pszText, int cchMax)
3598 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3599 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
3600 return E_NOTIMPL;
3603 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
3605 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3606 FIXME("Stub: %p (%p)\n", This, pdwFlags);
3607 return E_NOTIMPL;
3610 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
3611 IShellView *pshv, int iColumn)
3613 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3614 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
3615 return E_NOTIMPL;
3618 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
3619 LPWSTR pszFileSpec, int cchFileSpec)
3621 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3622 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
3623 return E_NOTIMPL;
3626 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
3627 IShellView *pshv)
3629 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3630 FIXME("Stub: %p (%p)\n", This, pshv);
3631 return E_NOTIMPL;
3634 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
3635 ICommDlgBrowser3_fnQueryInterface,
3636 ICommDlgBrowser3_fnAddRef,
3637 ICommDlgBrowser3_fnRelease,
3638 ICommDlgBrowser3_fnOnDefaultCommand,
3639 ICommDlgBrowser3_fnOnStateChange,
3640 ICommDlgBrowser3_fnIncludeObject,
3641 ICommDlgBrowser3_fnNotify,
3642 ICommDlgBrowser3_fnGetDefaultMenuText,
3643 ICommDlgBrowser3_fnGetViewFlags,
3644 ICommDlgBrowser3_fnOnColumnClicked,
3645 ICommDlgBrowser3_fnGetCurrentFilter,
3646 ICommDlgBrowser3_fnOnPreviewCreated
3649 /**************************************************************************
3650 * IOleWindow implementation
3652 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
3654 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
3657 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
3659 FileDialogImpl *This = impl_from_IOleWindow(iface);
3660 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3663 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
3665 FileDialogImpl *This = impl_from_IOleWindow(iface);
3666 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3669 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
3671 FileDialogImpl *This = impl_from_IOleWindow(iface);
3672 return IFileDialog2_Release(&This->IFileDialog2_iface);
3675 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
3677 FileDialogImpl *This = impl_from_IOleWindow(iface);
3678 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
3679 return E_NOTIMPL;
3682 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
3684 FileDialogImpl *This = impl_from_IOleWindow(iface);
3685 TRACE("%p (%p)\n", This, phwnd);
3686 *phwnd = This->dlg_hwnd;
3687 return S_OK;
3690 static const IOleWindowVtbl vt_IOleWindow = {
3691 IOleWindow_fnQueryInterface,
3692 IOleWindow_fnAddRef,
3693 IOleWindow_fnRelease,
3694 IOleWindow_fnGetWindow,
3695 IOleWindow_fnContextSensitiveHelp
3698 /**************************************************************************
3699 * IFileDialogCustomize implementation
3701 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3703 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3706 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3707 REFIID riid, void **ppvObject)
3709 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3710 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3713 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3715 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3716 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3719 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3721 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3722 return IFileDialog2_Release(&This->IFileDialog2_iface);
3725 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3726 DWORD dwIDCtl)
3728 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3729 MENUINFO mi;
3730 TRACE("%p (%ld)\n", This, dwIDCtl);
3732 if (This->hmenu_opendropdown || get_cctrl(This, dwIDCtl))
3733 return E_UNEXPECTED;
3735 This->hmenu_opendropdown = CreatePopupMenu();
3737 if (!This->hmenu_opendropdown)
3738 return E_OUTOFMEMORY;
3740 mi.cbSize = sizeof(mi);
3741 mi.fMask = MIM_STYLE;
3742 mi.dwStyle = MNS_NOTIFYBYPOS;
3743 SetMenuInfo(This->hmenu_opendropdown, &mi);
3745 This->cctrl_opendropdown.hwnd = NULL;
3746 This->cctrl_opendropdown.wrapper_hwnd = NULL;
3747 This->cctrl_opendropdown.id = dwIDCtl;
3748 This->cctrl_opendropdown.dlgid = 0;
3749 This->cctrl_opendropdown.type = IDLG_CCTRL_OPENDROPDOWN;
3750 This->cctrl_opendropdown.cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
3751 list_init(&This->cctrl_opendropdown.sub_cctrls);
3752 list_init(&This->cctrl_opendropdown.sub_items);
3754 return S_OK;
3757 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3758 DWORD dwIDCtl,
3759 LPCWSTR pszLabel)
3761 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3762 customctrl *ctrl;
3763 TBBUTTON tbb;
3764 HRESULT hr;
3765 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszLabel);
3767 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3768 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3769 This->cctrl_def_height, &ctrl);
3770 if(SUCCEEDED(hr))
3772 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3773 ctrl->type = IDLG_CCTRL_MENU;
3775 /* Add the actual button with a popup menu. */
3776 tbb.iBitmap = I_IMAGENONE;
3777 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3778 tbb.iString = (DWORD_PTR)pszLabel;
3779 tbb.fsState = TBSTATE_ENABLED;
3780 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3781 tbb.idCommand = 1;
3783 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3786 return hr;
3789 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3790 DWORD dwIDCtl,
3791 LPCWSTR pszLabel)
3793 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3794 customctrl *ctrl;
3795 HRESULT hr;
3796 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszLabel);
3798 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3799 This->cctrl_def_height, &ctrl);
3800 if(SUCCEEDED(hr))
3801 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3803 return hr;
3806 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3807 DWORD dwIDCtl)
3809 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3810 customctrl *ctrl;
3811 HRESULT hr;
3812 TRACE("%p (%ld)\n", This, dwIDCtl);
3814 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3815 This->cctrl_def_height, &ctrl);
3816 if(SUCCEEDED(hr))
3817 ctrl->type = IDLG_CCTRL_COMBOBOX;
3819 return hr;
3822 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3823 DWORD dwIDCtl)
3825 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3826 customctrl *ctrl;
3827 HRESULT hr;
3828 TRACE("%p (%ld)\n", This, dwIDCtl);
3830 hr = cctrl_create_new(This, dwIDCtl, NULL, L"RadioButtonList", 0, 0, 0, &ctrl);
3831 if(SUCCEEDED(hr))
3833 ctrl->type = IDLG_CCTRL_RADIOBUTTONLIST;
3834 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)This);
3837 return hr;
3840 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3841 DWORD dwIDCtl,
3842 LPCWSTR pszLabel,
3843 BOOL bChecked)
3845 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3846 customctrl *ctrl;
3847 HRESULT hr;
3848 TRACE("%p (%ld, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3850 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0,
3851 This->cctrl_def_height, &ctrl);
3852 if(SUCCEEDED(hr))
3854 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3855 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3858 return hr;
3861 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3862 DWORD dwIDCtl,
3863 LPCWSTR pszText)
3865 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3866 customctrl *ctrl;
3867 HRESULT hr;
3868 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszText);
3870 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3871 This->cctrl_def_height, &ctrl);
3872 if(SUCCEEDED(hr))
3873 ctrl->type = IDLG_CCTRL_EDITBOX;
3875 return hr;
3878 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3879 DWORD dwIDCtl)
3881 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3882 customctrl *ctrl;
3883 HRESULT hr;
3884 TRACE("%p (%ld)\n", This, dwIDCtl);
3886 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3887 GetSystemMetrics(SM_CYEDGE), &ctrl);
3888 if(SUCCEEDED(hr))
3889 ctrl->type = IDLG_CCTRL_SEPARATOR;
3891 return hr;
3894 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3895 DWORD dwIDCtl,
3896 LPCWSTR pszText)
3898 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3899 customctrl *ctrl;
3900 HRESULT hr;
3901 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszText);
3903 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3904 This->cctrl_def_height, &ctrl);
3905 if(SUCCEEDED(hr))
3906 ctrl->type = IDLG_CCTRL_TEXT;
3908 return hr;
3911 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3912 DWORD dwIDCtl,
3913 LPCWSTR pszLabel)
3915 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3916 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3917 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pszLabel);
3919 if(!ctrl) return E_INVALIDARG;
3921 switch(ctrl->type)
3923 case IDLG_CCTRL_MENU:
3924 case IDLG_CCTRL_PUSHBUTTON:
3925 case IDLG_CCTRL_CHECKBUTTON:
3926 case IDLG_CCTRL_TEXT:
3927 case IDLG_CCTRL_VISUALGROUP:
3928 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3929 break;
3930 case IDLG_CCTRL_OPENDROPDOWN:
3931 return E_NOTIMPL;
3932 default:
3933 break;
3936 return S_OK;
3939 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3940 DWORD dwIDCtl,
3941 CDCONTROLSTATEF *pdwState)
3943 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3944 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3945 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pdwState);
3947 if(!ctrl || ctrl->type == IDLG_CCTRL_OPENDROPDOWN) return E_NOTIMPL;
3949 *pdwState = ctrl->cdcstate;
3950 return S_OK;
3953 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3954 DWORD dwIDCtl,
3955 CDCONTROLSTATEF dwState)
3957 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3958 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3959 TRACE("%p (%ld, %x)\n", This, dwIDCtl, dwState);
3961 if(ctrl && ctrl->hwnd)
3963 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3965 if(dwState & CDCS_ENABLED)
3966 wndstyle &= ~(WS_DISABLED);
3967 else
3968 wndstyle |= WS_DISABLED;
3970 if(dwState & CDCS_VISIBLE)
3971 wndstyle |= WS_VISIBLE;
3972 else
3973 wndstyle &= ~(WS_VISIBLE);
3975 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3977 /* We save the state separately since at least one application
3978 * relies on being able to hide a control. */
3979 ctrl->cdcstate = dwState;
3982 return S_OK;
3985 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3986 DWORD dwIDCtl,
3987 WCHAR **ppszText)
3989 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3990 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3991 WCHAR len, *text;
3992 TRACE("%p (%ld, %p)\n", This, dwIDCtl, ppszText);
3994 if(!ctrl || !ctrl->hwnd || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
3995 return E_FAIL;
3997 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
3998 if(!text) return E_FAIL;
4000 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
4001 *ppszText = text;
4002 return S_OK;
4005 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
4006 DWORD dwIDCtl,
4007 LPCWSTR pszText)
4009 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4010 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4011 TRACE("%p (%ld, %s)\n", This, dwIDCtl, debugstr_w(pszText));
4013 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
4014 return E_FAIL;
4016 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
4017 return S_OK;
4020 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
4021 DWORD dwIDCtl,
4022 BOOL *pbChecked)
4024 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4025 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4026 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pbChecked);
4028 if(ctrl && ctrl->hwnd)
4029 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
4031 return S_OK;
4034 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
4035 DWORD dwIDCtl,
4036 BOOL bChecked)
4038 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4039 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4040 TRACE("%p (%ld, %d)\n", This, dwIDCtl, bChecked);
4042 if(ctrl && ctrl->hwnd)
4043 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
4045 return S_OK;
4048 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
4050 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
4051 UINT i;
4052 if(!count || (count == CB_ERR))
4053 return -1;
4055 for(i = 0; i < count; i++)
4056 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
4057 return i;
4059 TRACE("Item with id %ld not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
4060 return -1;
4063 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
4064 DWORD dwIDCtl,
4065 DWORD dwIDItem,
4066 LPCWSTR pszLabel)
4068 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4069 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4070 HRESULT hr;
4071 TRACE("%p (%ld, %ld, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4073 if(!ctrl) return E_FAIL;
4075 switch(ctrl->type)
4077 case IDLG_CCTRL_COMBOBOX:
4079 UINT index;
4080 cctrl_item* item;
4082 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4084 if (FAILED(hr)) return hr;
4086 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
4087 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
4089 return S_OK;
4091 case IDLG_CCTRL_MENU:
4092 case IDLG_CCTRL_OPENDROPDOWN:
4094 cctrl_item* item;
4095 HMENU hmenu;
4097 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4099 if (FAILED(hr)) return hr;
4101 if (ctrl->type == IDLG_CCTRL_MENU)
4103 TBBUTTON tbb;
4104 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4105 hmenu = (HMENU)tbb.dwData;
4107 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4108 hmenu = This->hmenu_opendropdown;
4110 AppendMenuW(hmenu, MF_STRING, dwIDItem, pszLabel);
4111 return S_OK;
4113 case IDLG_CCTRL_RADIOBUTTONLIST:
4115 cctrl_item* item;
4117 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4119 if (SUCCEEDED(hr))
4121 item->hwnd = CreateWindowExW(0, WC_BUTTONW, pszLabel,
4122 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|BS_RADIOBUTTON|BS_MULTILINE,
4123 0, 0, 0, 0, ctrl->hwnd, ULongToHandle(dwIDItem), COMDLG32_hInstance, 0);
4125 if (!item->hwnd)
4127 ERR("Failed to create radio button\n");
4128 list_remove(&item->entry);
4129 item_free(item);
4130 return E_FAIL;
4134 return hr;
4136 default:
4137 break;
4140 return E_NOINTERFACE; /* win7 */
4143 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
4144 DWORD dwIDCtl,
4145 DWORD dwIDItem)
4147 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4148 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4149 TRACE("%p (%ld, %ld)\n", This, dwIDCtl, dwIDItem);
4151 if(!ctrl) return E_FAIL;
4153 switch(ctrl->type)
4155 case IDLG_CCTRL_COMBOBOX:
4157 cctrl_item* item;
4158 DWORD position;
4160 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4162 if (!item)
4163 return E_INVALIDARG;
4165 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
4167 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0) == CB_ERR)
4168 return E_FAIL;
4171 list_remove(&item->entry);
4172 item_free(item);
4174 return S_OK;
4176 case IDLG_CCTRL_MENU:
4177 case IDLG_CCTRL_OPENDROPDOWN:
4179 HMENU hmenu;
4180 cctrl_item* item;
4182 item = get_item(ctrl, dwIDItem, 0, NULL);
4184 if (!item)
4185 return E_UNEXPECTED;
4187 if (item->cdcstate & CDCS_VISIBLE)
4189 if (ctrl->type == IDLG_CCTRL_MENU)
4191 TBBUTTON tbb;
4192 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4193 hmenu = (HMENU)tbb.dwData;
4195 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4196 hmenu = This->hmenu_opendropdown;
4198 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
4199 return E_UNEXPECTED;
4202 list_remove(&item->entry);
4203 item_free(item);
4205 return S_OK;
4207 case IDLG_CCTRL_RADIOBUTTONLIST:
4209 cctrl_item* item;
4211 item = get_item(ctrl, dwIDItem, 0, NULL);
4213 if (!item)
4214 return E_UNEXPECTED;
4216 list_remove(&item->entry);
4217 item_free(item);
4219 return S_OK;
4221 default:
4222 break;
4225 return E_FAIL;
4228 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
4229 DWORD dwIDCtl)
4231 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4232 TRACE("%p (%ld)\n", This, dwIDCtl);
4234 /* Not implemented by native */
4235 return E_NOTIMPL;
4238 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
4239 DWORD dwIDCtl,
4240 DWORD dwIDItem,
4241 CDCONTROLSTATEF *pdwState)
4243 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4244 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4245 TRACE("%p (%ld, %ld, %p)\n", This, dwIDCtl, dwIDItem, pdwState);
4247 if(!ctrl) return E_FAIL;
4249 switch(ctrl->type)
4251 case IDLG_CCTRL_COMBOBOX:
4252 case IDLG_CCTRL_MENU:
4253 case IDLG_CCTRL_OPENDROPDOWN:
4254 case IDLG_CCTRL_RADIOBUTTONLIST:
4256 cctrl_item* item;
4258 item = get_item(ctrl, dwIDItem, 0, NULL);
4260 if (!item)
4261 return E_UNEXPECTED;
4263 *pdwState = item->cdcstate;
4265 return S_OK;
4267 default:
4268 break;
4271 return E_FAIL;
4274 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
4275 DWORD dwIDCtl,
4276 DWORD dwIDItem,
4277 CDCONTROLSTATEF dwState)
4279 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4280 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4281 TRACE("%p (%ld, %ld, %x)\n", This, dwIDCtl, dwIDItem, dwState);
4283 if(!ctrl) return E_FAIL;
4285 switch(ctrl->type)
4287 case IDLG_CCTRL_COMBOBOX:
4289 cctrl_item* item;
4290 BOOL visible, was_visible;
4291 DWORD position;
4293 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4295 if (!item)
4296 return E_UNEXPECTED;
4298 visible = ((dwState & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4299 was_visible = ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4301 if (visible && !was_visible)
4303 SendMessageW(ctrl->hwnd, CB_INSERTSTRING, position, (LPARAM)item->label);
4304 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, position, dwIDItem);
4306 else if (!visible && was_visible)
4308 SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0);
4311 item->cdcstate = dwState;
4313 return S_OK;
4315 case IDLG_CCTRL_MENU:
4316 case IDLG_CCTRL_OPENDROPDOWN:
4318 HMENU hmenu;
4319 cctrl_item* item;
4320 CDCONTROLSTATEF prev_state;
4321 DWORD position;
4323 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, &position);
4325 if (!item)
4326 return E_UNEXPECTED;
4328 prev_state = item->cdcstate;
4330 if (ctrl->type == IDLG_CCTRL_MENU)
4332 TBBUTTON tbb;
4333 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4334 hmenu = (HMENU)tbb.dwData;
4336 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4337 hmenu = This->hmenu_opendropdown;
4339 if (dwState & CDCS_VISIBLE)
4341 if (prev_state & CDCS_VISIBLE)
4343 /* change state */
4344 EnableMenuItem(hmenu, dwIDItem,
4345 MF_BYCOMMAND|((dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED));
4347 else
4349 /* show item */
4350 MENUITEMINFOW mii;
4352 mii.cbSize = sizeof(mii);
4353 mii.fMask = MIIM_ID|MIIM_STATE|MIIM_STRING;
4354 mii.fState = (dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED;
4355 mii.wID = dwIDItem;
4356 mii.dwTypeData = item->label;
4358 InsertMenuItemW(hmenu, position, TRUE, &mii);
4361 else if (prev_state & CDCS_VISIBLE)
4363 /* hide item */
4364 DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND);
4367 item->cdcstate = dwState;
4369 if (ctrl->type == IDLG_CCTRL_OPENDROPDOWN)
4371 update_control_text(This);
4372 update_layout(This);
4375 return S_OK;
4377 case IDLG_CCTRL_RADIOBUTTONLIST:
4379 cctrl_item* item;
4381 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, NULL);
4383 if (!item)
4384 return E_UNEXPECTED;
4386 /* Oddly, native allows setting this but doesn't seem to do anything with it. */
4387 item->cdcstate = dwState;
4389 return S_OK;
4391 default:
4392 break;
4395 return E_FAIL;
4398 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
4399 DWORD dwIDCtl,
4400 DWORD *pdwIDItem)
4402 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4403 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4404 TRACE("%p (%ld, %p)\n", This, dwIDCtl, pdwIDItem);
4406 if(!ctrl) return E_FAIL;
4408 switch(ctrl->type)
4410 case IDLG_CCTRL_COMBOBOX:
4412 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
4413 if(index == CB_ERR)
4414 return E_FAIL;
4416 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
4417 return S_OK;
4419 case IDLG_CCTRL_OPENDROPDOWN:
4420 if (This->opendropdown_has_selection)
4422 *pdwIDItem = This->opendropdown_selection;
4423 return S_OK;
4425 else
4427 /* Return first enabled item. */
4428 cctrl_item* item = get_first_item(ctrl);
4430 if (item)
4432 *pdwIDItem = item->id;
4433 return S_OK;
4436 WARN("no enabled items in open dropdown\n");
4437 return E_FAIL;
4439 case IDLG_CCTRL_RADIOBUTTONLIST:
4441 cctrl_item* item;
4443 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
4445 if (SendMessageW(item->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED)
4447 *pdwIDItem = item->id;
4448 return S_OK;
4452 WARN("no checked items in radio button list\n");
4453 return E_FAIL;
4455 default:
4456 FIXME("Unsupported control type %d\n", ctrl->type);
4459 return E_NOTIMPL;
4462 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
4463 DWORD dwIDCtl,
4464 DWORD dwIDItem)
4466 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4467 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4468 TRACE("%p (%ld, %ld)\n", This, dwIDCtl, dwIDItem);
4470 if(!ctrl) return E_INVALIDARG;
4472 switch(ctrl->type)
4474 case IDLG_CCTRL_COMBOBOX:
4476 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
4478 if(index == -1)
4479 return E_INVALIDARG;
4481 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
4482 return E_FAIL;
4484 return S_OK;
4486 case IDLG_CCTRL_RADIOBUTTONLIST:
4488 cctrl_item* item;
4490 item = get_item(ctrl, dwIDItem, 0, NULL);
4492 if (item)
4494 radiobuttonlist_set_selected_item(This, ctrl, item);
4495 return S_OK;
4498 return E_INVALIDARG;
4500 default:
4501 FIXME("Unsupported control type %d\n", ctrl->type);
4504 return E_INVALIDARG;
4507 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
4508 DWORD dwIDCtl,
4509 LPCWSTR pszLabel)
4511 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4512 customctrl *vg;
4513 HRESULT hr;
4514 TRACE("%p (%ld, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
4516 if(This->cctrl_active_vg)
4517 return E_UNEXPECTED;
4519 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0,
4520 This->cctrl_def_height, &vg);
4521 if(SUCCEEDED(hr))
4523 vg->type = IDLG_CCTRL_VISUALGROUP;
4524 This->cctrl_active_vg = vg;
4527 return hr;
4530 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
4532 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4533 TRACE("%p\n", This);
4535 This->cctrl_active_vg = NULL;
4537 return S_OK;
4540 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
4541 DWORD dwIDCtl)
4543 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4544 FIXME("stub - %p (%ld)\n", This, dwIDCtl);
4545 return S_OK;
4548 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
4549 DWORD dwIDCtl,
4550 DWORD dwIDItem,
4551 LPCWSTR pszLabel)
4553 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4554 FIXME("stub - %p (%ld, %ld, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4555 return E_NOTIMPL;
4558 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
4559 IFileDialogCustomize_fnQueryInterface,
4560 IFileDialogCustomize_fnAddRef,
4561 IFileDialogCustomize_fnRelease,
4562 IFileDialogCustomize_fnEnableOpenDropDown,
4563 IFileDialogCustomize_fnAddMenu,
4564 IFileDialogCustomize_fnAddPushButton,
4565 IFileDialogCustomize_fnAddComboBox,
4566 IFileDialogCustomize_fnAddRadioButtonList,
4567 IFileDialogCustomize_fnAddCheckButton,
4568 IFileDialogCustomize_fnAddEditBox,
4569 IFileDialogCustomize_fnAddSeparator,
4570 IFileDialogCustomize_fnAddText,
4571 IFileDialogCustomize_fnSetControlLabel,
4572 IFileDialogCustomize_fnGetControlState,
4573 IFileDialogCustomize_fnSetControlState,
4574 IFileDialogCustomize_fnGetEditBoxText,
4575 IFileDialogCustomize_fnSetEditBoxText,
4576 IFileDialogCustomize_fnGetCheckButtonState,
4577 IFileDialogCustomize_fnSetCheckButtonState,
4578 IFileDialogCustomize_fnAddControlItem,
4579 IFileDialogCustomize_fnRemoveControlItem,
4580 IFileDialogCustomize_fnRemoveAllControlItems,
4581 IFileDialogCustomize_fnGetControlItemState,
4582 IFileDialogCustomize_fnSetControlItemState,
4583 IFileDialogCustomize_fnGetSelectedControlItem,
4584 IFileDialogCustomize_fnSetSelectedControlItem,
4585 IFileDialogCustomize_fnStartVisualGroup,
4586 IFileDialogCustomize_fnEndVisualGroup,
4587 IFileDialogCustomize_fnMakeProminent,
4588 IFileDialogCustomize_fnSetControlItemText
4591 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
4593 FileDialogImpl *fdimpl;
4594 HRESULT hr;
4595 IShellFolder *psf;
4596 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
4598 if(!ppv)
4599 return E_POINTER;
4600 if(pUnkOuter)
4601 return CLASS_E_NOAGGREGATION;
4603 fdimpl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FileDialogImpl));
4604 if(!fdimpl)
4605 return E_OUTOFMEMORY;
4607 fdimpl->ref = 1;
4608 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
4609 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
4610 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
4611 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
4612 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
4613 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
4615 if(type == ITEMDLG_TYPE_OPEN)
4617 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
4618 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
4619 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
4620 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
4622 else
4624 WCHAR buf[16];
4625 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
4626 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
4627 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
4629 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, ARRAY_SIZE(buf));
4630 fdimpl->custom_title = StrDupW(buf);
4631 fdimpl->custom_okbutton = StrDupW(buf);
4634 list_init(&fdimpl->events_clients);
4636 /* FIXME: The default folder setting should be restored for the
4637 * application if it was previously set. */
4638 SHGetDesktopFolder(&psf);
4639 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
4640 IShellFolder_Release(psf);
4642 hr = init_custom_controls(fdimpl);
4643 if(FAILED(hr))
4645 ERR("Failed to initialize custom controls (0x%08lx).\n", hr);
4646 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4647 return E_FAIL;
4650 hr = IFileDialog2_QueryInterface(&fdimpl->IFileDialog2_iface, riid, ppv);
4651 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4652 return hr;
4655 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4657 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
4660 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4662 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);