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