[COMDLG32] Sync with Wine Staging 3.17. CORE-15127
[reactos.git] / dll / win32 / comdlg32 / itemdlg.c
1 /*
2 * Common Item Dialog
3 *
4 * Copyright 2010,2011 David Hedberg
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #ifndef __REACTOS__ /* Win 7 */
22
23 #include <stdarg.h>
24
25 #define COBJMACROS
26 #define NONAMELESSUNION
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "wingdi.h"
32 #include "winreg.h"
33 #include "shlwapi.h"
34
35 #include "commdlg.h"
36 #include "cdlg.h"
37 #include "filedlgbrowser.h"
38
39 #include "wine/debug.h"
40 #include "wine/list.h"
41
42 #define IDC_NAV_TOOLBAR 200
43 #define IDC_NAVBACK 201
44 #define IDC_NAVFORWARD 202
45
46 #include <initguid.h>
47 /* This seems to be another version of IID_IFileDialogCustomize. If
48 * there is any difference I have yet to find it. */
49 DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F);
50
51 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
52
53 static const WCHAR notifysink_childW[] = {'n','f','s','_','c','h','i','l','d',0};
54 static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0};
55 static const WCHAR radiobuttonlistW[] = {'R','a','d','i','o','B','u','t','t','o','n','L','i','s','t',0};
56
57 enum ITEMDLG_TYPE {
58 ITEMDLG_TYPE_OPEN,
59 ITEMDLG_TYPE_SAVE
60 };
61
62 enum ITEMDLG_CCTRL_TYPE {
63 IDLG_CCTRL_MENU,
64 IDLG_CCTRL_PUSHBUTTON,
65 IDLG_CCTRL_COMBOBOX,
66 IDLG_CCTRL_RADIOBUTTONLIST,
67 IDLG_CCTRL_CHECKBUTTON,
68 IDLG_CCTRL_EDITBOX,
69 IDLG_CCTRL_SEPARATOR,
70 IDLG_CCTRL_TEXT,
71 IDLG_CCTRL_OPENDROPDOWN,
72 IDLG_CCTRL_VISUALGROUP
73 };
74
75 typedef struct cctrl_item {
76 DWORD id, parent_id;
77 LPWSTR label;
78 CDCONTROLSTATEF cdcstate;
79 HWND hwnd;
80 struct list entry;
81 } cctrl_item;
82
83 typedef struct {
84 HWND hwnd, wrapper_hwnd;
85 UINT id, dlgid;
86 enum ITEMDLG_CCTRL_TYPE type;
87 CDCONTROLSTATEF cdcstate;
88 struct list entry;
89
90 struct list sub_cctrls;
91 struct list sub_cctrls_entry;
92 struct list sub_items;
93 } customctrl;
94
95 typedef struct {
96 struct list entry;
97 IFileDialogEvents *pfde;
98 DWORD cookie;
99 } events_client;
100
101 typedef struct FileDialogImpl {
102 IFileDialog2 IFileDialog2_iface;
103 union {
104 IFileOpenDialog IFileOpenDialog_iface;
105 IFileSaveDialog IFileSaveDialog_iface;
106 } u;
107 enum ITEMDLG_TYPE dlg_type;
108 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
109 IServiceProvider IServiceProvider_iface;
110 ICommDlgBrowser3 ICommDlgBrowser3_iface;
111 IOleWindow IOleWindow_iface;
112 IFileDialogCustomize IFileDialogCustomize_iface;
113 LONG ref;
114
115 FILEOPENDIALOGOPTIONS options;
116 COMDLG_FILTERSPEC *filterspecs;
117 UINT filterspec_count;
118 UINT filetypeindex;
119
120 struct list events_clients;
121 DWORD events_next_cookie;
122
123 IShellItemArray *psia_selection;
124 IShellItemArray *psia_results;
125 IShellItem *psi_defaultfolder;
126 IShellItem *psi_setfolder;
127 IShellItem *psi_folder;
128
129 HWND dlg_hwnd;
130 IExplorerBrowser *peb;
131 DWORD ebevents_cookie;
132
133 LPWSTR set_filename;
134 LPWSTR default_ext;
135 LPWSTR custom_title;
136 LPWSTR custom_okbutton;
137 LPWSTR custom_cancelbutton;
138 LPWSTR custom_filenamelabel;
139
140 UINT cctrl_width, cctrl_def_height, cctrls_cols;
141 UINT cctrl_indent, dpi_x, dpi_y;
142 HWND cctrls_hwnd;
143 struct list cctrls;
144 UINT_PTR cctrl_next_dlgid;
145 customctrl *cctrl_active_vg;
146
147 HMENU hmenu_opendropdown;
148 customctrl cctrl_opendropdown;
149 HFONT hfont_opendropdown;
150 BOOL opendropdown_has_selection;
151 DWORD opendropdown_selection;
152
153 GUID client_guid;
154 } FileDialogImpl;
155
156 /**************************************************************************
157 * Event wrappers.
158 */
159 static HRESULT events_OnFileOk(FileDialogImpl *This)
160 {
161 events_client *cursor;
162 HRESULT hr = S_OK;
163 TRACE("%p\n", This);
164
165 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
166 {
167 TRACE("Notifying %p\n", cursor);
168 hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
169 if(FAILED(hr) && hr != E_NOTIMPL)
170 break;
171 }
172
173 if(hr == E_NOTIMPL)
174 hr = S_OK;
175
176 return hr;
177 }
178
179 static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
180 {
181 events_client *cursor;
182 HRESULT hr = S_OK;
183 TRACE("%p (%p)\n", This, folder);
184
185 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
186 {
187 TRACE("Notifying %p\n", cursor);
188 hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
189 if(FAILED(hr) && hr != E_NOTIMPL)
190 break;
191 }
192
193 if(hr == E_NOTIMPL)
194 hr = S_OK;
195
196 return hr;
197 }
198
199 static void events_OnFolderChange(FileDialogImpl *This)
200 {
201 events_client *cursor;
202 TRACE("%p\n", This);
203
204 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
205 {
206 TRACE("Notifying %p\n", cursor);
207 IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
208 }
209 }
210
211 static void events_OnSelectionChange(FileDialogImpl *This)
212 {
213 events_client *cursor;
214 TRACE("%p\n", This);
215
216 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
217 {
218 TRACE("Notifying %p\n", cursor);
219 IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
220 }
221 }
222
223 static void events_OnTypeChange(FileDialogImpl *This)
224 {
225 events_client *cursor;
226 TRACE("%p\n", This);
227
228 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
229 {
230 TRACE("Notifying %p\n", cursor);
231 IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
232 }
233 }
234
235 static HRESULT events_OnOverwrite(FileDialogImpl *This, IShellItem *shellitem)
236 {
237 events_client *cursor;
238 HRESULT hr = S_OK;
239 FDE_OVERWRITE_RESPONSE response = FDEOR_DEFAULT;
240 TRACE("%p %p\n", This, shellitem);
241
242 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
243 {
244 TRACE("Notifying %p\n", cursor);
245 hr = IFileDialogEvents_OnOverwrite(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, shellitem, &response);
246 TRACE("<-- hr=%x response=%u\n", hr, response);
247 if(FAILED(hr) && hr != E_NOTIMPL)
248 break;
249 }
250
251 if(hr == E_NOTIMPL)
252 hr = S_OK;
253
254 if(SUCCEEDED(hr))
255 {
256 if (response == FDEOR_DEFAULT)
257 {
258 WCHAR buf[100];
259 int answer;
260
261 LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, buf, 100);
262 answer = MessageBoxW(This->dlg_hwnd, buf, This->custom_title,
263 MB_YESNO | MB_ICONEXCLAMATION);
264 if (answer == IDNO || answer == IDCANCEL)
265 {
266 hr = E_FAIL;
267 }
268 }
269 else if (response == FDEOR_REFUSE)
270 hr = E_FAIL;
271 }
272
273 return hr;
274 }
275
276 static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
277 {
278 return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
279 }
280
281 static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
282 {
283 events_client *cursor;
284 TRACE("%p\n", This);
285
286 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
287 {
288 IFileDialogControlEvents *pfdce;
289 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
290 {
291 TRACE("Notifying %p\n", cursor);
292 IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
293 IFileDialogControlEvents_Release(pfdce);
294 }
295 }
296
297 return S_OK;
298 }
299
300 static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
301 {
302 events_client *cursor;
303 TRACE("%p %i %i\n", This, ctl_id, item_id);
304
305 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
306 {
307 IFileDialogControlEvents *pfdce;
308 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
309 {
310 TRACE("Notifying %p\n", cursor);
311 IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
312 IFileDialogControlEvents_Release(pfdce);
313 }
314 }
315
316 return S_OK;
317 }
318
319 static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
320 {
321 events_client *cursor;
322 TRACE("%p\n", This);
323
324 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
325 {
326 IFileDialogControlEvents *pfdce;
327 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
328 {
329 TRACE("Notifying %p\n", cursor);
330 IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
331 IFileDialogControlEvents_Release(pfdce);
332 }
333 }
334
335 return S_OK;
336 }
337
338 static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
339 DWORD ctl_id)
340 {
341 events_client *cursor;
342 TRACE("%p\n", This);
343
344 LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
345 {
346 IFileDialogControlEvents *pfdce;
347 if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
348 {
349 TRACE("Notifying %p\n", cursor);
350 IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
351 IFileDialogControlEvents_Release(pfdce);
352 }
353 }
354
355 return S_OK;
356 }
357
358 /**************************************************************************
359 * Helper functions.
360 */
361 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
362 {
363 HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
364 UINT len;
365
366 if(!hwnd_edit)
367 {
368 if(This->set_filename)
369 {
370 len = lstrlenW(This->set_filename);
371 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
372 lstrcpyW(*str, This->set_filename);
373 return len;
374 }
375 return 0;
376 }
377
378 len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
379 *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
380 if(!*str)
381 return 0;
382
383 SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
384 return len;
385 }
386
387 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
388 {
389 if(This->set_filename)
390 LocalFree(This->set_filename);
391
392 This->set_filename = str ? StrDupW(str) : NULL;
393
394 return SetDlgItemTextW(This->dlg_hwnd, IDC_FILENAME, This->set_filename);
395 }
396
397 static void fill_filename_from_selection(FileDialogImpl *This)
398 {
399 IShellItem *psi;
400 LPWSTR *names;
401 HRESULT hr;
402 UINT item_count, valid_count;
403 UINT len_total, i;
404
405 if(!This->psia_selection)
406 return;
407
408 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
409 if(FAILED(hr) || !item_count)
410 return;
411
412 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
413
414 /* Get names of the selected items */
415 valid_count = 0; len_total = 0;
416 for(i = 0; i < item_count; i++)
417 {
418 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
419 if(SUCCEEDED(hr))
420 {
421 UINT attr;
422
423 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
424 if(SUCCEEDED(hr) &&
425 (( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
426 (!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
427 continue;
428
429 hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
430 if(SUCCEEDED(hr))
431 {
432 len_total += lstrlenW(names[valid_count]) + 3;
433 valid_count++;
434 }
435 IShellItem_Release(psi);
436 }
437 }
438
439 if(valid_count == 1)
440 {
441 set_file_name(This, names[0]);
442 CoTaskMemFree(names[0]);
443 }
444 else if(valid_count > 1)
445 {
446 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
447 LPWSTR cur_point = string;
448
449 for(i = 0; i < valid_count; i++)
450 {
451 LPWSTR file = names[i];
452 *cur_point++ = '\"';
453 lstrcpyW(cur_point, file);
454 cur_point += lstrlenW(file);
455 *cur_point++ = '\"';
456 *cur_point++ = ' ';
457 CoTaskMemFree(file);
458 }
459 *(cur_point-1) = '\0';
460
461 set_file_name(This, string);
462 HeapFree(GetProcessHeap(), 0, string);
463 }
464
465 HeapFree(GetProcessHeap(), 0, names);
466 return;
467 }
468
469 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
470 {
471 WCHAR *endpos, *ext;
472
473 lstrcpyW(buf, spec);
474 if( (endpos = StrChrW(buf, ';')) )
475 *endpos = '\0';
476
477 ext = PathFindExtensionW(buf);
478 if(StrChrW(ext, '*'))
479 return NULL;
480
481 return ext;
482 }
483
484 static BOOL shell_item_exists(IShellItem* shellitem)
485 {
486 LPWSTR filename;
487 HRESULT hr;
488 BOOL result;
489
490 hr = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &filename);
491 if (SUCCEEDED(hr))
492 {
493 /* FIXME: Implement SFGAO_VALIDATE in Wine and use it instead. */
494 result = (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES);
495 CoTaskMemFree(filename);
496 }
497 else
498 {
499 SFGAOF attributes;
500 result = SUCCEEDED(IShellItem_GetAttributes(shellitem, SFGAO_VALIDATE, &attributes));
501 }
502
503 return result;
504 }
505
506 static HRESULT on_default_action(FileDialogImpl *This)
507 {
508 IShellFolder *psf_parent, *psf_desktop;
509 LPITEMIDLIST *pidla;
510 LPITEMIDLIST current_folder;
511 LPWSTR fn_iter, files = NULL, tmp_files;
512 UINT file_count = 0, len, i;
513 int open_action;
514 HRESULT hr, ret = E_FAIL;
515
516 len = get_file_name(This, &tmp_files);
517 if(len)
518 {
519 UINT size_used;
520 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
521 CoTaskMemFree(tmp_files);
522 }
523 if(!file_count) return E_FAIL;
524
525 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
526 if(FAILED(hr))
527 {
528 ERR("Failed to get pidl for current directory.\n");
529 HeapFree(GetProcessHeap(), 0, files);
530 return hr;
531 }
532
533 TRACE("Acting on %d file(s).\n", file_count);
534
535 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
536 open_action = ONOPEN_OPEN;
537 fn_iter = files;
538
539 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
540 {
541 WCHAR canon_filename[MAX_PATH];
542 psf_parent = NULL;
543
544 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
545
546 if( (This->options & FOS_NOVALIDATE) &&
547 !(This->options & FOS_FILEMUSTEXIST) )
548 open_action = ONOPEN_OPEN;
549 else
550 open_action = ONOPEN_BROWSE;
551
552 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
553 This->options & ~FOS_FILEMUSTEXIST,
554 (This->dlg_type == ITEMDLG_TYPE_SAVE),
555 open_action);
556
557 /* Add the proper extension */
558 if(open_action == ONOPEN_OPEN)
559 {
560 static const WCHAR dotW[] = {'.',0};
561
562 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
563 {
564 WCHAR extbuf[MAX_PATH], *newext = NULL;
565
566 if(This->filterspec_count)
567 {
568 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
569 }
570 else if(This->default_ext)
571 {
572 lstrcpyW(extbuf, dotW);
573 lstrcatW(extbuf, This->default_ext);
574 newext = extbuf;
575 }
576
577 if(newext)
578 {
579 WCHAR *ext = PathFindExtensionW(canon_filename);
580 if(lstrcmpW(ext, newext))
581 lstrcatW(canon_filename, newext);
582 }
583 }
584 else
585 {
586 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
587 !PathFileExistsW(canon_filename))
588 {
589 if(This->default_ext)
590 {
591 lstrcatW(canon_filename, dotW);
592 lstrcatW(canon_filename, This->default_ext);
593
594 if(!PathFileExistsW(canon_filename))
595 {
596 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
597 open_action = ONOPEN_BROWSE;
598 }
599 }
600 else
601 {
602 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
603 open_action = ONOPEN_BROWSE;
604 }
605 }
606 }
607 }
608
609 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
610
611 if(psf_parent && !(open_action == ONOPEN_BROWSE))
612 IShellFolder_Release(psf_parent);
613
614 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
615 }
616
617 HeapFree(GetProcessHeap(), 0, files);
618 ILFree(current_folder);
619
620 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
621 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
622
623 switch(open_action)
624 {
625 case ONOPEN_SEARCH:
626 FIXME("Filtering not implemented.\n");
627 break;
628
629 case ONOPEN_BROWSE:
630 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
631 if(FAILED(hr))
632 ERR("Failed to browse to directory: %08x\n", hr);
633
634 IShellFolder_Release(psf_parent);
635 break;
636
637 case ONOPEN_OPEN:
638 hr = SHGetDesktopFolder(&psf_desktop);
639 if(SUCCEEDED(hr))
640 {
641 if(This->psia_results)
642 {
643 IShellItemArray_Release(This->psia_results);
644 This->psia_results = NULL;
645 }
646
647 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
648 &This->psia_results);
649
650 IShellFolder_Release(psf_desktop);
651
652 if(FAILED(hr))
653 break;
654
655 if(This->options & FOS_PICKFOLDERS)
656 {
657 SFGAOF attributes;
658 hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
659 if(hr != S_OK)
660 {
661 WCHAR buf[64];
662 LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, ARRAY_SIZE(buf));
663
664 MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
665
666 IShellItemArray_Release(This->psia_results);
667 This->psia_results = NULL;
668 break;
669 }
670 }
671
672 if((This->options & FOS_OVERWRITEPROMPT) && This->dlg_type == ITEMDLG_TYPE_SAVE)
673 {
674 IShellItem *shellitem;
675
676 for (i=0; SUCCEEDED(hr) && i<file_count; i++)
677 {
678 hr = IShellItemArray_GetItemAt(This->psia_results, i, &shellitem);
679 if (SUCCEEDED(hr))
680 {
681 if (shell_item_exists(shellitem))
682 hr = events_OnOverwrite(This, shellitem);
683
684 IShellItem_Release(shellitem);
685 }
686 }
687
688 if (FAILED(hr))
689 break;
690 }
691
692 if(events_OnFileOk(This) == S_OK)
693 ret = S_OK;
694 }
695 break;
696
697 default:
698 ERR("Failed.\n");
699 break;
700 }
701
702 /* Clean up */
703 for(i = 0; i < file_count; i++)
704 ILFree(pidla[i]);
705 HeapFree(GetProcessHeap(), 0, pidla);
706
707 /* Success closes the dialog */
708 return ret;
709 }
710
711 static void show_opendropdown(FileDialogImpl *This)
712 {
713 HWND open_hwnd;
714 RECT open_rc;
715 MSG msg;
716
717 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
718
719 GetWindowRect(open_hwnd, &open_rc);
720
721 if (TrackPopupMenu(This->hmenu_opendropdown, 0, open_rc.left, open_rc.bottom, 0, This->dlg_hwnd, NULL) &&
722 PeekMessageW(&msg, This->dlg_hwnd, WM_MENUCOMMAND, WM_MENUCOMMAND, PM_REMOVE))
723 {
724 MENUITEMINFOW mii;
725
726 This->opendropdown_has_selection = TRUE;
727
728 mii.cbSize = sizeof(mii);
729 mii.fMask = MIIM_ID;
730 GetMenuItemInfoW((HMENU)msg.lParam, msg.wParam, TRUE, &mii);
731 This->opendropdown_selection = mii.wID;
732
733 if(SUCCEEDED(on_default_action(This)))
734 EndDialog(This->dlg_hwnd, S_OK);
735 else
736 This->opendropdown_has_selection = FALSE;
737 }
738 }
739
740 /**************************************************************************
741 * Control item functions.
742 */
743
744 static void item_free(cctrl_item *item)
745 {
746 DestroyWindow(item->hwnd);
747 HeapFree(GetProcessHeap(), 0, item->label);
748 HeapFree(GetProcessHeap(), 0, item);
749 }
750
751 static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF visible_flags, DWORD* position)
752 {
753 DWORD dummy;
754 cctrl_item* item;
755
756 if (!position) position = &dummy;
757
758 *position = 0;
759
760 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
761 {
762 if (item->id == itemid)
763 return item;
764
765 if ((item->cdcstate & visible_flags) == visible_flags)
766 (*position)++;
767 }
768
769 return NULL;
770 }
771
772 static cctrl_item* get_first_item(customctrl* parent)
773 {
774 cctrl_item* item;
775
776 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
777 {
778 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
779 return item;
780 }
781
782 return NULL;
783 }
784
785 static HRESULT add_item(customctrl* parent, DWORD itemid, LPCWSTR label, cctrl_item** result)
786 {
787 cctrl_item* item;
788 LPWSTR label_copy;
789
790 if (get_item(parent, itemid, 0, NULL))
791 return E_INVALIDARG;
792
793 item = HeapAlloc(GetProcessHeap(), 0, sizeof(*item));
794 label_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(label)+1)*sizeof(WCHAR));
795
796 if (!item || !label_copy)
797 {
798 HeapFree(GetProcessHeap(), 0, item);
799 HeapFree(GetProcessHeap(), 0, label_copy);
800 return E_OUTOFMEMORY;
801 }
802
803 item->id = itemid;
804 item->parent_id = parent->id;
805 lstrcpyW(label_copy, label);
806 item->label = label_copy;
807 item->cdcstate = CDCS_VISIBLE|CDCS_ENABLED;
808 item->hwnd = NULL;
809 list_add_tail(&parent->sub_items, &item->entry);
810
811 *result = item;
812
813 return S_OK;
814 }
815
816 /**************************************************************************
817 * Control functions.
818 */
819 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
820 {
821 customctrl *ctrl, *sub_ctrl;
822
823 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
824 {
825 if(ctrl->dlgid == dlgid)
826 return ctrl;
827
828 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
829 if(sub_ctrl->dlgid == dlgid)
830 return sub_ctrl;
831 }
832
833 ERR("Failed to find control with dialog id %d\n", dlgid);
834 return NULL;
835 }
836
837 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
838 {
839 customctrl *ctrl, *sub_ctrl;
840
841 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
842 {
843 if(ctrl->id == ctlid)
844 return ctrl;
845
846 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
847 if(sub_ctrl->id == ctlid)
848 return sub_ctrl;
849 }
850
851 if (This->hmenu_opendropdown && This->cctrl_opendropdown.id == ctlid)
852 return &This->cctrl_opendropdown;
853
854 TRACE("No existing control with control id %d\n", ctlid);
855 return NULL;
856 }
857
858 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
859 {
860 LPWSTR text;
861 UINT len, final_width;
862 UINT lines, final_height;
863 SIZE size;
864 RECT rc;
865 HDC hdc;
866 WCHAR *c;
867 HFONT font;
868
869 TRACE("\n");
870
871 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
872 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
873 if(!text) return;
874 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
875
876 hdc = GetDC(hctrl);
877 font = (HFONT)SendMessageW(hctrl, WM_GETFONT, 0, 0);
878 font = SelectObject(hdc, font);
879 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
880 SelectObject(hdc, font);
881 ReleaseDC(hctrl, hdc);
882
883 if(len && multiline)
884 {
885 /* FIXME: line-wrap */
886 for(lines = 1, c = text; *c != '\0'; c++)
887 if(*c == '\n') lines++;
888
889 final_height = size.cy*lines + 2*4;
890 }
891 else
892 {
893 GetWindowRect(hctrl, &rc);
894 final_height = rc.bottom - rc.top;
895 }
896
897 final_width = min(max(size.cx, min_width) + 4, max_width);
898 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
899 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
900
901 HeapFree(GetProcessHeap(), 0, text);
902 }
903
904 static UINT ctrl_get_height(customctrl *ctrl) {
905 RECT rc;
906 GetWindowRect(ctrl->wrapper_hwnd, &rc);
907 return rc.bottom - rc.top;
908 }
909
910 static void ctrl_free(customctrl *ctrl)
911 {
912 customctrl *sub_cur1, *sub_cur2;
913 cctrl_item *item_cur1, *item_cur2;
914
915 TRACE("Freeing control %p\n", ctrl);
916 if(ctrl->type == IDLG_CCTRL_MENU)
917 {
918 TBBUTTON tbb;
919 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
920 DestroyMenu((HMENU)tbb.dwData);
921 }
922
923 LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
924 {
925 list_remove(&sub_cur1->sub_cctrls_entry);
926 ctrl_free(sub_cur1);
927 }
928
929 LIST_FOR_EACH_ENTRY_SAFE(item_cur1, item_cur2, &ctrl->sub_items, cctrl_item, entry)
930 {
931 list_remove(&item_cur1->entry);
932 item_free(item_cur1);
933 }
934
935 DestroyWindow(ctrl->hwnd);
936 HeapFree(GetProcessHeap(), 0, ctrl);
937 }
938
939 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
940 {
941 RECT rc;
942 UINT total_height;
943 UINT max_width, size;
944 customctrl *sub_ctrl;
945
946 switch(ctrl->type)
947 {
948 case IDLG_CCTRL_PUSHBUTTON:
949 case IDLG_CCTRL_COMBOBOX:
950 case IDLG_CCTRL_CHECKBUTTON:
951 case IDLG_CCTRL_TEXT:
952 size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
953 ctrl_resize(ctrl->hwnd, size, size, TRUE);
954 GetWindowRect(ctrl->hwnd, &rc);
955 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
956 SWP_NOZORDER|SWP_NOMOVE);
957 break;
958 case IDLG_CCTRL_VISUALGROUP:
959 total_height = 0;
960 ctrl_resize(ctrl->hwnd, 0, This->cctrl_indent, TRUE);
961
962 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
963 {
964 customctrl_resize(This, sub_ctrl);
965 SetWindowPos(sub_ctrl->wrapper_hwnd, NULL, This->cctrl_indent, total_height, 0, 0,
966 SWP_NOZORDER|SWP_NOSIZE);
967
968 total_height += ctrl_get_height(sub_ctrl);
969 }
970
971 /* The label should be right adjusted */
972 {
973 UINT width, height;
974
975 GetWindowRect(ctrl->hwnd, &rc);
976 width = rc.right - rc.left;
977 height = rc.bottom - rc.top;
978
979 SetWindowPos(ctrl->hwnd, NULL, This->cctrl_indent - width, 0, width, height, SWP_NOZORDER);
980 }
981
982 /* Resize the wrapper window to fit all the sub controls */
983 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, This->cctrl_width + This->cctrl_indent, total_height,
984 SWP_NOZORDER|SWP_NOMOVE);
985 break;
986 case IDLG_CCTRL_RADIOBUTTONLIST:
987 {
988 cctrl_item* item;
989
990 total_height = 0;
991 max_width = 0;
992
993 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
994 {
995 size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
996 ctrl_resize(item->hwnd, size, size, TRUE);
997 SetWindowPos(item->hwnd, NULL, 0, total_height, 0, 0,
998 SWP_NOZORDER|SWP_NOSIZE);
999
1000 GetWindowRect(item->hwnd, &rc);
1001
1002 total_height += rc.bottom - rc.top;
1003 max_width = max(rc.right - rc.left, max_width);
1004 }
1005
1006 SetWindowPos(ctrl->hwnd, NULL, 0, 0, max_width, total_height,
1007 SWP_NOZORDER|SWP_NOMOVE);
1008
1009 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, max_width, total_height,
1010 SWP_NOZORDER|SWP_NOMOVE);
1011
1012 break;
1013 }
1014 case IDLG_CCTRL_EDITBOX:
1015 case IDLG_CCTRL_SEPARATOR:
1016 case IDLG_CCTRL_MENU:
1017 case IDLG_CCTRL_OPENDROPDOWN:
1018 /* Nothing */
1019 break;
1020 }
1021 }
1022
1023 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
1024 {
1025 FileDialogImpl *This = crs->lpCreateParams;
1026 TRACE("%p\n", This);
1027
1028 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1029 return TRUE;
1030 }
1031
1032 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1033 {
1034 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1035
1036 TRACE("%p, %lx\n", This, wparam);
1037
1038 if(ctrl)
1039 {
1040 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
1041 {
1042 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
1043 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
1044 }
1045 else
1046 cctrl_event_OnButtonClicked(This, ctrl->id);
1047 }
1048
1049 return TRUE;
1050 }
1051
1052 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1053 {
1054 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1055 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
1056
1057 if(ctrl)
1058 {
1059 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
1060 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
1061
1062 cctrl_event_OnItemSelected(This, ctrl->id, selid);
1063 }
1064 return TRUE;
1065 }
1066
1067 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
1068 {
1069 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
1070 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
1071 POINT pt = { 0, nmtb->rcButton.bottom };
1072 TBBUTTON tbb;
1073 UINT idcmd;
1074
1075 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
1076
1077 if(ctrl)
1078 {
1079 cctrl_event_OnControlActivating(This,ctrl->id);
1080
1081 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1082 ClientToScreen(ctrl->hwnd, &pt);
1083 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
1084 if(idcmd)
1085 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
1086 }
1087
1088 return TBDDRET_DEFAULT;
1089 }
1090
1091 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1092 {
1093 switch(HIWORD(wparam))
1094 {
1095 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
1096 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
1097 }
1098
1099 return FALSE;
1100 }
1101
1102 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1103 {
1104 NMHDR *nmhdr = (NMHDR*)lparam;
1105
1106 switch(nmhdr->code)
1107 {
1108 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
1109 }
1110
1111 return FALSE;
1112 }
1113
1114 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1115 {
1116 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1117 customctrl *ctrl;
1118 HWND hwnd_child;
1119 RECT rc;
1120
1121 switch(message)
1122 {
1123 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
1124 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
1125 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
1126 case WM_SIZE:
1127 hwnd_child = GetPropW(hwnd, notifysink_childW);
1128 ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA);
1129 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
1130 {
1131 GetClientRect(hwnd, &rc);
1132 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1133 }
1134 return TRUE;
1135 }
1136
1137 return DefWindowProcW(hwnd, message, wparam, lparam);
1138 }
1139
1140 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
1141 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
1142 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
1143 {
1144 HWND ns_hwnd, control_hwnd, parent_hwnd;
1145 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
1146 customctrl *ctrl;
1147
1148 if(get_cctrl(This, id))
1149 return E_UNEXPECTED; /* Duplicate id */
1150
1151 if(This->cctrl_active_vg)
1152 parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
1153 else
1154 parent_hwnd = This->cctrls_hwnd;
1155
1156 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
1157 0, 0, This->cctrl_width, height, parent_hwnd,
1158 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
1159 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
1160 0, 0, This->cctrl_width, height, ns_hwnd,
1161 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
1162
1163 if(!ns_hwnd || !control_hwnd)
1164 {
1165 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
1166 DestroyWindow(ns_hwnd);
1167 DestroyWindow(control_hwnd);
1168
1169 return E_FAIL;
1170 }
1171
1172 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
1173
1174 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
1175 if(!ctrl)
1176 return E_OUTOFMEMORY;
1177
1178 ctrl->hwnd = control_hwnd;
1179 ctrl->wrapper_hwnd = ns_hwnd;
1180 ctrl->id = id;
1181 ctrl->dlgid = This->cctrl_next_dlgid;
1182 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
1183 list_init(&ctrl->sub_cctrls);
1184 list_init(&ctrl->sub_items);
1185
1186 if(This->cctrl_active_vg)
1187 list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
1188 else
1189 list_add_tail(&This->cctrls, &ctrl->entry);
1190
1191 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl);
1192
1193 if(ppctrl) *ppctrl = ctrl;
1194
1195 This->cctrl_next_dlgid++;
1196 return S_OK;
1197 }
1198
1199 /**************************************************************************
1200 * Container functions.
1201 */
1202 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
1203 {
1204 UINT container_height;
1205 UINT column_width;
1206 UINT nr_of_cols;
1207 UINT max_control_height, total_height = 0;
1208 UINT cur_col_pos, cur_row_pos;
1209 customctrl *ctrl;
1210 BOOL fits_height;
1211 UINT cspacing = MulDiv(90, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Columns are spaced with 90px */
1212 UINT rspacing = MulDiv(4, This->dpi_y, USER_DEFAULT_SCREEN_DPI); /* Rows are spaced with 4 px. */
1213
1214 /* Given the new width of the container, this function determines the
1215 * needed height of the container and places the controls according to
1216 * the new layout. Returns the new height.
1217 */
1218
1219 TRACE("%p\n", This);
1220
1221 column_width = This->cctrl_width + cspacing;
1222 nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
1223
1224 /* We don't need to do anything unless the number of visible columns has changed. */
1225 if(nr_of_cols == This->cctrls_cols)
1226 {
1227 RECT rc;
1228 GetWindowRect(This->cctrls_hwnd, &rc);
1229 return rc.bottom - rc.top;
1230 }
1231
1232 This->cctrls_cols = nr_of_cols;
1233
1234 /* Get the size of the tallest control, and the total size of
1235 * all the controls to figure out the number of slots we need.
1236 */
1237 max_control_height = 0;
1238 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1239 {
1240 if(ctrl->cdcstate & CDCS_VISIBLE)
1241 {
1242 UINT control_height = ctrl_get_height(ctrl);
1243 max_control_height = max(max_control_height, control_height);
1244
1245 total_height += control_height + rspacing;
1246 }
1247 }
1248
1249 if(!total_height)
1250 return 0;
1251
1252 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
1253 TRACE("Guess: container_height: %d\n",container_height);
1254
1255 /* Incrementally increase container_height until all the controls
1256 * fit.
1257 */
1258 do {
1259 UINT columns_needed = 1;
1260 cur_row_pos = 0;
1261
1262 fits_height = TRUE;
1263 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1264 {
1265 if(ctrl->cdcstate & CDCS_VISIBLE)
1266 {
1267 UINT control_height = ctrl_get_height(ctrl);
1268
1269 if(cur_row_pos + control_height > container_height)
1270 {
1271 if(++columns_needed > nr_of_cols)
1272 {
1273 container_height += 1;
1274 fits_height = FALSE;
1275 break;
1276 }
1277 cur_row_pos = 0;
1278 }
1279
1280 cur_row_pos += control_height + rspacing;
1281 }
1282 }
1283 } while(!fits_height);
1284
1285 TRACE("Final container height: %d\n", container_height);
1286
1287 /* Move the controls to their final destination
1288 */
1289 cur_col_pos = 0, cur_row_pos = 0;
1290 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1291 {
1292 if(ctrl->cdcstate & CDCS_VISIBLE)
1293 {
1294 RECT rc;
1295 UINT control_height, control_indent;
1296 GetWindowRect(ctrl->wrapper_hwnd, &rc);
1297 control_height = rc.bottom - rc.top;
1298
1299 if(cur_row_pos + control_height > container_height)
1300 {
1301 cur_row_pos = 0;
1302 cur_col_pos += This->cctrl_width + cspacing;
1303 }
1304
1305
1306 if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
1307 control_indent = 0;
1308 else
1309 control_indent = This->cctrl_indent;
1310
1311 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
1312 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1313
1314 cur_row_pos += control_height + rspacing;
1315 }
1316 }
1317
1318 /* Sanity check */
1319 if(cur_row_pos + This->cctrl_width > container_width)
1320 ERR("-- Failed to place controls properly.\n");
1321
1322 return container_height;
1323 }
1324
1325 static void ctrl_set_font(customctrl *ctrl, HFONT font)
1326 {
1327 customctrl *sub_ctrl;
1328 cctrl_item* item;
1329
1330 SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1331
1332 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1333 {
1334 ctrl_set_font(sub_ctrl, font);
1335 }
1336
1337 if (ctrl->type == IDLG_CCTRL_RADIOBUTTONLIST)
1338 {
1339 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1340 {
1341 SendMessageW(item->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1342 }
1343 }
1344 }
1345
1346 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
1347 {
1348 LONG wndstyle;
1349
1350 if(parent)
1351 {
1352 customctrl *ctrl;
1353 HFONT font;
1354
1355 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1356 wndstyle &= ~(WS_POPUP);
1357 wndstyle |= WS_CHILD;
1358 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1359
1360 SetParent(This->cctrls_hwnd, parent);
1361 ShowWindow(This->cctrls_hwnd, TRUE);
1362
1363 /* Set the fonts to match the dialog font. */
1364 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
1365 if(!font)
1366 ERR("Failed to get font handle from dialog.\n");
1367
1368 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1369 {
1370 if(font) ctrl_set_font(ctrl, font);
1371 customctrl_resize(This, ctrl);
1372 }
1373 }
1374 else
1375 {
1376 ShowWindow(This->cctrls_hwnd, FALSE);
1377
1378 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1379 wndstyle &= ~(WS_CHILD);
1380 wndstyle |= WS_POPUP;
1381 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1382
1383 SetParent(This->cctrls_hwnd, NULL);
1384 }
1385 }
1386
1387 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
1388 {
1389 FileDialogImpl *This = crs->lpCreateParams;
1390 TRACE("%p\n", This);
1391
1392 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1393 return TRUE;
1394 }
1395
1396 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
1397 {
1398 customctrl *cur1, *cur2;
1399 TRACE("%p\n", This);
1400
1401 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1402 {
1403 list_remove(&cur1->entry);
1404 ctrl_free(cur1);
1405 }
1406
1407 return TRUE;
1408 }
1409
1410 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1411 {
1412 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1413
1414 switch(umessage)
1415 {
1416 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1417 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1418 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1419 }
1420
1421 return FALSE;
1422 }
1423
1424 static void radiobuttonlist_set_selected_item(FileDialogImpl *This, customctrl *ctrl, cctrl_item *item)
1425 {
1426 cctrl_item *cursor;
1427
1428 LIST_FOR_EACH_ENTRY(cursor, &ctrl->sub_items, cctrl_item, entry)
1429 {
1430 SendMessageW(cursor->hwnd, BM_SETCHECK, (cursor == item) ? BST_CHECKED : BST_UNCHECKED, 0);
1431 }
1432 }
1433
1434 static LRESULT radiobuttonlist_on_bn_clicked(FileDialogImpl *This, HWND hwnd, HWND child)
1435 {
1436 DWORD ctrl_id = (DWORD)GetWindowLongPtrW(hwnd, GWLP_ID);
1437 customctrl *ctrl;
1438 cctrl_item *item;
1439 BOOL found_item=FALSE;
1440
1441 ctrl = get_cctrl_from_dlgid(This, ctrl_id);
1442
1443 if (!ctrl)
1444 {
1445 ERR("Can't find this control\n");
1446 return 0;
1447 }
1448
1449 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1450 {
1451 if (item->hwnd == child)
1452 {
1453 found_item = TRUE;
1454 break;
1455 }
1456 }
1457
1458 if (!found_item)
1459 {
1460 ERR("Can't find control item\n");
1461 return 0;
1462 }
1463
1464 radiobuttonlist_set_selected_item(This, ctrl, item);
1465
1466 cctrl_event_OnItemSelected(This, ctrl->id, item->id);
1467
1468 return 0;
1469 }
1470
1471 static LRESULT radiobuttonlist_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1472 {
1473 switch(HIWORD(wparam))
1474 {
1475 case BN_CLICKED: return radiobuttonlist_on_bn_clicked(This, hwnd, (HWND)lparam);
1476 }
1477
1478 return FALSE;
1479 }
1480
1481 static LRESULT CALLBACK radiobuttonlist_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1482 {
1483 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1484
1485 switch(message)
1486 {
1487 case WM_COMMAND: return radiobuttonlist_on_wm_command(This, hwnd, wparam, lparam);
1488 }
1489
1490 return DefWindowProcW(hwnd, message, wparam, lparam);
1491 }
1492
1493 static HRESULT init_custom_controls(FileDialogImpl *This)
1494 {
1495 WNDCLASSW wc;
1496 HDC hdc;
1497 static const WCHAR ctrl_container_classname[] =
1498 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1499
1500 InitCommonControlsEx(NULL);
1501
1502 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1503 {
1504 wc.style = CS_HREDRAW | CS_VREDRAW;
1505 wc.lpfnWndProc = ctrl_container_wndproc;
1506 wc.cbClsExtra = 0;
1507 wc.cbWndExtra = 0;
1508 wc.hInstance = COMDLG32_hInstance;
1509 wc.hIcon = 0;
1510 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1511 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1512 wc.lpszMenuName = NULL;
1513 wc.lpszClassName = ctrl_container_classname;
1514
1515 if(!RegisterClassW(&wc)) return E_FAIL;
1516 }
1517
1518 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1519 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1520 0, 0, 0, 0, NULL, 0,
1521 COMDLG32_hInstance, This);
1522 if(!This->cctrls_hwnd)
1523 return E_FAIL;
1524
1525 hdc = GetDC(This->cctrls_hwnd);
1526 This->dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
1527 This->dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
1528 ReleaseDC(This->cctrls_hwnd, hdc);
1529
1530 This->cctrl_width = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Controls have a fixed width */
1531 This->cctrl_indent = MulDiv(100, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1532 This->cctrl_def_height = MulDiv(23, This->dpi_y, USER_DEFAULT_SCREEN_DPI);
1533 This->cctrls_cols = 0;
1534
1535 This->cctrl_next_dlgid = 0x2000;
1536 list_init(&This->cctrls);
1537 This->cctrl_active_vg = NULL;
1538
1539 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1540
1541 /* Register class for */
1542 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1543 wc.hInstance != COMDLG32_hInstance)
1544 {
1545 wc.style = CS_HREDRAW | CS_VREDRAW;
1546 wc.lpfnWndProc = notifysink_proc;
1547 wc.cbClsExtra = 0;
1548 wc.cbWndExtra = 0;
1549 wc.hInstance = COMDLG32_hInstance;
1550 wc.hIcon = 0;
1551 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1552 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1553 wc.lpszMenuName = NULL;
1554 wc.lpszClassName = floatnotifysinkW;
1555
1556 if (!RegisterClassW(&wc))
1557 ERR("Failed to register FloatNotifySink window class.\n");
1558 }
1559
1560 if( !GetClassInfoW(COMDLG32_hInstance, radiobuttonlistW, &wc) ||
1561 wc.hInstance != COMDLG32_hInstance)
1562 {
1563 wc.style = CS_HREDRAW | CS_VREDRAW;
1564 wc.lpfnWndProc = radiobuttonlist_proc;
1565 wc.cbClsExtra = 0;
1566 wc.cbWndExtra = 0;
1567 wc.hInstance = COMDLG32_hInstance;
1568 wc.hIcon = 0;
1569 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1570 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1571 wc.lpszMenuName = NULL;
1572 wc.lpszClassName = radiobuttonlistW;
1573
1574 if (!RegisterClassW(&wc))
1575 ERR("Failed to register RadioButtonList window class.\n");
1576 }
1577
1578 return S_OK;
1579 }
1580
1581 /**************************************************************************
1582 * Window related functions.
1583 */
1584 static BOOL update_open_dropdown(FileDialogImpl *This)
1585 {
1586 /* Show or hide the open dropdown button as appropriate */
1587 BOOL show=FALSE, showing;
1588 HWND open_hwnd, dropdown_hwnd;
1589
1590 if (This->hmenu_opendropdown)
1591 {
1592 INT num_visible_items=0;
1593 cctrl_item* item;
1594
1595 LIST_FOR_EACH_ENTRY(item, &This->cctrl_opendropdown.sub_items, cctrl_item, entry)
1596 {
1597 if (item->cdcstate & CDCS_VISIBLE)
1598 {
1599 num_visible_items++;
1600 if (num_visible_items >= 2)
1601 {
1602 show = TRUE;
1603 break;
1604 }
1605 }
1606 }
1607 }
1608
1609 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1610 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1611
1612 showing = (GetWindowLongPtrW(dropdown_hwnd, GWL_STYLE) & WS_VISIBLE) != 0;
1613
1614 if (showing != show)
1615 {
1616 RECT open_rc, dropdown_rc;
1617
1618 GetWindowRect(open_hwnd, &open_rc);
1619 GetWindowRect(dropdown_hwnd, &dropdown_rc);
1620
1621 if (show)
1622 {
1623 ShowWindow(dropdown_hwnd, SW_SHOW);
1624
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);
1628 }
1629 else
1630 {
1631 ShowWindow(dropdown_hwnd, SW_HIDE);
1632
1633 SetWindowPos(open_hwnd, NULL, 0, 0,
1634 (open_rc.right - open_rc.left) + (dropdown_rc.right - dropdown_rc.left),
1635 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1636 }
1637 }
1638
1639 return show;
1640 }
1641
1642 static void update_layout(FileDialogImpl *This)
1643 {
1644 HDWP hdwp;
1645 HWND hwnd;
1646 RECT dialog_rc;
1647 RECT cancel_rc, dropdown_rc, open_rc;
1648 RECT filetype_rc, filename_rc, filenamelabel_rc;
1649 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1650 static const UINT vspacing = 4, hspacing = 4;
1651 static const UINT min_width = 320, min_height = 200;
1652 BOOL show_dropdown;
1653
1654 if (!GetClientRect(This->dlg_hwnd, &dialog_rc))
1655 {
1656 TRACE("Invalid dialog window, not updating layout\n");
1657 return;
1658 }
1659
1660 if(dialog_rc.right < min_width || dialog_rc.bottom < min_height)
1661 {
1662 TRACE("Dialog size (%d, %d) too small, not updating layout\n", dialog_rc.right, dialog_rc.bottom);
1663 return;
1664 }
1665
1666 /****
1667 * Calculate the size of the dialog and all the parts.
1668 */
1669
1670 /* Cancel button */
1671 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1672 if(hwnd)
1673 {
1674 int cancel_width, cancel_height;
1675 GetWindowRect(hwnd, &cancel_rc);
1676 cancel_width = cancel_rc.right - cancel_rc.left;
1677 cancel_height = cancel_rc.bottom - cancel_rc.top;
1678
1679 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1680 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1681 cancel_rc.right = cancel_rc.left + cancel_width;
1682 cancel_rc.bottom = cancel_rc.top + cancel_height;
1683 }
1684
1685 /* Open/Save dropdown */
1686 show_dropdown = update_open_dropdown(This);
1687
1688 if(show_dropdown)
1689 {
1690 int dropdown_width, dropdown_height;
1691 hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1692
1693 GetWindowRect(hwnd, &dropdown_rc);
1694 dropdown_width = dropdown_rc.right - dropdown_rc.left;
1695 dropdown_height = dropdown_rc.bottom - dropdown_rc.top;
1696
1697 dropdown_rc.left = cancel_rc.left - dropdown_width - hspacing;
1698 dropdown_rc.top = cancel_rc.top;
1699 dropdown_rc.right = dropdown_rc.left + dropdown_width;
1700 dropdown_rc.bottom = dropdown_rc.top + dropdown_height;
1701 }
1702 else
1703 {
1704 dropdown_rc.left = dropdown_rc.right = cancel_rc.left - hspacing;
1705 dropdown_rc.top = cancel_rc.top;
1706 dropdown_rc.bottom = cancel_rc.bottom;
1707 }
1708
1709 /* Open/Save button */
1710 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1711 if(hwnd)
1712 {
1713 int open_width, open_height;
1714 GetWindowRect(hwnd, &open_rc);
1715 open_width = open_rc.right - open_rc.left;
1716 open_height = open_rc.bottom - open_rc.top;
1717
1718 open_rc.left = dropdown_rc.left - open_width;
1719 open_rc.top = dropdown_rc.top;
1720 open_rc.right = open_rc.left + open_width;
1721 open_rc.bottom = open_rc.top + open_height;
1722 }
1723
1724 /* The filetype combobox. */
1725 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1726 if(hwnd)
1727 {
1728 int filetype_width, filetype_height;
1729 GetWindowRect(hwnd, &filetype_rc);
1730
1731 filetype_width = filetype_rc.right - filetype_rc.left;
1732 filetype_height = filetype_rc.bottom - filetype_rc.top;
1733
1734 filetype_rc.right = cancel_rc.right;
1735
1736 filetype_rc.left = filetype_rc.right - filetype_width;
1737 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1738 filetype_rc.bottom = filetype_rc.top + filetype_height;
1739
1740 if(!This->filterspec_count)
1741 filetype_rc.left = filetype_rc.right;
1742 }
1743
1744 /* Filename label. */
1745 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1746 if(hwnd)
1747 {
1748 int filetypelabel_width, filetypelabel_height;
1749 GetWindowRect(hwnd, &filenamelabel_rc);
1750
1751 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1752 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1753
1754 filenamelabel_rc.left = 160; /* FIXME */
1755 filenamelabel_rc.top = filetype_rc.top;
1756 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1757 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1758 }
1759
1760 /* Filename edit box. */
1761 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1762 if(hwnd)
1763 {
1764 int filename_width, filename_height;
1765 GetWindowRect(hwnd, &filename_rc);
1766
1767 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1768 filename_height = filename_rc.bottom - filename_rc.top;
1769
1770 filename_rc.left = filenamelabel_rc.right + hspacing;
1771 filename_rc.top = filetype_rc.top;
1772 filename_rc.right = filename_rc.left + filename_width;
1773 filename_rc.bottom = filename_rc.top + filename_height;
1774 }
1775
1776 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1777 if(hwnd)
1778 {
1779 GetWindowRect(hwnd, &toolbar_rc);
1780 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1781 }
1782
1783 /* The custom controls */
1784 customctrls_rc.left = dialog_rc.left + hspacing;
1785 customctrls_rc.right = dialog_rc.right - hspacing;
1786 customctrls_rc.bottom = filename_rc.top - vspacing;
1787 customctrls_rc.top = customctrls_rc.bottom -
1788 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1789
1790 /* The ExplorerBrowser control. */
1791 ebrowser_rc.left = dialog_rc.left + hspacing;
1792 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1793 ebrowser_rc.right = dialog_rc.right - hspacing;
1794 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1795
1796 /****
1797 * Move everything to the right place.
1798 */
1799
1800 /* FIXME: The Save Dialog uses a slightly different layout. */
1801 hdwp = BeginDeferWindowPos(7);
1802
1803 if(hdwp && This->peb)
1804 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1805
1806 if(hdwp && This->cctrls_hwnd)
1807 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1808 customctrls_rc.left, customctrls_rc.top,
1809 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1810 SWP_NOZORDER | SWP_NOACTIVATE);
1811
1812 /* The default controls */
1813 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1814 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1815 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1816
1817 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1818 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1819 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1820 SWP_NOZORDER | SWP_NOACTIVATE);
1821
1822 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1823 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1824 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1825
1826 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1827 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1828 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1829
1830 if(hdwp && This->hmenu_opendropdown && (hwnd = GetDlgItem(This->dlg_hwnd, psh1)))
1831 DeferWindowPos(hdwp, hwnd, NULL, dropdown_rc.left, dropdown_rc.top, 0, 0,
1832 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1833
1834 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1835 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1836 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1837
1838 if(hdwp)
1839 EndDeferWindowPos(hdwp);
1840 else
1841 ERR("Failed to position dialog controls.\n");
1842
1843 return;
1844 }
1845
1846 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1847 {
1848 IShellItem *psi_folder;
1849 IObjectWithSite *client;
1850 FOLDERSETTINGS fos;
1851 RECT rc = {0};
1852 HRESULT hr;
1853
1854 /* Create ExplorerBrowser instance */
1855 OleInitialize(NULL);
1856
1857 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1858 &IID_IExplorerBrowser, (void**)&This->peb);
1859 if(FAILED(hr))
1860 {
1861 ERR("Failed to instantiate ExplorerBrowser control.\n");
1862 return hr;
1863 }
1864
1865 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES | EBO_NOBORDER);
1866
1867 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1868 if(FAILED(hr))
1869 {
1870 ERR("Failed to initialize the ExplorerBrowser control.\n");
1871 IExplorerBrowser_Release(This->peb);
1872 This->peb = NULL;
1873 return hr;
1874 }
1875 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1876 if(FAILED(hr))
1877 ERR("Advise (ExplorerBrowser) failed.\n");
1878
1879 /* Get previous options? */
1880 fos.ViewMode = fos.fFlags = 0;
1881 if(!(This->options & FOS_ALLOWMULTISELECT))
1882 fos.fFlags |= FWF_SINGLESEL;
1883
1884 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1885
1886 hr = IExplorerBrowser_QueryInterface(This->peb, &IID_IObjectWithSite, (void**)&client);
1887 if (hr == S_OK)
1888 {
1889 hr = IObjectWithSite_SetSite(client, (IUnknown*)&This->IFileDialog2_iface);
1890 IObjectWithSite_Release(client);
1891 if(FAILED(hr))
1892 ERR("SetSite failed, 0x%08x\n", hr);
1893 }
1894
1895 /* Browse somewhere */
1896 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1897 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1898
1899 return S_OK;
1900 }
1901
1902 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1903 {
1904 HWND htoolbar;
1905 TBADDBITMAP tbab;
1906 TBBUTTON button[2];
1907
1908 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1909 0, 0, 0, 0,
1910 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1911
1912 tbab.hInst = HINST_COMMCTRL;
1913 tbab.nID = IDB_HIST_LARGE_COLOR;
1914 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1915
1916 button[0].iBitmap = HIST_BACK;
1917 button[0].idCommand = IDC_NAVBACK;
1918 button[0].fsState = TBSTATE_ENABLED;
1919 button[0].fsStyle = BTNS_BUTTON;
1920 button[0].dwData = 0;
1921 button[0].iString = 0;
1922
1923 button[1].iBitmap = HIST_FORWARD;
1924 button[1].idCommand = IDC_NAVFORWARD;
1925 button[1].fsState = TBSTATE_ENABLED;
1926 button[1].fsStyle = BTNS_BUTTON;
1927 button[1].dwData = 0;
1928 button[1].iString = 0;
1929
1930 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1931 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1932 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1933 }
1934
1935 static void update_control_text(FileDialogImpl *This)
1936 {
1937 HWND hitem;
1938 LPCWSTR custom_okbutton;
1939 cctrl_item* item;
1940 UINT min_width = MulDiv(50, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1941 UINT max_width = MulDiv(250, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
1942
1943 if(This->custom_title)
1944 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1945
1946 if(This->hmenu_opendropdown && (item = get_first_item(&This->cctrl_opendropdown)))
1947 custom_okbutton = item->label;
1948 else
1949 custom_okbutton = This->custom_okbutton;
1950
1951 if(custom_okbutton &&
1952 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1953 {
1954 SetWindowTextW(hitem, custom_okbutton);
1955 ctrl_resize(hitem, min_width, max_width, FALSE);
1956 }
1957
1958 if(This->custom_cancelbutton &&
1959 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1960 {
1961 SetWindowTextW(hitem, This->custom_cancelbutton);
1962 ctrl_resize(hitem, min_width, max_width, FALSE);
1963 }
1964
1965 if(This->custom_filenamelabel &&
1966 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1967 {
1968 SetWindowTextW(hitem, This->custom_filenamelabel);
1969 ctrl_resize(hitem, min_width, max_width, FALSE);
1970 }
1971 }
1972
1973 static LRESULT CALLBACK dropdown_subclass_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1974 {
1975 static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
1976 static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
1977
1978 if (umessage == WM_LBUTTONDOWN)
1979 {
1980 FileDialogImpl *This = GetPropW(hwnd, prop_this);
1981
1982 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
1983 show_opendropdown(This);
1984 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
1985
1986 return 0;
1987 }
1988
1989 return CallWindowProcW((WNDPROC)GetPropW(hwnd, prop_oldwndproc), hwnd, umessage, wparam, lparam);
1990 }
1991
1992 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1993 {
1994 FileDialogImpl *This = (FileDialogImpl*)lParam;
1995 HWND hitem;
1996
1997 TRACE("(%p, %p)\n", This, hwnd);
1998
1999 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
2000 This->dlg_hwnd = hwnd;
2001
2002 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
2003 if(hitem) ShowWindow(hitem, SW_HIDE);
2004
2005 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
2006 if(hitem) ShowWindow(hitem, SW_HIDE);
2007
2008 /* Fill filetypes combobox, or hide it. */
2009 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
2010 if(This->filterspec_count)
2011 {
2012 HDC hdc;
2013 HFONT font;
2014 SIZE size;
2015 UINT i, maxwidth = 0;
2016
2017 hdc = GetDC(hitem);
2018 font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
2019 SelectObject(hdc, font);
2020
2021 for(i = 0; i < This->filterspec_count; i++)
2022 {
2023 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
2024
2025 if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
2026 maxwidth = max(maxwidth, size.cx);
2027 }
2028 ReleaseDC(hitem, hdc);
2029
2030 if(maxwidth > 0)
2031 {
2032 maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
2033 SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
2034 }
2035 else
2036 ERR("Failed to calculate width of filetype dropdown\n");
2037
2038 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
2039 }
2040 else
2041 ShowWindow(hitem, SW_HIDE);
2042
2043 if(This->set_filename &&
2044 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
2045 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
2046
2047 if(This->hmenu_opendropdown)
2048 {
2049 HWND dropdown_hwnd;
2050 LOGFONTW lfw, lfw_marlett;
2051 HFONT dialog_font;
2052 static const WCHAR marlett[] = {'M','a','r','l','e','t','t',0};
2053 static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
2054 static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
2055
2056 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
2057
2058 /* Change dropdown button font to Marlett */
2059 dialog_font = (HFONT)SendMessageW(dropdown_hwnd, WM_GETFONT, 0, 0);
2060
2061 GetObjectW(dialog_font, sizeof(lfw), &lfw);
2062
2063 memset(&lfw_marlett, 0, sizeof(lfw_marlett));
2064 lstrcpyW(lfw_marlett.lfFaceName, marlett);
2065 lfw_marlett.lfHeight = lfw.lfHeight;
2066 lfw_marlett.lfCharSet = SYMBOL_CHARSET;
2067
2068 This->hfont_opendropdown = CreateFontIndirectW(&lfw_marlett);
2069
2070 SendMessageW(dropdown_hwnd, WM_SETFONT, (LPARAM)This->hfont_opendropdown, 0);
2071
2072 /* Subclass button so we can handle LBUTTONDOWN */
2073 SetPropW(dropdown_hwnd, prop_this, This);
2074 SetPropW(dropdown_hwnd, prop_oldwndproc,
2075 (HANDLE)SetWindowLongPtrW(dropdown_hwnd, GWLP_WNDPROC, (LONG_PTR)dropdown_subclass_proc));
2076 }
2077
2078 ctrl_container_reparent(This, This->dlg_hwnd);
2079 init_explorerbrowser(This);
2080 init_toolbar(This, hwnd);
2081 update_control_text(This);
2082 update_layout(This);
2083
2084 if(This->filterspec_count)
2085 events_OnTypeChange(This);
2086
2087 if ((hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)))
2088 SetFocus(hitem);
2089
2090 return FALSE;
2091 }
2092
2093 static LRESULT on_wm_size(FileDialogImpl *This)
2094 {
2095 update_layout(This);
2096 return FALSE;
2097 }
2098
2099 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
2100 {
2101 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
2102 TRACE("%p (%p)\n", This, mmi);
2103
2104 /* FIXME */
2105 mmi->ptMinTrackSize.x = 640;
2106 mmi->ptMinTrackSize.y = 480;
2107
2108 return FALSE;
2109 }
2110
2111 static LRESULT on_wm_destroy(FileDialogImpl *This)
2112 {
2113 TRACE("%p\n", This);
2114
2115 if(This->peb)
2116 {
2117 IExplorerBrowser_Destroy(This->peb);
2118 IExplorerBrowser_Release(This->peb);
2119 This->peb = NULL;
2120 }
2121
2122 ctrl_container_reparent(This, NULL);
2123 This->dlg_hwnd = NULL;
2124
2125 DeleteObject(This->hfont_opendropdown);
2126 This->hfont_opendropdown = NULL;
2127
2128 return TRUE;
2129 }
2130
2131 static LRESULT on_idok(FileDialogImpl *This)
2132 {
2133 TRACE("%p\n", This);
2134
2135 if(SUCCEEDED(on_default_action(This)))
2136 EndDialog(This->dlg_hwnd, S_OK);
2137
2138 return FALSE;
2139 }
2140
2141 static LRESULT on_idcancel(FileDialogImpl *This)
2142 {
2143 TRACE("%p\n", This);
2144
2145 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
2146
2147 return FALSE;
2148 }
2149
2150 static LRESULT on_command_opendropdown(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2151 {
2152 if(HIWORD(wparam) == BN_CLICKED)
2153 {
2154 HWND hwnd = (HWND)lparam;
2155 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
2156 show_opendropdown(This);
2157 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
2158 }
2159
2160 return FALSE;
2161 }
2162
2163 static LRESULT on_browse_back(FileDialogImpl *This)
2164 {
2165 TRACE("%p\n", This);
2166 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
2167 return FALSE;
2168 }
2169
2170 static LRESULT on_browse_forward(FileDialogImpl *This)
2171 {
2172 TRACE("%p\n", This);
2173 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
2174 return FALSE;
2175 }
2176
2177 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2178 {
2179 if(HIWORD(wparam) == CBN_SELCHANGE)
2180 {
2181 IShellView *psv;
2182 HRESULT hr;
2183 LPWSTR filename;
2184 UINT prev_index = This->filetypeindex;
2185
2186 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
2187 TRACE("File type selection changed to %d.\n", This->filetypeindex);
2188
2189 if(prev_index == This->filetypeindex)
2190 return FALSE;
2191
2192 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
2193 if(SUCCEEDED(hr))
2194 {
2195 IShellView_Refresh(psv);
2196 IShellView_Release(psv);
2197 }
2198
2199 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
2200 {
2201 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
2202
2203 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
2204 if(ext)
2205 {
2206 lstrcpyW(buf, filename);
2207
2208 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
2209 PathRemoveExtensionW(buf);
2210
2211 lstrcatW(buf, ext);
2212 set_file_name(This, buf);
2213 }
2214 CoTaskMemFree(filename);
2215 }
2216
2217 /* The documentation claims that OnTypeChange is called only
2218 * when the dialog is opened, but this is obviously not the
2219 * case. */
2220 events_OnTypeChange(This);
2221 }
2222
2223 return FALSE;
2224 }
2225
2226 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2227 {
2228 switch(LOWORD(wparam))
2229 {
2230 case IDOK: return on_idok(This);
2231 case IDCANCEL: return on_idcancel(This);
2232 case psh1: return on_command_opendropdown(This, wparam, lparam);
2233 case IDC_NAVBACK: return on_browse_back(This);
2234 case IDC_NAVFORWARD: return on_browse_forward(This);
2235 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
2236 default: TRACE("Unknown command.\n");
2237 }
2238 return FALSE;
2239 }
2240
2241 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
2242 {
2243 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
2244
2245 switch(umessage)
2246 {
2247 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
2248 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
2249 case WM_SIZE: return on_wm_size(This);
2250 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
2251 case WM_DESTROY: return on_wm_destroy(This);
2252 }
2253
2254 return FALSE;
2255 }
2256
2257 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
2258 {
2259 INT_PTR res;
2260
2261 SetLastError(0);
2262 res = DialogBoxParamW(COMDLG32_hInstance,
2263 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
2264 parent, itemdlg_dlgproc, (LPARAM)This);
2265 This->dlg_hwnd = NULL;
2266 if(res == -1)
2267 {
2268 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
2269 return E_FAIL;
2270 }
2271
2272 TRACE("Returning 0x%08x\n", (HRESULT)res);
2273 return (HRESULT)res;
2274 }
2275
2276 /**************************************************************************
2277 * IFileDialog implementation
2278 */
2279 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
2280 {
2281 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
2282 }
2283
2284 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
2285 REFIID riid,
2286 void **ppvObject)
2287 {
2288 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2289 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2290
2291 *ppvObject = NULL;
2292 if(IsEqualGUID(riid, &IID_IUnknown) ||
2293 IsEqualGUID(riid, &IID_IFileDialog) ||
2294 IsEqualGUID(riid, &IID_IFileDialog2))
2295 {
2296 *ppvObject = iface;
2297 }
2298 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
2299 {
2300 *ppvObject = &This->u.IFileOpenDialog_iface;
2301 }
2302 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
2303 {
2304 *ppvObject = &This->u.IFileSaveDialog_iface;
2305 }
2306 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
2307 {
2308 *ppvObject = &This->IExplorerBrowserEvents_iface;
2309 }
2310 else if(IsEqualGUID(riid, &IID_IServiceProvider))
2311 {
2312 *ppvObject = &This->IServiceProvider_iface;
2313 }
2314 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
2315 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
2316 IsEqualGUID(&IID_ICommDlgBrowser, riid))
2317 {
2318 *ppvObject = &This->ICommDlgBrowser3_iface;
2319 }
2320 else if(IsEqualGUID(&IID_IOleWindow, riid))
2321 {
2322 *ppvObject = &This->IOleWindow_iface;
2323 }
2324 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
2325 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
2326 {
2327 *ppvObject = &This->IFileDialogCustomize_iface;
2328 }
2329 else
2330 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
2331
2332 if(*ppvObject)
2333 {
2334 IUnknown_AddRef((IUnknown*)*ppvObject);
2335 return S_OK;
2336 }
2337
2338 return E_NOINTERFACE;
2339 }
2340
2341 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
2342 {
2343 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2344 LONG ref = InterlockedIncrement(&This->ref);
2345 TRACE("%p - ref %d\n", This, ref);
2346
2347 return ref;
2348 }
2349
2350 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
2351 {
2352 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2353 LONG ref = InterlockedDecrement(&This->ref);
2354 TRACE("%p - ref %d\n", This, ref);
2355
2356 if(!ref)
2357 {
2358 UINT i;
2359 for(i = 0; i < This->filterspec_count; i++)
2360 {
2361 LocalFree((void*)This->filterspecs[i].pszName);
2362 LocalFree((void*)This->filterspecs[i].pszSpec);
2363 }
2364 HeapFree(GetProcessHeap(), 0, This->filterspecs);
2365
2366 DestroyWindow(This->cctrls_hwnd);
2367
2368 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
2369 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
2370 if(This->psi_folder) IShellItem_Release(This->psi_folder);
2371 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
2372 if(This->psia_results) IShellItemArray_Release(This->psia_results);
2373
2374 LocalFree(This->set_filename);
2375 LocalFree(This->default_ext);
2376 LocalFree(This->custom_title);
2377 LocalFree(This->custom_okbutton);
2378 LocalFree(This->custom_cancelbutton);
2379 LocalFree(This->custom_filenamelabel);
2380
2381 DestroyMenu(This->hmenu_opendropdown);
2382 DeleteObject(This->hfont_opendropdown);
2383
2384 HeapFree(GetProcessHeap(), 0, This);
2385 }
2386
2387 return ref;
2388 }
2389
2390 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
2391 {
2392 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2393 TRACE("%p (%p)\n", iface, hwndOwner);
2394
2395 This->opendropdown_has_selection = FALSE;
2396
2397 return create_dialog(This, hwndOwner);
2398 }
2399
2400 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
2401 const COMDLG_FILTERSPEC *rgFilterSpec)
2402 {
2403 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2404 UINT i;
2405 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
2406
2407 if(This->filterspecs)
2408 return E_UNEXPECTED;
2409
2410 if(!rgFilterSpec)
2411 return E_INVALIDARG;
2412
2413 if(!cFileTypes)
2414 return S_OK;
2415
2416 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
2417 for(i = 0; i < cFileTypes; i++)
2418 {
2419 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
2420 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
2421 }
2422 This->filterspec_count = cFileTypes;
2423
2424 return S_OK;
2425 }
2426
2427 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
2428 {
2429 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2430 TRACE("%p (%d)\n", This, iFileType);
2431
2432 if(!This->filterspecs)
2433 return E_FAIL;
2434
2435 iFileType = max(iFileType, 1);
2436 iFileType = min(iFileType, This->filterspec_count);
2437 This->filetypeindex = iFileType-1;
2438
2439 return S_OK;
2440 }
2441
2442 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
2443 {
2444 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2445 TRACE("%p (%p)\n", This, piFileType);
2446
2447 if(!piFileType)
2448 return E_INVALIDARG;
2449
2450 if(This->filterspec_count == 0)
2451 *piFileType = 0;
2452 else
2453 *piFileType = This->filetypeindex + 1;
2454
2455 return S_OK;
2456 }
2457
2458 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
2459 {
2460 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2461 events_client *client;
2462 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
2463
2464 if(!pfde || !pdwCookie)
2465 return E_INVALIDARG;
2466
2467 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
2468 client->pfde = pfde;
2469 client->cookie = ++This->events_next_cookie;
2470
2471 IFileDialogEvents_AddRef(pfde);
2472 *pdwCookie = client->cookie;
2473
2474 list_add_tail(&This->events_clients, &client->entry);
2475
2476 return S_OK;
2477 }
2478
2479 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
2480 {
2481 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2482 events_client *client, *found = NULL;
2483 TRACE("%p (%d)\n", This, dwCookie);
2484
2485 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
2486 {
2487 if(client->cookie == dwCookie)
2488 {
2489 found = client;
2490 break;
2491 }
2492 }
2493
2494 if(found)
2495 {
2496 list_remove(&found->entry);
2497 IFileDialogEvents_Release(found->pfde);
2498 HeapFree(GetProcessHeap(), 0, found);
2499 return S_OK;
2500 }
2501
2502 return E_INVALIDARG;
2503 }
2504
2505 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
2506 {
2507 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2508 TRACE("%p (0x%x)\n", This, fos);
2509
2510 if (fos & ~(FOS_OVERWRITEPROMPT | FOS_STRICTFILETYPES | FOS_NOCHANGEDIR | FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM
2511 | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_ALLOWMULTISELECT | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST
2512 | FOS_CREATEPROMPT | FOS_SHAREAWARE | FOS_NOREADONLYRETURN | FOS_NOTESTFILECREATE | FOS_HIDEMRUPLACES
2513 | FOS_HIDEPINNEDPLACES | FOS_NODEREFERENCELINKS | FOS_DONTADDTORECENT | FOS_FORCESHOWHIDDEN
2514 | FOS_DEFAULTNOMINIMODE | FOS_FORCEPREVIEWPANEON | FOS_SUPPORTSTREAMABLEITEMS))
2515 {
2516 WARN("Invalid option %#x\n", fos);
2517 return E_INVALIDARG;
2518 }
2519
2520 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
2521 {
2522 WCHAR buf[30];
2523 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, ARRAY_SIZE(buf));
2524 IFileDialog2_SetTitle(iface, buf);
2525 }
2526
2527 This->options = fos;
2528
2529 return S_OK;
2530 }
2531
2532 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
2533 {
2534 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2535 TRACE("%p (%p)\n", This, pfos);
2536
2537 if(!pfos)
2538 return E_INVALIDARG;
2539
2540 *pfos = This->options;
2541
2542 return S_OK;
2543 }
2544
2545 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
2546 {
2547 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2548 TRACE("%p (%p)\n", This, psi);
2549 if(This->psi_defaultfolder)
2550 IShellItem_Release(This->psi_defaultfolder);
2551
2552 This->psi_defaultfolder = psi;
2553
2554 if(This->psi_defaultfolder)
2555 IShellItem_AddRef(This->psi_defaultfolder);
2556
2557 return S_OK;
2558 }
2559
2560 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
2561 {
2562 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2563 TRACE("%p (%p)\n", This, psi);
2564 if(This->psi_setfolder)
2565 IShellItem_Release(This->psi_setfolder);
2566
2567 This->psi_setfolder = psi;
2568
2569 if(This->psi_setfolder)
2570 IShellItem_AddRef(This->psi_setfolder);
2571
2572 return S_OK;
2573 }
2574
2575 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
2576 {
2577 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2578 TRACE("%p (%p)\n", This, ppsi);
2579 if(!ppsi)
2580 return E_INVALIDARG;
2581
2582 /* FIXME:
2583 If the dialog is shown, return the current(ly selected) folder. */
2584
2585 *ppsi = NULL;
2586 if(This->psi_folder)
2587 *ppsi = This->psi_folder;
2588 else if(This->psi_setfolder)
2589 *ppsi = This->psi_setfolder;
2590 else if(This->psi_defaultfolder)
2591 *ppsi = This->psi_defaultfolder;
2592
2593 if(*ppsi)
2594 {
2595 IShellItem_AddRef(*ppsi);
2596 return S_OK;
2597 }
2598
2599 return E_FAIL;
2600 }
2601
2602 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
2603 {
2604 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2605 HRESULT hr;
2606 TRACE("%p (%p)\n", This, ppsi);
2607
2608 if(!ppsi)
2609 return E_INVALIDARG;
2610
2611 if(This->psia_selection)
2612 {
2613 /* FIXME: Check filename edit box */
2614 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2615 return hr;
2616 }
2617
2618 return E_FAIL;
2619 }
2620
2621 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
2622 {
2623 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2624 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2625
2626 set_file_name(This, pszName);
2627
2628 return S_OK;
2629 }
2630
2631 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
2632 {
2633 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2634 TRACE("%p (%p)\n", iface, pszName);
2635
2636 if(!pszName)
2637 return E_INVALIDARG;
2638
2639 *pszName = NULL;
2640 get_file_name(This, pszName);
2641 return *pszName ? S_OK : E_FAIL;
2642 }
2643
2644 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
2645 {
2646 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2647 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2648
2649 LocalFree(This->custom_title);
2650 This->custom_title = StrDupW(pszTitle);
2651 update_control_text(This);
2652
2653 return S_OK;
2654 }
2655
2656 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
2657 {
2658 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2659 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2660
2661 LocalFree(This->custom_okbutton);
2662 This->custom_okbutton = StrDupW(pszText);
2663 update_control_text(This);
2664 update_layout(This);
2665
2666 return S_OK;
2667 }
2668
2669 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2670 {
2671 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2672 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2673
2674 LocalFree(This->custom_filenamelabel);
2675 This->custom_filenamelabel = StrDupW(pszLabel);
2676 update_control_text(This);
2677 update_layout(This);
2678
2679 return S_OK;
2680 }
2681
2682 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
2683 {
2684 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2685 HRESULT hr;
2686 TRACE("%p (%p)\n", This, ppsi);
2687
2688 if(!ppsi)
2689 return E_INVALIDARG;
2690
2691 if(This->psia_results)
2692 {
2693 UINT item_count;
2694 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2695 if(SUCCEEDED(hr))
2696 {
2697 if(item_count != 1)
2698 return E_FAIL;
2699
2700 /* Adds a reference. */
2701 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2702 }
2703
2704 return hr;
2705 }
2706
2707 return E_UNEXPECTED;
2708 }
2709
2710 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2711 {
2712 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2713 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2714 return S_OK;
2715 }
2716
2717 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2718 {
2719 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2720 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2721
2722 LocalFree(This->default_ext);
2723 This->default_ext = StrDupW(pszDefaultExtension);
2724
2725 return S_OK;
2726 }
2727
2728 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2729 {
2730 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2731 TRACE("%p (0x%08x)\n", This, hr);
2732
2733 if(This->dlg_hwnd)
2734 EndDialog(This->dlg_hwnd, hr);
2735
2736 return S_OK;
2737 }
2738
2739 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2740 {
2741 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2742 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2743 This->client_guid = *guid;
2744 return S_OK;
2745 }
2746
2747 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2748 {
2749 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2750 FIXME("stub - %p\n", This);
2751 return E_NOTIMPL;
2752 }
2753
2754 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2755 {
2756 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2757 FIXME("stub - %p (%p)\n", This, pFilter);
2758 return E_NOTIMPL;
2759 }
2760
2761 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2762 {
2763 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2764 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2765
2766 LocalFree(This->custom_cancelbutton);
2767 This->custom_cancelbutton = StrDupW(pszLabel);
2768 update_control_text(This);
2769 update_layout(This);
2770
2771 return S_OK;
2772 }
2773
2774 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2775 {
2776 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2777 FIXME("stub - %p (%p)\n", This, psi);
2778 return E_NOTIMPL;
2779 }
2780
2781 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2782 IFileDialog2_fnQueryInterface,
2783 IFileDialog2_fnAddRef,
2784 IFileDialog2_fnRelease,
2785 IFileDialog2_fnShow,
2786 IFileDialog2_fnSetFileTypes,
2787 IFileDialog2_fnSetFileTypeIndex,
2788 IFileDialog2_fnGetFileTypeIndex,
2789 IFileDialog2_fnAdvise,
2790 IFileDialog2_fnUnadvise,
2791 IFileDialog2_fnSetOptions,
2792 IFileDialog2_fnGetOptions,
2793 IFileDialog2_fnSetDefaultFolder,
2794 IFileDialog2_fnSetFolder,
2795 IFileDialog2_fnGetFolder,
2796 IFileDialog2_fnGetCurrentSelection,
2797 IFileDialog2_fnSetFileName,
2798 IFileDialog2_fnGetFileName,
2799 IFileDialog2_fnSetTitle,
2800 IFileDialog2_fnSetOkButtonLabel,
2801 IFileDialog2_fnSetFileNameLabel,
2802 IFileDialog2_fnGetResult,
2803 IFileDialog2_fnAddPlace,
2804 IFileDialog2_fnSetDefaultExtension,
2805 IFileDialog2_fnClose,
2806 IFileDialog2_fnSetClientGuid,
2807 IFileDialog2_fnClearClientData,
2808 IFileDialog2_fnSetFilter,
2809 IFileDialog2_fnSetCancelButtonLabel,
2810 IFileDialog2_fnSetNavigationRoot
2811 };
2812
2813 /**************************************************************************
2814 * IFileOpenDialog
2815 */
2816 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2817 {
2818 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2819 }
2820
2821 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2822 REFIID riid, void **ppvObject)
2823 {
2824 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2825 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2826 }
2827
2828 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2829 {
2830 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2831 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2832 }
2833
2834 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2835 {
2836 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2837 return IFileDialog2_Release(&This->IFileDialog2_iface);
2838 }
2839
2840 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2841 {
2842 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2843 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2844 }
2845
2846 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2847 const COMDLG_FILTERSPEC *rgFilterSpec)
2848 {
2849 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2850 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2851 }
2852
2853 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2854 {
2855 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2856 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2857 }
2858
2859 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2860 {
2861 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2862 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2863 }
2864
2865 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2866 DWORD *pdwCookie)
2867 {
2868 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2869 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2870 }
2871
2872 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2873 {
2874 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2875 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2876 }
2877
2878 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2879 {
2880 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2881 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2882 }
2883
2884 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2885 {
2886 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2887 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2888 }
2889
2890 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2891 {
2892 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2893 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2894 }
2895
2896 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2897 {
2898 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2899 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2900 }
2901
2902 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2903 {
2904 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2905 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2906 }
2907
2908 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2909 {
2910 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2911 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2912 }
2913
2914 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2915 {
2916 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2917 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2918 }
2919
2920 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2921 {
2922 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2923 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2924 }
2925
2926 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2927 {
2928 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2929 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2930 }
2931
2932 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2933 {
2934 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2935 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2936 }
2937
2938 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2939 {
2940 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2941 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2942 }
2943
2944 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2945 {
2946 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2947 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2948 }
2949
2950 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2951 {
2952 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2953 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2954 }
2955
2956 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2957 LPCWSTR pszDefaultExtension)
2958 {
2959 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2960 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2961 }
2962
2963 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2964 {
2965 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2966 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2967 }
2968
2969 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2970 {
2971 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2972 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2973 }
2974
2975 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2976 {
2977 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2978 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2979 }
2980
2981 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2982 {
2983 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2984 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2985 }
2986
2987 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2988 {
2989 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2990 TRACE("%p (%p)\n", This, ppenum);
2991
2992 *ppenum = This->psia_results;
2993
2994 if(*ppenum)
2995 {
2996 IShellItemArray_AddRef(*ppenum);
2997 return S_OK;
2998 }
2999
3000 return E_FAIL;
3001 }
3002
3003 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
3004 {
3005 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
3006 TRACE("%p (%p)\n", This, ppsai);
3007
3008 if(This->psia_selection)
3009 {
3010 *ppsai = This->psia_selection;
3011 IShellItemArray_AddRef(*ppsai);
3012 return S_OK;
3013 }
3014
3015 return E_FAIL;
3016 }
3017
3018 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
3019 IFileOpenDialog_fnQueryInterface,
3020 IFileOpenDialog_fnAddRef,
3021 IFileOpenDialog_fnRelease,
3022 IFileOpenDialog_fnShow,
3023 IFileOpenDialog_fnSetFileTypes,
3024 IFileOpenDialog_fnSetFileTypeIndex,
3025 IFileOpenDialog_fnGetFileTypeIndex,
3026 IFileOpenDialog_fnAdvise,
3027 IFileOpenDialog_fnUnadvise,
3028 IFileOpenDialog_fnSetOptions,
3029 IFileOpenDialog_fnGetOptions,
3030 IFileOpenDialog_fnSetDefaultFolder,
3031 IFileOpenDialog_fnSetFolder,
3032 IFileOpenDialog_fnGetFolder,
3033 IFileOpenDialog_fnGetCurrentSelection,
3034 IFileOpenDialog_fnSetFileName,
3035 IFileOpenDialog_fnGetFileName,
3036 IFileOpenDialog_fnSetTitle,
3037 IFileOpenDialog_fnSetOkButtonLabel,
3038 IFileOpenDialog_fnSetFileNameLabel,
3039 IFileOpenDialog_fnGetResult,
3040 IFileOpenDialog_fnAddPlace,
3041 IFileOpenDialog_fnSetDefaultExtension,
3042 IFileOpenDialog_fnClose,
3043 IFileOpenDialog_fnSetClientGuid,
3044 IFileOpenDialog_fnClearClientData,
3045 IFileOpenDialog_fnSetFilter,
3046 IFileOpenDialog_fnGetResults,
3047 IFileOpenDialog_fnGetSelectedItems
3048 };
3049
3050 /**************************************************************************
3051 * IFileSaveDialog
3052 */
3053 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
3054 {
3055 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
3056 }
3057
3058 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
3059 REFIID riid,
3060 void **ppvObject)
3061 {
3062 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3063 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3064 }
3065
3066 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
3067 {
3068 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3069 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3070 }
3071
3072 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
3073 {
3074 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3075 return IFileDialog2_Release(&This->IFileDialog2_iface);
3076 }
3077
3078 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
3079 {
3080 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3081 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
3082 }
3083
3084 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
3085 const COMDLG_FILTERSPEC *rgFilterSpec)
3086 {
3087 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3088 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
3089 }
3090
3091 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
3092 {
3093 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3094 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
3095 }
3096
3097 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
3098 {
3099 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3100 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
3101 }
3102
3103 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
3104 DWORD *pdwCookie)
3105 {
3106 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3107 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
3108 }
3109
3110 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
3111 {
3112 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3113 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
3114 }
3115
3116 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
3117 {
3118 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3119 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
3120 }
3121
3122 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
3123 {
3124 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3125 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
3126 }
3127
3128 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
3129 {
3130 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3131 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
3132 }
3133
3134 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
3135 {
3136 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3137 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
3138 }
3139
3140 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
3141 {
3142 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3143 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
3144 }
3145
3146 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
3147 {
3148 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3149 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
3150 }
3151
3152 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
3153 {
3154 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3155 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
3156 }
3157
3158 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
3159 {
3160 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3161 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
3162 }
3163
3164 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
3165 {
3166 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3167 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
3168 }
3169
3170 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
3171 {
3172 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3173 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
3174 }
3175
3176 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
3177 {
3178 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3179 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
3180 }
3181
3182 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
3183 {
3184 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3185 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
3186 }
3187
3188 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
3189 {
3190 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3191 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
3192 }
3193
3194 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
3195 LPCWSTR pszDefaultExtension)
3196 {
3197 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3198 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
3199 }
3200
3201 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
3202 {
3203 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3204 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
3205 }
3206
3207 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
3208 {
3209 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3210 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
3211 }
3212
3213 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
3214 {
3215 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3216 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
3217 }
3218
3219 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
3220 {
3221 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3222 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
3223 }
3224
3225 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
3226 {
3227 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3228 FIXME("stub - %p (%p)\n", This, psi);
3229 return E_NOTIMPL;
3230 }
3231
3232 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
3233 {
3234 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3235 FIXME("stub - %p (%p)\n", This, pStore);
3236 return E_NOTIMPL;
3237 }
3238
3239 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
3240 IPropertyDescriptionList *pList,
3241 BOOL fAppendDefault)
3242 {
3243 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3244 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
3245 return E_NOTIMPL;
3246 }
3247
3248 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
3249 {
3250 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3251 FIXME("stub - %p (%p)\n", This, ppStore);
3252 return E_NOTIMPL;
3253 }
3254
3255 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
3256 IShellItem *psi,
3257 IPropertyStore *pStore,
3258 HWND hwnd,
3259 IFileOperationProgressSink *pSink)
3260 {
3261 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3262 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
3263 return E_NOTIMPL;
3264 }
3265
3266 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
3267 IFileSaveDialog_fnQueryInterface,
3268 IFileSaveDialog_fnAddRef,
3269 IFileSaveDialog_fnRelease,
3270 IFileSaveDialog_fnShow,
3271 IFileSaveDialog_fnSetFileTypes,
3272 IFileSaveDialog_fnSetFileTypeIndex,
3273 IFileSaveDialog_fnGetFileTypeIndex,
3274 IFileSaveDialog_fnAdvise,
3275 IFileSaveDialog_fnUnadvise,
3276 IFileSaveDialog_fnSetOptions,
3277 IFileSaveDialog_fnGetOptions,
3278 IFileSaveDialog_fnSetDefaultFolder,
3279 IFileSaveDialog_fnSetFolder,
3280 IFileSaveDialog_fnGetFolder,
3281 IFileSaveDialog_fnGetCurrentSelection,
3282 IFileSaveDialog_fnSetFileName,
3283 IFileSaveDialog_fnGetFileName,
3284 IFileSaveDialog_fnSetTitle,
3285 IFileSaveDialog_fnSetOkButtonLabel,
3286 IFileSaveDialog_fnSetFileNameLabel,
3287 IFileSaveDialog_fnGetResult,
3288 IFileSaveDialog_fnAddPlace,
3289 IFileSaveDialog_fnSetDefaultExtension,
3290 IFileSaveDialog_fnClose,
3291 IFileSaveDialog_fnSetClientGuid,
3292 IFileSaveDialog_fnClearClientData,
3293 IFileSaveDialog_fnSetFilter,
3294 IFileSaveDialog_fnSetSaveAsItem,
3295 IFileSaveDialog_fnSetProperties,
3296 IFileSaveDialog_fnSetCollectedProperties,
3297 IFileSaveDialog_fnGetProperties,
3298 IFileSaveDialog_fnApplyProperties
3299 };
3300
3301 /**************************************************************************
3302 * IExplorerBrowserEvents implementation
3303 */
3304 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
3305 {
3306 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
3307 }
3308
3309 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
3310 REFIID riid, void **ppvObject)
3311 {
3312 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3313 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
3314
3315 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3316 }
3317
3318 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
3319 {
3320 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3321 TRACE("%p\n", This);
3322 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3323 }
3324
3325 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
3326 {
3327 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3328 TRACE("%p\n", This);
3329 return IFileDialog2_Release(&This->IFileDialog2_iface);
3330 }
3331
3332 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
3333 PCIDLIST_ABSOLUTE pidlFolder)
3334 {
3335 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3336 IShellItem *psi;
3337 HRESULT hr;
3338 TRACE("%p (%p)\n", This, pidlFolder);
3339
3340 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
3341 if(SUCCEEDED(hr))
3342 {
3343 hr = events_OnFolderChanging(This, psi);
3344 IShellItem_Release(psi);
3345
3346 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
3347 if(hr == S_FALSE)
3348 hr = E_FAIL;
3349
3350 return hr;
3351 }
3352 else
3353 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
3354
3355 return S_OK;
3356 }
3357
3358 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
3359 IShellView *psv)
3360 {
3361 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3362 TRACE("%p (%p)\n", This, psv);
3363 return S_OK;
3364 }
3365
3366 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
3367 PCIDLIST_ABSOLUTE pidlFolder)
3368 {
3369 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3370 HRESULT hr;
3371 TRACE("%p (%p)\n", This, pidlFolder);
3372
3373 if(This->psi_folder)
3374 IShellItem_Release(This->psi_folder);
3375
3376 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
3377 if(FAILED(hr))
3378 {
3379 ERR("Failed to get the current folder.\n");
3380 This->psi_folder = NULL;
3381 }
3382
3383 events_OnFolderChange(This);
3384
3385 return S_OK;
3386 }
3387
3388 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
3389 PCIDLIST_ABSOLUTE pidlFolder)
3390 {
3391 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3392 TRACE("%p (%p)\n", This, pidlFolder);
3393 return S_OK;
3394 }
3395
3396 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
3397 IExplorerBrowserEvents_fnQueryInterface,
3398 IExplorerBrowserEvents_fnAddRef,
3399 IExplorerBrowserEvents_fnRelease,
3400 IExplorerBrowserEvents_fnOnNavigationPending,
3401 IExplorerBrowserEvents_fnOnViewCreated,
3402 IExplorerBrowserEvents_fnOnNavigationComplete,
3403 IExplorerBrowserEvents_fnOnNavigationFailed
3404 };
3405
3406 /**************************************************************************
3407 * IServiceProvider implementation
3408 */
3409 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
3410 {
3411 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
3412 }
3413
3414 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
3415 REFIID riid, void **ppvObject)
3416 {
3417 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3418 TRACE("%p\n", This);
3419 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3420 }
3421
3422 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
3423 {
3424 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3425 TRACE("%p\n", This);
3426 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3427 }
3428
3429 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
3430 {
3431 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3432 TRACE("%p\n", This);
3433 return IFileDialog2_Release(&This->IFileDialog2_iface);
3434 }
3435
3436 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
3437 REFGUID guidService,
3438 REFIID riid, void **ppv)
3439 {
3440 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3441 HRESULT hr = E_NOTIMPL;
3442 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
3443
3444 *ppv = NULL;
3445 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
3446 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
3447 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
3448 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
3449 else
3450 FIXME("Interface %s requested from unknown service %s\n",
3451 debugstr_guid(riid), debugstr_guid(guidService));
3452
3453 return hr;
3454 }
3455
3456 static const IServiceProviderVtbl vt_IServiceProvider = {
3457 IServiceProvider_fnQueryInterface,
3458 IServiceProvider_fnAddRef,
3459 IServiceProvider_fnRelease,
3460 IServiceProvider_fnQueryService
3461 };
3462
3463 /**************************************************************************
3464 * ICommDlgBrowser3 implementation
3465 */
3466 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
3467 {
3468 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
3469 }
3470
3471 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
3472 REFIID riid, void **ppvObject)
3473 {
3474 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3475 TRACE("%p\n", This);
3476 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3477 }
3478
3479 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
3480 {
3481 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3482 TRACE("%p\n", This);
3483 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3484 }
3485
3486 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
3487 {
3488 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3489 TRACE("%p\n", This);
3490 return IFileDialog2_Release(&This->IFileDialog2_iface);
3491 }
3492
3493 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
3494 IShellView *shv)
3495 {
3496 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3497 HRESULT hr;
3498 TRACE("%p (%p)\n", This, shv);
3499
3500 hr = on_default_action(This);
3501
3502 if(SUCCEEDED(hr))
3503 EndDialog(This->dlg_hwnd, S_OK);
3504
3505 return S_OK;
3506 }
3507
3508 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
3509 IShellView *shv, ULONG uChange )
3510 {
3511 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3512 IDataObject *new_selection;
3513 HRESULT hr;
3514 TRACE("%p (%p, %x)\n", This, shv, uChange);
3515
3516 switch(uChange)
3517 {
3518 case CDBOSC_SELCHANGE:
3519 if(This->psia_selection)
3520 {
3521 IShellItemArray_Release(This->psia_selection);
3522 This->psia_selection = NULL;
3523 }
3524
3525 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
3526 if(SUCCEEDED(hr))
3527 {
3528 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
3529 (void**)&This->psia_selection);
3530 if(SUCCEEDED(hr))
3531 {
3532 fill_filename_from_selection(This);
3533 events_OnSelectionChange(This);
3534 }
3535
3536 IDataObject_Release(new_selection);
3537 }
3538 break;
3539 default:
3540 TRACE("Unhandled state change\n");
3541 }
3542 return S_OK;
3543 }
3544
3545 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
3546 IShellView *shv, LPCITEMIDLIST pidl)
3547 {
3548 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3549 IShellItem *psi;
3550 LPWSTR filename;
3551 LPITEMIDLIST parent_pidl;
3552 HRESULT hr;
3553 ULONG attr;
3554 TRACE("%p (%p, %p)\n", This, shv, pidl);
3555
3556 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
3557 return S_OK;
3558
3559 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3560 if(SUCCEEDED(hr))
3561 {
3562 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3563 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3564 ILFree(parent_pidl);
3565 ILFree(full_pidl);
3566 }
3567 if(FAILED(hr))
3568 {
3569 ERR("Failed to get shellitem (%08x).\n", hr);
3570 return S_OK;
3571 }
3572
3573 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3574 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3575 {
3576 IShellItem_Release(psi);
3577 return S_OK;
3578 }
3579
3580 if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
3581 {
3582 IShellItem_Release(psi);
3583 return S_FALSE;
3584 }
3585
3586 hr = S_OK;
3587 if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
3588 {
3589 if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
3590 hr = S_FALSE;
3591 CoTaskMemFree(filename);
3592 }
3593
3594 IShellItem_Release(psi);
3595 return hr;
3596 }
3597
3598 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
3599 IShellView *ppshv, DWORD dwNotifyType)
3600 {
3601 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3602 FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
3603 return E_NOTIMPL;
3604 }
3605
3606 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
3607 IShellView *pshv,
3608 LPWSTR pszText, int cchMax)
3609 {
3610 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3611 FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
3612 return E_NOTIMPL;
3613 }
3614
3615 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
3616 {
3617 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3618 FIXME("Stub: %p (%p)\n", This, pdwFlags);
3619 return E_NOTIMPL;
3620 }
3621
3622 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
3623 IShellView *pshv, int iColumn)
3624 {
3625 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3626 FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
3627 return E_NOTIMPL;
3628 }
3629
3630 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
3631 LPWSTR pszFileSpec, int cchFileSpec)
3632 {
3633 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3634 FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
3635 return E_NOTIMPL;
3636 }
3637
3638 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
3639 IShellView *pshv)
3640 {
3641 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3642 FIXME("Stub: %p (%p)\n", This, pshv);
3643 return E_NOTIMPL;
3644 }
3645
3646 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
3647 ICommDlgBrowser3_fnQueryInterface,
3648 ICommDlgBrowser3_fnAddRef,
3649 ICommDlgBrowser3_fnRelease,
3650 ICommDlgBrowser3_fnOnDefaultCommand,
3651 ICommDlgBrowser3_fnOnStateChange,
3652 ICommDlgBrowser3_fnIncludeObject,
3653 ICommDlgBrowser3_fnNotify,
3654 ICommDlgBrowser3_fnGetDefaultMenuText,
3655 ICommDlgBrowser3_fnGetViewFlags,
3656 ICommDlgBrowser3_fnOnColumnClicked,
3657 ICommDlgBrowser3_fnGetCurrentFilter,
3658 ICommDlgBrowser3_fnOnPreviewCreated
3659 };
3660
3661 /**************************************************************************
3662 * IOleWindow implementation
3663 */
3664 static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
3665 {
3666 return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
3667 }
3668
3669 static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
3670 {
3671 FileDialogImpl *This = impl_from_IOleWindow(iface);
3672 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3673 }
3674
3675 static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
3676 {
3677 FileDialogImpl *This = impl_from_IOleWindow(iface);
3678 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3679 }
3680
3681 static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
3682 {
3683 FileDialogImpl *This = impl_from_IOleWindow(iface);
3684 return IFileDialog2_Release(&This->IFileDialog2_iface);
3685 }
3686
3687 static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
3688 {
3689 FileDialogImpl *This = impl_from_IOleWindow(iface);
3690 FIXME("Stub: %p (%d)\n", This, fEnterMOde);
3691 return E_NOTIMPL;
3692 }
3693
3694 static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
3695 {
3696 FileDialogImpl *This = impl_from_IOleWindow(iface);
3697 TRACE("%p (%p)\n", This, phwnd);
3698 *phwnd = This->dlg_hwnd;
3699 return S_OK;
3700 }
3701
3702 static const IOleWindowVtbl vt_IOleWindow = {
3703 IOleWindow_fnQueryInterface,
3704 IOleWindow_fnAddRef,
3705 IOleWindow_fnRelease,
3706 IOleWindow_fnGetWindow,
3707 IOleWindow_fnContextSensitiveHelp
3708 };
3709
3710 /**************************************************************************
3711 * IFileDialogCustomize implementation
3712 */
3713 static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
3714 {
3715 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
3716 }
3717
3718 static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
3719 REFIID riid, void **ppvObject)
3720 {
3721 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3722 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3723 }
3724
3725 static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
3726 {
3727 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3728 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3729 }
3730
3731 static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
3732 {
3733 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3734 return IFileDialog2_Release(&This->IFileDialog2_iface);
3735 }
3736
3737 static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
3738 DWORD dwIDCtl)
3739 {
3740 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3741 MENUINFO mi;
3742 TRACE("%p (%d)\n", This, dwIDCtl);
3743
3744 if (This->hmenu_opendropdown || get_cctrl(This, dwIDCtl))
3745 return E_UNEXPECTED;
3746
3747 This->hmenu_opendropdown = CreatePopupMenu();
3748
3749 if (!This->hmenu_opendropdown)
3750 return E_OUTOFMEMORY;
3751
3752 mi.cbSize = sizeof(mi);
3753 mi.fMask = MIM_STYLE;
3754 mi.dwStyle = MNS_NOTIFYBYPOS;
3755 SetMenuInfo(This->hmenu_opendropdown, &mi);
3756
3757 This->cctrl_opendropdown.hwnd = NULL;
3758 This->cctrl_opendropdown.wrapper_hwnd = NULL;
3759 This->cctrl_opendropdown.id = dwIDCtl;
3760 This->cctrl_opendropdown.dlgid = 0;
3761 This->cctrl_opendropdown.type = IDLG_CCTRL_OPENDROPDOWN;
3762 This->cctrl_opendropdown.cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
3763 list_init(&This->cctrl_opendropdown.sub_cctrls);
3764 list_init(&This->cctrl_opendropdown.sub_items);
3765
3766 return S_OK;
3767 }
3768
3769 static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
3770 DWORD dwIDCtl,
3771 LPCWSTR pszLabel)
3772 {
3773 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3774 customctrl *ctrl;
3775 TBBUTTON tbb;
3776 HRESULT hr;
3777 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3778
3779 hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
3780 TBSTYLE_FLAT | CCS_NODIVIDER, 0,
3781 This->cctrl_def_height, &ctrl);
3782 if(SUCCEEDED(hr))
3783 {
3784 SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
3785 ctrl->type = IDLG_CCTRL_MENU;
3786
3787 /* Add the actual button with a popup menu. */
3788 tbb.iBitmap = I_IMAGENONE;
3789 tbb.dwData = (DWORD_PTR)CreatePopupMenu();
3790 tbb.iString = (DWORD_PTR)pszLabel;
3791 tbb.fsState = TBSTATE_ENABLED;
3792 tbb.fsStyle = BTNS_WHOLEDROPDOWN;
3793 tbb.idCommand = 1;
3794
3795 SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
3796 }
3797
3798 return hr;
3799 }
3800
3801 static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
3802 DWORD dwIDCtl,
3803 LPCWSTR pszLabel)
3804 {
3805 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3806 customctrl *ctrl;
3807 HRESULT hr;
3808 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3809
3810 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
3811 This->cctrl_def_height, &ctrl);
3812 if(SUCCEEDED(hr))
3813 ctrl->type = IDLG_CCTRL_PUSHBUTTON;
3814
3815 return hr;
3816 }
3817
3818 static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
3819 DWORD dwIDCtl)
3820 {
3821 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3822 customctrl *ctrl;
3823 HRESULT hr;
3824 TRACE("%p (%d)\n", This, dwIDCtl);
3825
3826 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
3827 This->cctrl_def_height, &ctrl);
3828 if(SUCCEEDED(hr))
3829 ctrl->type = IDLG_CCTRL_COMBOBOX;
3830
3831 return hr;
3832 }
3833
3834 static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
3835 DWORD dwIDCtl)
3836 {
3837 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3838 customctrl *ctrl;
3839 HRESULT hr;
3840 TRACE("%p (%d)\n", This, dwIDCtl);
3841
3842 hr = cctrl_create_new(This, dwIDCtl, NULL, radiobuttonlistW, 0, 0, 0, &ctrl);
3843 if(SUCCEEDED(hr))
3844 {
3845 ctrl->type = IDLG_CCTRL_RADIOBUTTONLIST;
3846 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)This);
3847 }
3848
3849 return hr;
3850 }
3851
3852 static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
3853 DWORD dwIDCtl,
3854 LPCWSTR pszLabel,
3855 BOOL bChecked)
3856 {
3857 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3858 customctrl *ctrl;
3859 HRESULT hr;
3860 TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
3861
3862 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0,
3863 This->cctrl_def_height, &ctrl);
3864 if(SUCCEEDED(hr))
3865 {
3866 ctrl->type = IDLG_CCTRL_CHECKBUTTON;
3867 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
3868 }
3869
3870 return hr;
3871 }
3872
3873 static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
3874 DWORD dwIDCtl,
3875 LPCWSTR pszText)
3876 {
3877 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3878 customctrl *ctrl;
3879 HRESULT hr;
3880 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3881
3882 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
3883 This->cctrl_def_height, &ctrl);
3884 if(SUCCEEDED(hr))
3885 ctrl->type = IDLG_CCTRL_EDITBOX;
3886
3887 return hr;
3888 }
3889
3890 static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
3891 DWORD dwIDCtl)
3892 {
3893 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3894 customctrl *ctrl;
3895 HRESULT hr;
3896 TRACE("%p (%d)\n", This, dwIDCtl);
3897
3898 hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
3899 GetSystemMetrics(SM_CYEDGE), &ctrl);
3900 if(SUCCEEDED(hr))
3901 ctrl->type = IDLG_CCTRL_SEPARATOR;
3902
3903 return hr;
3904 }
3905
3906 static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
3907 DWORD dwIDCtl,
3908 LPCWSTR pszText)
3909 {
3910 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3911 customctrl *ctrl;
3912 HRESULT hr;
3913 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
3914
3915 hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
3916 This->cctrl_def_height, &ctrl);
3917 if(SUCCEEDED(hr))
3918 ctrl->type = IDLG_CCTRL_TEXT;
3919
3920 return hr;
3921 }
3922
3923 static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
3924 DWORD dwIDCtl,
3925 LPCWSTR pszLabel)
3926 {
3927 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3928 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3929 TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
3930
3931 if(!ctrl) return E_INVALIDARG;
3932
3933 switch(ctrl->type)
3934 {
3935 case IDLG_CCTRL_MENU:
3936 case IDLG_CCTRL_PUSHBUTTON:
3937 case IDLG_CCTRL_CHECKBUTTON:
3938 case IDLG_CCTRL_TEXT:
3939 case IDLG_CCTRL_VISUALGROUP:
3940 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
3941 break;
3942 case IDLG_CCTRL_OPENDROPDOWN:
3943 return E_NOTIMPL;
3944 default:
3945 break;
3946 }
3947
3948 return S_OK;
3949 }
3950
3951 static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
3952 DWORD dwIDCtl,
3953 CDCONTROLSTATEF *pdwState)
3954 {
3955 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3956 customctrl *ctrl = get_cctrl(This, dwIDCtl);
3957 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
3958
3959 if(!ctrl || ctrl->type == IDLG_CCTRL_OPENDROPDOWN) return E_NOTIMPL;
3960
3961 *pdwState = ctrl->cdcstate;
3962 return S_OK;
3963 }
3964
3965 static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
3966 DWORD dwIDCtl,
3967 CDCONTROLSTATEF dwState)
3968 {
3969 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
3970 customctrl *ctrl = get_cctrl(This,dwIDCtl);
3971 TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
3972
3973 if(ctrl && ctrl->hwnd)
3974 {
3975 LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
3976
3977 if(dwState & CDCS_ENABLED)
3978 wndstyle &= ~(WS_DISABLED);
3979 else
3980 wndstyle |= WS_DISABLED;
3981
3982 if(dwState & CDCS_VISIBLE)
3983 wndstyle |= WS_VISIBLE;
3984 else
3985 wndstyle &= ~(WS_VISIBLE);
3986
3987 SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
3988
3989 /* We save the state separately since at least one application
3990 * relies on being able to hide a control. */
3991 ctrl->cdcstate = dwState;
3992 }
3993
3994 return S_OK;
3995 }
3996
3997 static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
3998 DWORD dwIDCtl,
3999 WCHAR **ppszText)
4000 {
4001 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4002 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4003 WCHAR len, *text;
4004 TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
4005
4006 if(!ctrl || !ctrl->hwnd || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
4007 return E_FAIL;
4008
4009 text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
4010 if(!text) return E_FAIL;
4011
4012 SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
4013 *ppszText = text;
4014 return S_OK;
4015 }
4016
4017 static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
4018 DWORD dwIDCtl,
4019 LPCWSTR pszText)
4020 {
4021 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4022 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4023 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
4024
4025 if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
4026 return E_FAIL;
4027
4028 SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
4029 return S_OK;
4030 }
4031
4032 static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
4033 DWORD dwIDCtl,
4034 BOOL *pbChecked)
4035 {
4036 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4037 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4038 TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
4039
4040 if(ctrl && ctrl->hwnd)
4041 *pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
4042
4043 return S_OK;
4044 }
4045
4046 static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
4047 DWORD dwIDCtl,
4048 BOOL bChecked)
4049 {
4050 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4051 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4052 TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
4053
4054 if(ctrl && ctrl->hwnd)
4055 SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
4056
4057 return S_OK;
4058 }
4059
4060 static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
4061 {
4062 UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
4063 UINT i;
4064 if(!count || (count == CB_ERR))
4065 return -1;
4066
4067 for(i = 0; i < count; i++)
4068 if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
4069 return i;
4070
4071 TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
4072 return -1;
4073 }
4074
4075 static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
4076 DWORD dwIDCtl,
4077 DWORD dwIDItem,
4078 LPCWSTR pszLabel)
4079 {
4080 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4081 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4082 HRESULT hr;
4083 TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4084
4085 if(!ctrl) return E_FAIL;
4086
4087 switch(ctrl->type)
4088 {
4089 case IDLG_CCTRL_COMBOBOX:
4090 {
4091 UINT index;
4092 cctrl_item* item;
4093
4094 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4095
4096 if (FAILED(hr)) return hr;
4097
4098 index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
4099 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
4100
4101 return S_OK;
4102 }
4103 case IDLG_CCTRL_MENU:
4104 case IDLG_CCTRL_OPENDROPDOWN:
4105 {
4106 cctrl_item* item;
4107 HMENU hmenu;
4108
4109 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4110
4111 if (FAILED(hr)) return hr;
4112
4113 if (ctrl->type == IDLG_CCTRL_MENU)
4114 {
4115 TBBUTTON tbb;
4116 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4117 hmenu = (HMENU)tbb.dwData;
4118 }
4119 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4120 hmenu = This->hmenu_opendropdown;
4121
4122 AppendMenuW(hmenu, MF_STRING, dwIDItem, pszLabel);
4123 return S_OK;
4124 }
4125 case IDLG_CCTRL_RADIOBUTTONLIST:
4126 {
4127 cctrl_item* item;
4128
4129 hr = add_item(ctrl, dwIDItem, pszLabel, &item);
4130
4131 if (SUCCEEDED(hr))
4132 {
4133 item->hwnd = CreateWindowExW(0, WC_BUTTONW, pszLabel,
4134 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|BS_RADIOBUTTON|BS_MULTILINE,
4135 0, 0, 0, 0, ctrl->hwnd, ULongToHandle(dwIDItem), COMDLG32_hInstance, 0);
4136
4137 if (!item->hwnd)
4138 {
4139 ERR("Failed to create radio button\n");
4140 list_remove(&item->entry);
4141 item_free(item);
4142 return E_FAIL;
4143 }
4144 }
4145
4146 return hr;
4147 }
4148 default:
4149 break;
4150 }
4151
4152 return E_NOINTERFACE; /* win7 */
4153 }
4154
4155 static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
4156 DWORD dwIDCtl,
4157 DWORD dwIDItem)
4158 {
4159 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4160 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4161 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
4162
4163 if(!ctrl) return E_FAIL;
4164
4165 switch(ctrl->type)
4166 {
4167 case IDLG_CCTRL_COMBOBOX:
4168 {
4169 cctrl_item* item;
4170 DWORD position;
4171
4172 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4173
4174 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
4175 {
4176 if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0) == CB_ERR)
4177 return E_FAIL;
4178 }
4179
4180 list_remove(&item->entry);
4181 item_free(item);
4182
4183 return S_OK;
4184 }
4185 case IDLG_CCTRL_MENU:
4186 case IDLG_CCTRL_OPENDROPDOWN:
4187 {
4188 HMENU hmenu;
4189 cctrl_item* item;
4190
4191 item = get_item(ctrl, dwIDItem, 0, NULL);
4192
4193 if (!item)
4194 return E_UNEXPECTED;
4195
4196 if (item->cdcstate & CDCS_VISIBLE)
4197 {
4198 if (ctrl->type == IDLG_CCTRL_MENU)
4199 {
4200 TBBUTTON tbb;
4201 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4202 hmenu = (HMENU)tbb.dwData;
4203 }
4204 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4205 hmenu = This->hmenu_opendropdown;
4206
4207 if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
4208 return E_UNEXPECTED;
4209 }
4210
4211 list_remove(&item->entry);
4212 item_free(item);
4213
4214 return S_OK;
4215 }
4216 case IDLG_CCTRL_RADIOBUTTONLIST:
4217 {
4218 cctrl_item* item;
4219
4220 item = get_item(ctrl, dwIDItem, 0, NULL);
4221
4222 if (!item)
4223 return E_UNEXPECTED;
4224
4225 list_remove(&item->entry);
4226 item_free(item);
4227
4228 return S_OK;
4229 }
4230 default:
4231 break;
4232 }
4233
4234 return E_FAIL;
4235 }
4236
4237 static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
4238 DWORD dwIDCtl)
4239 {
4240 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4241 TRACE("%p (%d)\n", This, dwIDCtl);
4242
4243 /* Not implemented by native */
4244 return E_NOTIMPL;
4245 }
4246
4247 static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
4248 DWORD dwIDCtl,
4249 DWORD dwIDItem,
4250 CDCONTROLSTATEF *pdwState)
4251 {
4252 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4253 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4254 TRACE("%p (%d, %d, %p)\n", This, dwIDCtl, dwIDItem, pdwState);
4255
4256 if(!ctrl) return E_FAIL;
4257
4258 switch(ctrl->type)
4259 {
4260 case IDLG_CCTRL_COMBOBOX:
4261 case IDLG_CCTRL_MENU:
4262 case IDLG_CCTRL_OPENDROPDOWN:
4263 case IDLG_CCTRL_RADIOBUTTONLIST:
4264 {
4265 cctrl_item* item;
4266
4267 item = get_item(ctrl, dwIDItem, 0, NULL);
4268
4269 if (!item)
4270 return E_UNEXPECTED;
4271
4272 *pdwState = item->cdcstate;
4273
4274 return S_OK;
4275 }
4276 default:
4277 break;
4278 }
4279
4280 return E_FAIL;
4281 }
4282
4283 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
4284 DWORD dwIDCtl,
4285 DWORD dwIDItem,
4286 CDCONTROLSTATEF dwState)
4287 {
4288 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4289 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4290 TRACE("%p (%d, %d, %x)\n", This, dwIDCtl, dwIDItem, dwState);
4291
4292 if(!ctrl) return E_FAIL;
4293
4294 switch(ctrl->type)
4295 {
4296 case IDLG_CCTRL_COMBOBOX:
4297 {
4298 cctrl_item* item;
4299 BOOL visible, was_visible;
4300 DWORD position;
4301
4302 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
4303
4304 if (!item)
4305 return E_UNEXPECTED;
4306
4307 visible = ((dwState & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4308 was_visible = ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
4309
4310 if (visible && !was_visible)
4311 {
4312 SendMessageW(ctrl->hwnd, CB_INSERTSTRING, position, (LPARAM)item->label);
4313 SendMessageW(ctrl->hwnd, CB_SETITEMDATA, position, dwIDItem);
4314 }
4315 else if (!visible && was_visible)
4316 {
4317 SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0);
4318 }
4319
4320 item->cdcstate = dwState;
4321
4322 return S_OK;
4323 }
4324 case IDLG_CCTRL_MENU:
4325 case IDLG_CCTRL_OPENDROPDOWN:
4326 {
4327 HMENU hmenu;
4328 cctrl_item* item;
4329 CDCONTROLSTATEF prev_state;
4330 DWORD position;
4331
4332 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, &position);
4333
4334 if (!item)
4335 return E_UNEXPECTED;
4336
4337 prev_state = item->cdcstate;
4338
4339 if (ctrl->type == IDLG_CCTRL_MENU)
4340 {
4341 TBBUTTON tbb;
4342 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
4343 hmenu = (HMENU)tbb.dwData;
4344 }
4345 else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
4346 hmenu = This->hmenu_opendropdown;
4347
4348 if (dwState & CDCS_VISIBLE)
4349 {
4350 if (prev_state & CDCS_VISIBLE)
4351 {
4352 /* change state */
4353 EnableMenuItem(hmenu, dwIDItem,
4354 MF_BYCOMMAND|((dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED));
4355 }
4356 else
4357 {
4358 /* show item */
4359 MENUITEMINFOW mii;
4360
4361 mii.cbSize = sizeof(mii);
4362 mii.fMask = MIIM_ID|MIIM_STATE|MIIM_STRING;
4363 mii.fState = (dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED;
4364 mii.wID = dwIDItem;
4365 mii.dwTypeData = item->label;
4366
4367 InsertMenuItemW(hmenu, position, TRUE, &mii);
4368 }
4369 }
4370 else if (prev_state & CDCS_VISIBLE)
4371 {
4372 /* hide item */
4373 DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND);
4374 }
4375
4376 item->cdcstate = dwState;
4377
4378 if (ctrl->type == IDLG_CCTRL_OPENDROPDOWN)
4379 {
4380 update_control_text(This);
4381 update_layout(This);
4382 }
4383
4384 return S_OK;
4385 }
4386 case IDLG_CCTRL_RADIOBUTTONLIST:
4387 {
4388 cctrl_item* item;
4389
4390 item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, NULL);
4391
4392 if (!item)
4393 return E_UNEXPECTED;
4394
4395 /* Oddly, native allows setting this but doesn't seem to do anything with it. */
4396 item->cdcstate = dwState;
4397
4398 return S_OK;
4399 }
4400 default:
4401 break;
4402 }
4403
4404 return E_FAIL;
4405 }
4406
4407 static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
4408 DWORD dwIDCtl,
4409 DWORD *pdwIDItem)
4410 {
4411 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4412 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4413 TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
4414
4415 if(!ctrl) return E_FAIL;
4416
4417 switch(ctrl->type)
4418 {
4419 case IDLG_CCTRL_COMBOBOX:
4420 {
4421 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
4422 if(index == CB_ERR)
4423 return E_FAIL;
4424
4425 *pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
4426 return S_OK;
4427 }
4428 case IDLG_CCTRL_OPENDROPDOWN:
4429 if (This->opendropdown_has_selection)
4430 {
4431 *pdwIDItem = This->opendropdown_selection;
4432 return S_OK;
4433 }
4434 else
4435 {
4436 /* Return first enabled item. */
4437 cctrl_item* item = get_first_item(ctrl);
4438
4439 if (item)
4440 {
4441 *pdwIDItem = item->id;
4442 return S_OK;
4443 }
4444
4445 WARN("no enabled items in open dropdown\n");
4446 return E_FAIL;
4447 }
4448 case IDLG_CCTRL_RADIOBUTTONLIST:
4449 {
4450 cctrl_item* item;
4451
4452 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
4453 {
4454 if (SendMessageW(item->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED)
4455 {
4456 *pdwIDItem = item->id;
4457 return S_OK;
4458 }
4459 }
4460
4461 WARN("no checked items in radio button list\n");
4462 return E_FAIL;
4463 }
4464 default:
4465 FIXME("Unsupported control type %d\n", ctrl->type);
4466 }
4467
4468 return E_NOTIMPL;
4469 }
4470
4471 static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
4472 DWORD dwIDCtl,
4473 DWORD dwIDItem)
4474 {
4475 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4476 customctrl *ctrl = get_cctrl(This, dwIDCtl);
4477 TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
4478
4479 if(!ctrl) return E_INVALIDARG;
4480
4481 switch(ctrl->type)
4482 {
4483 case IDLG_CCTRL_COMBOBOX:
4484 {
4485 UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
4486
4487 if(index == -1)
4488 return E_INVALIDARG;
4489
4490 if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
4491 return E_FAIL;
4492
4493 return S_OK;
4494 }
4495 case IDLG_CCTRL_RADIOBUTTONLIST:
4496 {
4497 cctrl_item* item;
4498
4499 item = get_item(ctrl, dwIDItem, 0, NULL);
4500
4501 if (item)
4502 {
4503 radiobuttonlist_set_selected_item(This, ctrl, item);
4504 return S_OK;
4505 }
4506
4507 return E_INVALIDARG;
4508 }
4509 default:
4510 FIXME("Unsupported control type %d\n", ctrl->type);
4511 }
4512
4513 return E_INVALIDARG;
4514 }
4515
4516 static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
4517 DWORD dwIDCtl,
4518 LPCWSTR pszLabel)
4519 {
4520 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4521 customctrl *vg;
4522 HRESULT hr;
4523 TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
4524
4525 if(This->cctrl_active_vg)
4526 return E_UNEXPECTED;
4527
4528 hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0,
4529 This->cctrl_def_height, &vg);
4530 if(SUCCEEDED(hr))
4531 {
4532 vg->type = IDLG_CCTRL_VISUALGROUP;
4533 This->cctrl_active_vg = vg;
4534 }
4535
4536 return hr;
4537 }
4538
4539 static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
4540 {
4541 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4542 TRACE("%p\n", This);
4543
4544 This->cctrl_active_vg = NULL;
4545
4546 return S_OK;
4547 }
4548
4549 static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
4550 DWORD dwIDCtl)
4551 {
4552 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4553 FIXME("stub - %p (%d)\n", This, dwIDCtl);
4554 return S_OK;
4555 }
4556
4557 static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
4558 DWORD dwIDCtl,
4559 DWORD dwIDItem,
4560 LPCWSTR pszLabel)
4561 {
4562 FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
4563 FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
4564 return E_NOTIMPL;
4565 }
4566
4567 static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
4568 IFileDialogCustomize_fnQueryInterface,
4569 IFileDialogCustomize_fnAddRef,
4570 IFileDialogCustomize_fnRelease,
4571 IFileDialogCustomize_fnEnableOpenDropDown,
4572 IFileDialogCustomize_fnAddMenu,
4573 IFileDialogCustomize_fnAddPushButton,
4574 IFileDialogCustomize_fnAddComboBox,
4575 IFileDialogCustomize_fnAddRadioButtonList,
4576 IFileDialogCustomize_fnAddCheckButton,
4577 IFileDialogCustomize_fnAddEditBox,
4578 IFileDialogCustomize_fnAddSeparator,
4579 IFileDialogCustomize_fnAddText,
4580 IFileDialogCustomize_fnSetControlLabel,
4581 IFileDialogCustomize_fnGetControlState,
4582 IFileDialogCustomize_fnSetControlState,
4583 IFileDialogCustomize_fnGetEditBoxText,
4584 IFileDialogCustomize_fnSetEditBoxText,
4585 IFileDialogCustomize_fnGetCheckButtonState,
4586 IFileDialogCustomize_fnSetCheckButtonState,
4587 IFileDialogCustomize_fnAddControlItem,
4588 IFileDialogCustomize_fnRemoveControlItem,
4589 IFileDialogCustomize_fnRemoveAllControlItems,
4590 IFileDialogCustomize_fnGetControlItemState,
4591 IFileDialogCustomize_fnSetControlItemState,
4592 IFileDialogCustomize_fnGetSelectedControlItem,
4593 IFileDialogCustomize_fnSetSelectedControlItem,
4594 IFileDialogCustomize_fnStartVisualGroup,
4595 IFileDialogCustomize_fnEndVisualGroup,
4596 IFileDialogCustomize_fnMakeProminent,
4597 IFileDialogCustomize_fnSetControlItemText
4598 };
4599
4600 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
4601 {
4602 FileDialogImpl *fdimpl;
4603 HRESULT hr;
4604 IShellFolder *psf;
4605 TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
4606
4607 if(!ppv)
4608 return E_POINTER;
4609 if(pUnkOuter)
4610 return CLASS_E_NOAGGREGATION;
4611
4612 fdimpl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FileDialogImpl));
4613 if(!fdimpl)
4614 return E_OUTOFMEMORY;
4615
4616 fdimpl->ref = 1;
4617 fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
4618 fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
4619 fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
4620 fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
4621 fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
4622 fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
4623
4624 if(type == ITEMDLG_TYPE_OPEN)
4625 {
4626 fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
4627 fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
4628 fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
4629 fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
4630 }
4631 else
4632 {
4633 WCHAR buf[16];
4634 fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
4635 fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
4636 fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
4637
4638 LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, ARRAY_SIZE(buf));
4639 fdimpl->custom_title = StrDupW(buf);
4640 fdimpl->custom_okbutton = StrDupW(buf);
4641 }
4642
4643 list_init(&fdimpl->events_clients);
4644
4645 /* FIXME: The default folder setting should be restored for the
4646 * application if it was previously set. */
4647 SHGetDesktopFolder(&psf);
4648 SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
4649 IShellFolder_Release(psf);
4650
4651 hr = init_custom_controls(fdimpl);
4652 if(FAILED(hr))
4653 {
4654 ERR("Failed to initialize custom controls (0x%08x).\n", hr);
4655 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4656 return E_FAIL;
4657 }
4658
4659 hr = IFileDialog2_QueryInterface(&fdimpl->IFileDialog2_iface, riid, ppv);
4660 IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
4661 return hr;
4662 }
4663
4664 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4665 {
4666 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
4667 }
4668
4669 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
4670 {
4671 return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);
4672 }
4673
4674 #endif /* Win 7 */