5fcbf0755ce6576d638ea23e2b956e8aea3b4ec5
[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 if(This->set_filename)
390 LocalFree(This->set_filename);
391
392 This->set_filename = str ? StrDupW(str) : NULL;
393
394 return SetDlgItemTextW(This->dlg_hwnd, IDC_FILENAME, This->set_filename);
395 }
396
397 static void fill_filename_from_selection(FileDialogImpl *This)
398 {
399 IShellItem *psi;
400 LPWSTR *names;
401 HRESULT hr;
402 UINT item_count, valid_count;
403 UINT len_total, i;
404
405 if(!This->psia_selection)
406 return;
407
408 hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
409 if(FAILED(hr) || !item_count)
410 return;
411
412 names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
413
414 /* Get names of the selected items */
415 valid_count = 0; len_total = 0;
416 for(i = 0; i < item_count; i++)
417 {
418 hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
419 if(SUCCEEDED(hr))
420 {
421 UINT attr;
422
423 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
424 if(SUCCEEDED(hr) &&
425 (( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
426 (!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
427 continue;
428
429 hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
430 if(SUCCEEDED(hr))
431 {
432 len_total += lstrlenW(names[valid_count]) + 3;
433 valid_count++;
434 }
435 IShellItem_Release(psi);
436 }
437 }
438
439 if(valid_count == 1)
440 {
441 set_file_name(This, names[0]);
442 CoTaskMemFree(names[0]);
443 }
444 else if(valid_count > 1)
445 {
446 LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
447 LPWSTR cur_point = string;
448
449 for(i = 0; i < valid_count; i++)
450 {
451 LPWSTR file = names[i];
452 *cur_point++ = '\"';
453 lstrcpyW(cur_point, file);
454 cur_point += lstrlenW(file);
455 *cur_point++ = '\"';
456 *cur_point++ = ' ';
457 CoTaskMemFree(file);
458 }
459 *(cur_point-1) = '\0';
460
461 set_file_name(This, string);
462 HeapFree(GetProcessHeap(), 0, string);
463 }
464
465 HeapFree(GetProcessHeap(), 0, names);
466 return;
467 }
468
469 static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
470 {
471 WCHAR *endpos, *ext;
472
473 lstrcpyW(buf, spec);
474 if( (endpos = StrChrW(buf, ';')) )
475 *endpos = '\0';
476
477 ext = PathFindExtensionW(buf);
478 if(StrChrW(ext, '*'))
479 return NULL;
480
481 return ext;
482 }
483
484 static BOOL shell_item_exists(IShellItem* shellitem)
485 {
486 LPWSTR filename;
487 HRESULT hr;
488 BOOL result;
489
490 hr = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &filename);
491 if (SUCCEEDED(hr))
492 {
493 /* FIXME: Implement SFGAO_VALIDATE in Wine and use it instead. */
494 result = (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES);
495 CoTaskMemFree(filename);
496 }
497 else
498 {
499 SFGAOF attributes;
500 result = SUCCEEDED(IShellItem_GetAttributes(shellitem, SFGAO_VALIDATE, &attributes));
501 }
502
503 return result;
504 }
505
506 static HRESULT on_default_action(FileDialogImpl *This)
507 {
508 IShellFolder *psf_parent, *psf_desktop;
509 LPITEMIDLIST *pidla;
510 LPITEMIDLIST current_folder;
511 LPWSTR fn_iter, files = NULL, tmp_files;
512 UINT file_count = 0, len, i;
513 int open_action;
514 HRESULT hr, ret = E_FAIL;
515
516 len = get_file_name(This, &tmp_files);
517 if(len)
518 {
519 UINT size_used;
520 file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
521 CoTaskMemFree(tmp_files);
522 }
523 if(!file_count) return E_FAIL;
524
525 hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
526 if(FAILED(hr))
527 {
528 ERR("Failed to get pidl for current directory.\n");
529 HeapFree(GetProcessHeap(), 0, files);
530 return hr;
531 }
532
533 TRACE("Acting on %d file(s).\n", file_count);
534
535 pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
536 open_action = ONOPEN_OPEN;
537 fn_iter = files;
538
539 for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
540 {
541 WCHAR canon_filename[MAX_PATH];
542 psf_parent = NULL;
543
544 COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
545
546 if( (This->options & FOS_NOVALIDATE) &&
547 !(This->options & FOS_FILEMUSTEXIST) )
548 open_action = ONOPEN_OPEN;
549 else
550 open_action = ONOPEN_BROWSE;
551
552 open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
553 This->options & ~FOS_FILEMUSTEXIST,
554 (This->dlg_type == ITEMDLG_TYPE_SAVE),
555 open_action);
556
557 /* Add the proper extension */
558 if(open_action == ONOPEN_OPEN)
559 {
560 static const WCHAR dotW[] = {'.',0};
561
562 if(This->dlg_type == ITEMDLG_TYPE_SAVE)
563 {
564 WCHAR extbuf[MAX_PATH], *newext = NULL;
565
566 if(This->filterspec_count)
567 {
568 newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
569 }
570 else if(This->default_ext)
571 {
572 lstrcpyW(extbuf, dotW);
573 lstrcatW(extbuf, This->default_ext);
574 newext = extbuf;
575 }
576
577 if(newext)
578 {
579 WCHAR *ext = PathFindExtensionW(canon_filename);
580 if(lstrcmpW(ext, newext))
581 lstrcatW(canon_filename, newext);
582 }
583 }
584 else
585 {
586 if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
587 !PathFileExistsW(canon_filename))
588 {
589 if(This->default_ext)
590 {
591 lstrcatW(canon_filename, dotW);
592 lstrcatW(canon_filename, This->default_ext);
593
594 if(!PathFileExistsW(canon_filename))
595 {
596 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
597 open_action = ONOPEN_BROWSE;
598 }
599 }
600 else
601 {
602 FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
603 open_action = ONOPEN_BROWSE;
604 }
605 }
606 }
607 }
608
609 pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
610
611 if(psf_parent && !(open_action == ONOPEN_BROWSE))
612 IShellFolder_Release(psf_parent);
613
614 fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
615 }
616
617 HeapFree(GetProcessHeap(), 0, files);
618 ILFree(current_folder);
619
620 if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
621 open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
622
623 switch(open_action)
624 {
625 case ONOPEN_SEARCH:
626 FIXME("Filtering not implemented.\n");
627 break;
628
629 case ONOPEN_BROWSE:
630 hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
631 if(FAILED(hr))
632 ERR("Failed to browse to directory: %08x\n", hr);
633
634 IShellFolder_Release(psf_parent);
635 break;
636
637 case ONOPEN_OPEN:
638 hr = SHGetDesktopFolder(&psf_desktop);
639 if(SUCCEEDED(hr))
640 {
641 if(This->psia_results)
642 {
643 IShellItemArray_Release(This->psia_results);
644 This->psia_results = NULL;
645 }
646
647 hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
648 &This->psia_results);
649
650 IShellFolder_Release(psf_desktop);
651
652 if(FAILED(hr))
653 break;
654
655 if(This->options & FOS_PICKFOLDERS)
656 {
657 SFGAOF attributes;
658 hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
659 if(hr != S_OK)
660 {
661 WCHAR buf[64];
662 LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, sizeof(buf)/sizeof(WCHAR));
663
664 MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
665
666 IShellItemArray_Release(This->psia_results);
667 This->psia_results = NULL;
668 break;
669 }
670 }
671
672 if((This->options & FOS_OVERWRITEPROMPT) && This->dlg_type == ITEMDLG_TYPE_SAVE)
673 {
674 IShellItem *shellitem;
675
676 for (i=0; SUCCEEDED(hr) && i<file_count; i++)
677 {
678 hr = IShellItemArray_GetItemAt(This->psia_results, i, &shellitem);
679 if (SUCCEEDED(hr))
680 {
681 if (shell_item_exists(shellitem))
682 hr = events_OnOverwrite(This, shellitem);
683
684 IShellItem_Release(shellitem);
685 }
686 }
687
688 if (FAILED(hr))
689 break;
690 }
691
692 if(events_OnFileOk(This) == S_OK)
693 ret = S_OK;
694 }
695 break;
696
697 default:
698 ERR("Failed.\n");
699 break;
700 }
701
702 /* Clean up */
703 for(i = 0; i < file_count; i++)
704 ILFree(pidla[i]);
705 HeapFree(GetProcessHeap(), 0, pidla);
706
707 /* Success closes the dialog */
708 return ret;
709 }
710
711 static void show_opendropdown(FileDialogImpl *This)
712 {
713 HWND open_hwnd;
714 RECT open_rc;
715 MSG msg;
716
717 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
718
719 GetWindowRect(open_hwnd, &open_rc);
720
721 if (TrackPopupMenu(This->hmenu_opendropdown, 0, open_rc.left, open_rc.bottom, 0, This->dlg_hwnd, NULL) &&
722 PeekMessageW(&msg, This->dlg_hwnd, WM_MENUCOMMAND, WM_MENUCOMMAND, PM_REMOVE))
723 {
724 MENUITEMINFOW mii;
725
726 This->opendropdown_has_selection = TRUE;
727
728 mii.cbSize = sizeof(mii);
729 mii.fMask = MIIM_ID;
730 GetMenuItemInfoW((HMENU)msg.lParam, msg.wParam, TRUE, &mii);
731 This->opendropdown_selection = mii.wID;
732
733 if(SUCCEEDED(on_default_action(This)))
734 EndDialog(This->dlg_hwnd, S_OK);
735 else
736 This->opendropdown_has_selection = FALSE;
737 }
738 }
739
740 /**************************************************************************
741 * Control item functions.
742 */
743
744 static void item_free(cctrl_item *item)
745 {
746 DestroyWindow(item->hwnd);
747 HeapFree(GetProcessHeap(), 0, item->label);
748 HeapFree(GetProcessHeap(), 0, item);
749 }
750
751 static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF visible_flags, DWORD* position)
752 {
753 DWORD dummy;
754 cctrl_item* item;
755
756 if (!position) position = &dummy;
757
758 *position = 0;
759
760 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
761 {
762 if (item->id == itemid)
763 return item;
764
765 if ((item->cdcstate & visible_flags) == visible_flags)
766 (*position)++;
767 }
768
769 return NULL;
770 }
771
772 static cctrl_item* get_first_item(customctrl* parent)
773 {
774 cctrl_item* item;
775
776 LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
777 {
778 if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
779 return item;
780 }
781
782 return NULL;
783 }
784
785 static HRESULT add_item(customctrl* parent, DWORD itemid, LPCWSTR label, cctrl_item** result)
786 {
787 cctrl_item* item;
788 LPWSTR label_copy;
789
790 if (get_item(parent, itemid, 0, NULL))
791 return E_INVALIDARG;
792
793 item = HeapAlloc(GetProcessHeap(), 0, sizeof(*item));
794 label_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(label)+1)*sizeof(WCHAR));
795
796 if (!item || !label_copy)
797 {
798 HeapFree(GetProcessHeap(), 0, item);
799 HeapFree(GetProcessHeap(), 0, label_copy);
800 return E_OUTOFMEMORY;
801 }
802
803 item->id = itemid;
804 item->parent_id = parent->id;
805 lstrcpyW(label_copy, label);
806 item->label = label_copy;
807 item->cdcstate = CDCS_VISIBLE|CDCS_ENABLED;
808 item->hwnd = NULL;
809 list_add_tail(&parent->sub_items, &item->entry);
810
811 *result = item;
812
813 return S_OK;
814 }
815
816 /**************************************************************************
817 * Control functions.
818 */
819 static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
820 {
821 customctrl *ctrl, *sub_ctrl;
822
823 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
824 {
825 if(ctrl->dlgid == dlgid)
826 return ctrl;
827
828 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
829 if(sub_ctrl->dlgid == dlgid)
830 return sub_ctrl;
831 }
832
833 ERR("Failed to find control with dialog id %d\n", dlgid);
834 return NULL;
835 }
836
837 static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
838 {
839 customctrl *ctrl, *sub_ctrl;
840
841 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
842 {
843 if(ctrl->id == ctlid)
844 return ctrl;
845
846 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
847 if(sub_ctrl->id == ctlid)
848 return sub_ctrl;
849 }
850
851 if (This->hmenu_opendropdown && This->cctrl_opendropdown.id == ctlid)
852 return &This->cctrl_opendropdown;
853
854 TRACE("No existing control with control id %d\n", ctlid);
855 return NULL;
856 }
857
858 static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
859 {
860 LPWSTR text;
861 UINT len, final_width;
862 UINT lines, final_height;
863 SIZE size;
864 RECT rc;
865 HDC hdc;
866 WCHAR *c;
867
868 TRACE("\n");
869
870 len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
871 text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
872 if(!text) return;
873 SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
874
875 hdc = GetDC(hctrl);
876 GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
877 ReleaseDC(hctrl, hdc);
878
879 if(len && multiline)
880 {
881 /* FIXME: line-wrap */
882 for(lines = 1, c = text; *c != '\0'; c++)
883 if(*c == '\n') lines++;
884
885 final_height = size.cy*lines + 2*4;
886 }
887 else
888 {
889 GetWindowRect(hctrl, &rc);
890 final_height = rc.bottom - rc.top;
891 }
892
893 final_width = min(max(size.cx, min_width) + 4, max_width);
894 SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
895 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
896
897 HeapFree(GetProcessHeap(), 0, text);
898 }
899
900 static UINT ctrl_get_height(customctrl *ctrl) {
901 RECT rc;
902 GetWindowRect(ctrl->wrapper_hwnd, &rc);
903 return rc.bottom - rc.top;
904 }
905
906 static void ctrl_free(customctrl *ctrl)
907 {
908 customctrl *sub_cur1, *sub_cur2;
909 cctrl_item *item_cur1, *item_cur2;
910
911 TRACE("Freeing control %p\n", ctrl);
912 if(ctrl->type == IDLG_CCTRL_MENU)
913 {
914 TBBUTTON tbb;
915 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
916 DestroyMenu((HMENU)tbb.dwData);
917 }
918
919 LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
920 {
921 list_remove(&sub_cur1->sub_cctrls_entry);
922 ctrl_free(sub_cur1);
923 }
924
925 LIST_FOR_EACH_ENTRY_SAFE(item_cur1, item_cur2, &ctrl->sub_items, cctrl_item, entry)
926 {
927 list_remove(&item_cur1->entry);
928 item_free(item_cur1);
929 }
930
931 DestroyWindow(ctrl->hwnd);
932 HeapFree(GetProcessHeap(), 0, ctrl);
933 }
934
935 static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
936 {
937 RECT rc;
938 UINT total_height;
939 UINT max_width;
940 customctrl *sub_ctrl;
941
942 switch(ctrl->type)
943 {
944 case IDLG_CCTRL_PUSHBUTTON:
945 case IDLG_CCTRL_COMBOBOX:
946 case IDLG_CCTRL_CHECKBUTTON:
947 case IDLG_CCTRL_TEXT:
948 ctrl_resize(ctrl->hwnd, 160, 160, TRUE);
949 GetWindowRect(ctrl->hwnd, &rc);
950 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
951 SWP_NOZORDER|SWP_NOMOVE);
952 break;
953 case IDLG_CCTRL_VISUALGROUP:
954 total_height = 0;
955 ctrl_resize(ctrl->hwnd, 0, This->cctrl_indent, TRUE);
956
957 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
958 {
959 customctrl_resize(This, sub_ctrl);
960 SetWindowPos(sub_ctrl->wrapper_hwnd, NULL, This->cctrl_indent, total_height, 0, 0,
961 SWP_NOZORDER|SWP_NOSIZE);
962
963 total_height += ctrl_get_height(sub_ctrl);
964 }
965
966 /* The label should be right adjusted */
967 {
968 UINT width, height;
969
970 GetWindowRect(ctrl->hwnd, &rc);
971 width = rc.right - rc.left;
972 height = rc.bottom - rc.top;
973
974 SetWindowPos(ctrl->hwnd, NULL, This->cctrl_indent - width, 0, width, height, SWP_NOZORDER);
975 }
976
977 /* Resize the wrapper window to fit all the sub controls */
978 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, This->cctrl_width + This->cctrl_indent, total_height,
979 SWP_NOZORDER|SWP_NOMOVE);
980 break;
981 case IDLG_CCTRL_RADIOBUTTONLIST:
982 {
983 cctrl_item* item;
984
985 total_height = 0;
986 max_width = 0;
987
988 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
989 {
990 ctrl_resize(item->hwnd, 160, 160, TRUE);
991 SetWindowPos(item->hwnd, NULL, 0, total_height, 0, 0,
992 SWP_NOZORDER|SWP_NOSIZE);
993
994 GetWindowRect(item->hwnd, &rc);
995
996 total_height += rc.bottom - rc.top;
997 max_width = max(rc.right - rc.left, max_width);
998 }
999
1000 SetWindowPos(ctrl->hwnd, NULL, 0, 0, max_width, total_height,
1001 SWP_NOZORDER|SWP_NOMOVE);
1002
1003 SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, max_width, total_height,
1004 SWP_NOZORDER|SWP_NOMOVE);
1005
1006 break;
1007 }
1008 case IDLG_CCTRL_EDITBOX:
1009 case IDLG_CCTRL_SEPARATOR:
1010 case IDLG_CCTRL_MENU:
1011 case IDLG_CCTRL_OPENDROPDOWN:
1012 /* Nothing */
1013 break;
1014 }
1015 }
1016
1017 static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
1018 {
1019 FileDialogImpl *This = crs->lpCreateParams;
1020 TRACE("%p\n", This);
1021
1022 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1023 return TRUE;
1024 }
1025
1026 static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1027 {
1028 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1029
1030 TRACE("%p, %lx\n", This, wparam);
1031
1032 if(ctrl)
1033 {
1034 if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
1035 {
1036 BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
1037 cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
1038 }
1039 else
1040 cctrl_event_OnButtonClicked(This, ctrl->id);
1041 }
1042
1043 return TRUE;
1044 }
1045
1046 static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
1047 {
1048 customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
1049 TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
1050
1051 if(ctrl)
1052 {
1053 UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
1054 UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
1055
1056 cctrl_event_OnItemSelected(This, ctrl->id, selid);
1057 }
1058 return TRUE;
1059 }
1060
1061 static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
1062 {
1063 NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
1064 customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
1065 POINT pt = { 0, nmtb->rcButton.bottom };
1066 TBBUTTON tbb;
1067 UINT idcmd;
1068
1069 TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
1070
1071 if(ctrl)
1072 {
1073 cctrl_event_OnControlActivating(This,ctrl->id);
1074
1075 SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
1076 ClientToScreen(ctrl->hwnd, &pt);
1077 idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
1078 if(idcmd)
1079 cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
1080 }
1081
1082 return TBDDRET_DEFAULT;
1083 }
1084
1085 static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1086 {
1087 switch(HIWORD(wparam))
1088 {
1089 case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
1090 case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
1091 }
1092
1093 return FALSE;
1094 }
1095
1096 static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1097 {
1098 NMHDR *nmhdr = (NMHDR*)lparam;
1099
1100 switch(nmhdr->code)
1101 {
1102 case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
1103 }
1104
1105 return FALSE;
1106 }
1107
1108 static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1109 {
1110 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1111 customctrl *ctrl;
1112 HWND hwnd_child;
1113 RECT rc;
1114
1115 switch(message)
1116 {
1117 case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
1118 case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
1119 case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
1120 case WM_SIZE:
1121 hwnd_child = GetPropW(hwnd, notifysink_childW);
1122 ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA);
1123 if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
1124 {
1125 GetClientRect(hwnd, &rc);
1126 SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
1127 }
1128 return TRUE;
1129 }
1130
1131 return DefWindowProcW(hwnd, message, wparam, lparam);
1132 }
1133
1134 static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
1135 LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
1136 DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
1137 {
1138 HWND ns_hwnd, control_hwnd, parent_hwnd;
1139 DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
1140 customctrl *ctrl;
1141
1142 if(get_cctrl(This, id))
1143 return E_UNEXPECTED; /* Duplicate id */
1144
1145 if(This->cctrl_active_vg)
1146 parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
1147 else
1148 parent_hwnd = This->cctrls_hwnd;
1149
1150 ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
1151 0, 0, This->cctrl_width, height, parent_hwnd,
1152 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
1153 control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
1154 0, 0, This->cctrl_width, height, ns_hwnd,
1155 (HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
1156
1157 if(!ns_hwnd || !control_hwnd)
1158 {
1159 ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
1160 DestroyWindow(ns_hwnd);
1161 DestroyWindow(control_hwnd);
1162
1163 return E_FAIL;
1164 }
1165
1166 SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
1167
1168 ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
1169 if(!ctrl)
1170 return E_OUTOFMEMORY;
1171
1172 ctrl->hwnd = control_hwnd;
1173 ctrl->wrapper_hwnd = ns_hwnd;
1174 ctrl->id = id;
1175 ctrl->dlgid = This->cctrl_next_dlgid;
1176 ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
1177 list_init(&ctrl->sub_cctrls);
1178 list_init(&ctrl->sub_items);
1179
1180 if(This->cctrl_active_vg)
1181 list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
1182 else
1183 list_add_tail(&This->cctrls, &ctrl->entry);
1184
1185 SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl);
1186
1187 if(ppctrl) *ppctrl = ctrl;
1188
1189 This->cctrl_next_dlgid++;
1190 return S_OK;
1191 }
1192
1193 /**************************************************************************
1194 * Container functions.
1195 */
1196 static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
1197 {
1198 UINT container_height;
1199 UINT column_width;
1200 UINT nr_of_cols;
1201 UINT max_control_height, total_height = 0;
1202 UINT cur_col_pos, cur_row_pos;
1203 customctrl *ctrl;
1204 BOOL fits_height;
1205 static const UINT cspacing = 90; /* Columns are spaced with 90px */
1206 static const UINT rspacing = 4; /* Rows are spaced with 4 px. */
1207
1208 /* Given the new width of the container, this function determines the
1209 * needed height of the container and places the controls according to
1210 * the new layout. Returns the new height.
1211 */
1212
1213 TRACE("%p\n", This);
1214
1215 column_width = This->cctrl_width + cspacing;
1216 nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
1217
1218 /* We don't need to do anything unless the number of visible columns has changed. */
1219 if(nr_of_cols == This->cctrls_cols)
1220 {
1221 RECT rc;
1222 GetWindowRect(This->cctrls_hwnd, &rc);
1223 return rc.bottom - rc.top;
1224 }
1225
1226 This->cctrls_cols = nr_of_cols;
1227
1228 /* Get the size of the tallest control, and the total size of
1229 * all the controls to figure out the number of slots we need.
1230 */
1231 max_control_height = 0;
1232 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1233 {
1234 if(ctrl->cdcstate & CDCS_VISIBLE)
1235 {
1236 UINT control_height = ctrl_get_height(ctrl);
1237 max_control_height = max(max_control_height, control_height);
1238
1239 total_height += control_height + rspacing;
1240 }
1241 }
1242
1243 if(!total_height)
1244 return 0;
1245
1246 container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
1247 TRACE("Guess: container_height: %d\n",container_height);
1248
1249 /* Incrementally increase container_height until all the controls
1250 * fit.
1251 */
1252 do {
1253 UINT columns_needed = 1;
1254 cur_row_pos = 0;
1255
1256 fits_height = TRUE;
1257 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1258 {
1259 if(ctrl->cdcstate & CDCS_VISIBLE)
1260 {
1261 UINT control_height = ctrl_get_height(ctrl);
1262
1263 if(cur_row_pos + control_height > container_height)
1264 {
1265 if(++columns_needed > nr_of_cols)
1266 {
1267 container_height += 1;
1268 fits_height = FALSE;
1269 break;
1270 }
1271 cur_row_pos = 0;
1272 }
1273
1274 cur_row_pos += control_height + rspacing;
1275 }
1276 }
1277 } while(!fits_height);
1278
1279 TRACE("Final container height: %d\n", container_height);
1280
1281 /* Move the controls to their final destination
1282 */
1283 cur_col_pos = 0, cur_row_pos = 0;
1284 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1285 {
1286 if(ctrl->cdcstate & CDCS_VISIBLE)
1287 {
1288 RECT rc;
1289 UINT control_height, control_indent;
1290 GetWindowRect(ctrl->wrapper_hwnd, &rc);
1291 control_height = rc.bottom - rc.top;
1292
1293 if(cur_row_pos + control_height > container_height)
1294 {
1295 cur_row_pos = 0;
1296 cur_col_pos += This->cctrl_width + cspacing;
1297 }
1298
1299
1300 if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
1301 control_indent = 0;
1302 else
1303 control_indent = This->cctrl_indent;
1304
1305 SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
1306 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1307
1308 cur_row_pos += control_height + rspacing;
1309 }
1310 }
1311
1312 /* Sanity check */
1313 if(cur_row_pos + This->cctrl_width > container_width)
1314 ERR("-- Failed to place controls properly.\n");
1315
1316 return container_height;
1317 }
1318
1319 static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
1320 {
1321 LONG wndstyle;
1322
1323 if(parent)
1324 {
1325 customctrl *ctrl, *sub_ctrl;
1326 HFONT font;
1327
1328 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1329 wndstyle &= ~(WS_POPUP);
1330 wndstyle |= WS_CHILD;
1331 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1332
1333 SetParent(This->cctrls_hwnd, parent);
1334 ShowWindow(This->cctrls_hwnd, TRUE);
1335
1336 /* Set the fonts to match the dialog font. */
1337 font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
1338 if(!font)
1339 ERR("Failed to get font handle from dialog.\n");
1340
1341 LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
1342 {
1343 if(font) SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1344
1345 /* If this is a VisualGroup */
1346 LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
1347 {
1348 if(font) SendMessageW(sub_ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1349 }
1350
1351 if (ctrl->type == IDLG_CCTRL_RADIOBUTTONLIST)
1352 {
1353 cctrl_item* item;
1354 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1355 {
1356 if (font) SendMessageW(item->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
1357 }
1358 }
1359
1360 customctrl_resize(This, ctrl);
1361 }
1362 }
1363 else
1364 {
1365 ShowWindow(This->cctrls_hwnd, FALSE);
1366
1367 wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
1368 wndstyle &= ~(WS_CHILD);
1369 wndstyle |= WS_POPUP;
1370 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
1371
1372 SetParent(This->cctrls_hwnd, NULL);
1373 }
1374 }
1375
1376 static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
1377 {
1378 FileDialogImpl *This = crs->lpCreateParams;
1379 TRACE("%p\n", This);
1380
1381 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1382 return TRUE;
1383 }
1384
1385 static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
1386 {
1387 customctrl *cur1, *cur2;
1388 TRACE("%p\n", This);
1389
1390 LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
1391 {
1392 list_remove(&cur1->entry);
1393 ctrl_free(cur1);
1394 }
1395
1396 return TRUE;
1397 }
1398
1399 static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1400 {
1401 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1402
1403 switch(umessage)
1404 {
1405 case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
1406 case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
1407 default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
1408 }
1409
1410 return FALSE;
1411 }
1412
1413 static void radiobuttonlist_set_selected_item(FileDialogImpl *This, customctrl *ctrl, cctrl_item *item)
1414 {
1415 cctrl_item *cursor;
1416
1417 LIST_FOR_EACH_ENTRY(cursor, &ctrl->sub_items, cctrl_item, entry)
1418 {
1419 SendMessageW(cursor->hwnd, BM_SETCHECK, (cursor == item) ? BST_CHECKED : BST_UNCHECKED, 0);
1420 }
1421 }
1422
1423 static LRESULT radiobuttonlist_on_bn_clicked(FileDialogImpl *This, HWND hwnd, HWND child)
1424 {
1425 DWORD ctrl_id = (DWORD)GetWindowLongPtrW(hwnd, GWLP_ID);
1426 customctrl *ctrl;
1427 cctrl_item *item;
1428 BOOL found_item=FALSE;
1429
1430 ctrl = get_cctrl_from_dlgid(This, ctrl_id);
1431
1432 if (!ctrl)
1433 {
1434 ERR("Can't find this control\n");
1435 return 0;
1436 }
1437
1438 LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
1439 {
1440 if (item->hwnd == child)
1441 {
1442 found_item = TRUE;
1443 break;
1444 }
1445 }
1446
1447 if (!found_item)
1448 {
1449 ERR("Can't find control item\n");
1450 return 0;
1451 }
1452
1453 radiobuttonlist_set_selected_item(This, ctrl, item);
1454
1455 cctrl_event_OnItemSelected(This, ctrl->id, item->id);
1456
1457 return 0;
1458 }
1459
1460 static LRESULT radiobuttonlist_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
1461 {
1462 switch(HIWORD(wparam))
1463 {
1464 case BN_CLICKED: return radiobuttonlist_on_bn_clicked(This, hwnd, (HWND)lparam);
1465 }
1466
1467 return FALSE;
1468 }
1469
1470 static LRESULT CALLBACK radiobuttonlist_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1471 {
1472 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1473
1474 switch(message)
1475 {
1476 case WM_COMMAND: return radiobuttonlist_on_wm_command(This, hwnd, wparam, lparam);
1477 }
1478
1479 return DefWindowProcW(hwnd, message, wparam, lparam);
1480 }
1481
1482 static HRESULT init_custom_controls(FileDialogImpl *This)
1483 {
1484 WNDCLASSW wc;
1485 static const WCHAR ctrl_container_classname[] =
1486 {'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
1487
1488 InitCommonControlsEx(NULL);
1489
1490 This->cctrl_width = 160; /* Controls have a fixed width */
1491 This->cctrl_indent = 100;
1492 This->cctrl_def_height = 23;
1493 This->cctrls_cols = 0;
1494
1495 This->cctrl_next_dlgid = 0x2000;
1496 list_init(&This->cctrls);
1497 This->cctrl_active_vg = NULL;
1498
1499 if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
1500 {
1501 wc.style = CS_HREDRAW | CS_VREDRAW;
1502 wc.lpfnWndProc = ctrl_container_wndproc;
1503 wc.cbClsExtra = 0;
1504 wc.cbWndExtra = 0;
1505 wc.hInstance = COMDLG32_hInstance;
1506 wc.hIcon = 0;
1507 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1508 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1509 wc.lpszMenuName = NULL;
1510 wc.lpszClassName = ctrl_container_classname;
1511
1512 if(!RegisterClassW(&wc)) return E_FAIL;
1513 }
1514
1515 This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
1516 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
1517 0, 0, 0, 0, NULL, 0,
1518 COMDLG32_hInstance, This);
1519 if(!This->cctrls_hwnd)
1520 return E_FAIL;
1521
1522 SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
1523
1524 /* Register class for */
1525 if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
1526 wc.hInstance != COMDLG32_hInstance)
1527 {
1528 wc.style = CS_HREDRAW | CS_VREDRAW;
1529 wc.lpfnWndProc = notifysink_proc;
1530 wc.cbClsExtra = 0;
1531 wc.cbWndExtra = 0;
1532 wc.hInstance = COMDLG32_hInstance;
1533 wc.hIcon = 0;
1534 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1535 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1536 wc.lpszMenuName = NULL;
1537 wc.lpszClassName = floatnotifysinkW;
1538
1539 if (!RegisterClassW(&wc))
1540 ERR("Failed to register FloatNotifySink window class.\n");
1541 }
1542
1543 if( !GetClassInfoW(COMDLG32_hInstance, radiobuttonlistW, &wc) ||
1544 wc.hInstance != COMDLG32_hInstance)
1545 {
1546 wc.style = CS_HREDRAW | CS_VREDRAW;
1547 wc.lpfnWndProc = radiobuttonlist_proc;
1548 wc.cbClsExtra = 0;
1549 wc.cbWndExtra = 0;
1550 wc.hInstance = COMDLG32_hInstance;
1551 wc.hIcon = 0;
1552 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
1553 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1554 wc.lpszMenuName = NULL;
1555 wc.lpszClassName = radiobuttonlistW;
1556
1557 if (!RegisterClassW(&wc))
1558 ERR("Failed to register RadioButtonList window class.\n");
1559 }
1560
1561 return S_OK;
1562 }
1563
1564 /**************************************************************************
1565 * Window related functions.
1566 */
1567 static BOOL update_open_dropdown(FileDialogImpl *This)
1568 {
1569 /* Show or hide the open dropdown button as appropriate */
1570 BOOL show=FALSE, showing;
1571 HWND open_hwnd, dropdown_hwnd;
1572
1573 if (This->hmenu_opendropdown)
1574 {
1575 INT num_visible_items=0;
1576 cctrl_item* item;
1577
1578 LIST_FOR_EACH_ENTRY(item, &This->cctrl_opendropdown.sub_items, cctrl_item, entry)
1579 {
1580 if (item->cdcstate & CDCS_VISIBLE)
1581 {
1582 num_visible_items++;
1583 if (num_visible_items >= 2)
1584 {
1585 show = TRUE;
1586 break;
1587 }
1588 }
1589 }
1590 }
1591
1592 open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1593 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1594
1595 showing = (GetWindowLongPtrW(dropdown_hwnd, GWL_STYLE) & WS_VISIBLE) != 0;
1596
1597 if (showing != show)
1598 {
1599 RECT open_rc, dropdown_rc;
1600
1601 GetWindowRect(open_hwnd, &open_rc);
1602 GetWindowRect(dropdown_hwnd, &dropdown_rc);
1603
1604 if (show)
1605 {
1606 ShowWindow(dropdown_hwnd, SW_SHOW);
1607
1608 SetWindowPos(open_hwnd, NULL, 0, 0,
1609 (open_rc.right - open_rc.left) - (dropdown_rc.right - dropdown_rc.left),
1610 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1611 }
1612 else
1613 {
1614 ShowWindow(dropdown_hwnd, SW_HIDE);
1615
1616 SetWindowPos(open_hwnd, NULL, 0, 0,
1617 (open_rc.right - open_rc.left) + (dropdown_rc.right - dropdown_rc.left),
1618 open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1619 }
1620 }
1621
1622 return show;
1623 }
1624
1625 static void update_layout(FileDialogImpl *This)
1626 {
1627 HDWP hdwp;
1628 HWND hwnd;
1629 RECT dialog_rc;
1630 RECT cancel_rc, dropdown_rc, open_rc;
1631 RECT filetype_rc, filename_rc, filenamelabel_rc;
1632 RECT toolbar_rc, ebrowser_rc, customctrls_rc;
1633 static const UINT vspacing = 4, hspacing = 4;
1634 static const UINT min_width = 320, min_height = 200;
1635 BOOL show_dropdown;
1636
1637 if (!GetClientRect(This->dlg_hwnd, &dialog_rc))
1638 {
1639 TRACE("Invalid dialog window, not updating layout\n");
1640 return;
1641 }
1642
1643 if(dialog_rc.right < min_width || dialog_rc.bottom < min_height)
1644 {
1645 TRACE("Dialog size (%d, %d) too small, not updating layout\n", dialog_rc.right, dialog_rc.bottom);
1646 return;
1647 }
1648
1649 /****
1650 * Calculate the size of the dialog and all the parts.
1651 */
1652
1653 /* Cancel button */
1654 hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
1655 if(hwnd)
1656 {
1657 int cancel_width, cancel_height;
1658 GetWindowRect(hwnd, &cancel_rc);
1659 cancel_width = cancel_rc.right - cancel_rc.left;
1660 cancel_height = cancel_rc.bottom - cancel_rc.top;
1661
1662 cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
1663 cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
1664 cancel_rc.right = cancel_rc.left + cancel_width;
1665 cancel_rc.bottom = cancel_rc.top + cancel_height;
1666 }
1667
1668 /* Open/Save dropdown */
1669 show_dropdown = update_open_dropdown(This);
1670
1671 if(show_dropdown)
1672 {
1673 int dropdown_width, dropdown_height;
1674 hwnd = GetDlgItem(This->dlg_hwnd, psh1);
1675
1676 GetWindowRect(hwnd, &dropdown_rc);
1677 dropdown_width = dropdown_rc.right - dropdown_rc.left;
1678 dropdown_height = dropdown_rc.bottom - dropdown_rc.top;
1679
1680 dropdown_rc.left = cancel_rc.left - dropdown_width - hspacing;
1681 dropdown_rc.top = cancel_rc.top;
1682 dropdown_rc.right = dropdown_rc.left + dropdown_width;
1683 dropdown_rc.bottom = dropdown_rc.top + dropdown_height;
1684 }
1685 else
1686 {
1687 dropdown_rc.left = dropdown_rc.right = cancel_rc.left - hspacing;
1688 dropdown_rc.top = cancel_rc.top;
1689 dropdown_rc.bottom = cancel_rc.bottom;
1690 }
1691
1692 /* Open/Save button */
1693 hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
1694 if(hwnd)
1695 {
1696 int open_width, open_height;
1697 GetWindowRect(hwnd, &open_rc);
1698 open_width = open_rc.right - open_rc.left;
1699 open_height = open_rc.bottom - open_rc.top;
1700
1701 open_rc.left = dropdown_rc.left - open_width;
1702 open_rc.top = dropdown_rc.top;
1703 open_rc.right = open_rc.left + open_width;
1704 open_rc.bottom = open_rc.top + open_height;
1705 }
1706
1707 /* The filetype combobox. */
1708 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1709 if(hwnd)
1710 {
1711 int filetype_width, filetype_height;
1712 GetWindowRect(hwnd, &filetype_rc);
1713
1714 filetype_width = filetype_rc.right - filetype_rc.left;
1715 filetype_height = filetype_rc.bottom - filetype_rc.top;
1716
1717 filetype_rc.right = cancel_rc.right;
1718
1719 filetype_rc.left = filetype_rc.right - filetype_width;
1720 filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
1721 filetype_rc.bottom = filetype_rc.top + filetype_height;
1722
1723 if(!This->filterspec_count)
1724 filetype_rc.left = filetype_rc.right;
1725 }
1726
1727 /* Filename label. */
1728 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
1729 if(hwnd)
1730 {
1731 int filetypelabel_width, filetypelabel_height;
1732 GetWindowRect(hwnd, &filenamelabel_rc);
1733
1734 filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
1735 filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
1736
1737 filenamelabel_rc.left = 160; /* FIXME */
1738 filenamelabel_rc.top = filetype_rc.top;
1739 filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
1740 filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
1741 }
1742
1743 /* Filename edit box. */
1744 hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
1745 if(hwnd)
1746 {
1747 int filename_width, filename_height;
1748 GetWindowRect(hwnd, &filename_rc);
1749
1750 filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
1751 filename_height = filename_rc.bottom - filename_rc.top;
1752
1753 filename_rc.left = filenamelabel_rc.right + hspacing;
1754 filename_rc.top = filetype_rc.top;
1755 filename_rc.right = filename_rc.left + filename_width;
1756 filename_rc.bottom = filename_rc.top + filename_height;
1757 }
1758
1759 hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
1760 if(hwnd)
1761 {
1762 GetWindowRect(hwnd, &toolbar_rc);
1763 MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
1764 }
1765
1766 /* The custom controls */
1767 customctrls_rc.left = dialog_rc.left + hspacing;
1768 customctrls_rc.right = dialog_rc.right - hspacing;
1769 customctrls_rc.bottom = filename_rc.top - vspacing;
1770 customctrls_rc.top = customctrls_rc.bottom -
1771 ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
1772
1773 /* The ExplorerBrowser control. */
1774 ebrowser_rc.left = dialog_rc.left + hspacing;
1775 ebrowser_rc.top = toolbar_rc.bottom + vspacing;
1776 ebrowser_rc.right = dialog_rc.right - hspacing;
1777 ebrowser_rc.bottom = customctrls_rc.top - vspacing;
1778
1779 /****
1780 * Move everything to the right place.
1781 */
1782
1783 /* FIXME: The Save Dialog uses a slightly different layout. */
1784 hdwp = BeginDeferWindowPos(7);
1785
1786 if(hdwp && This->peb)
1787 IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
1788
1789 if(hdwp && This->cctrls_hwnd)
1790 DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
1791 customctrls_rc.left, customctrls_rc.top,
1792 customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
1793 SWP_NOZORDER | SWP_NOACTIVATE);
1794
1795 /* The default controls */
1796 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
1797 DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
1798 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1799
1800 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
1801 DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
1802 filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
1803 SWP_NOZORDER | SWP_NOACTIVATE);
1804
1805 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
1806 DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
1807 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1808
1809 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
1810 DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
1811 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1812
1813 if(hdwp && This->hmenu_opendropdown && (hwnd = GetDlgItem(This->dlg_hwnd, psh1)))
1814 DeferWindowPos(hdwp, hwnd, NULL, dropdown_rc.left, dropdown_rc.top, 0, 0,
1815 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1816
1817 if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
1818 DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
1819 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1820
1821 if(hdwp)
1822 EndDeferWindowPos(hdwp);
1823 else
1824 ERR("Failed to position dialog controls.\n");
1825
1826 return;
1827 }
1828
1829 static HRESULT init_explorerbrowser(FileDialogImpl *This)
1830 {
1831 IShellItem *psi_folder;
1832 IObjectWithSite *client;
1833 FOLDERSETTINGS fos;
1834 RECT rc = {0};
1835 HRESULT hr;
1836
1837 /* Create ExplorerBrowser instance */
1838 OleInitialize(NULL);
1839
1840 hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
1841 &IID_IExplorerBrowser, (void**)&This->peb);
1842 if(FAILED(hr))
1843 {
1844 ERR("Failed to instantiate ExplorerBrowser control.\n");
1845 return hr;
1846 }
1847
1848 IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES | EBO_NOBORDER);
1849
1850 hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
1851 if(FAILED(hr))
1852 {
1853 ERR("Failed to initialize the ExplorerBrowser control.\n");
1854 IExplorerBrowser_Release(This->peb);
1855 This->peb = NULL;
1856 return hr;
1857 }
1858 hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
1859 if(FAILED(hr))
1860 ERR("Advise (ExplorerBrowser) failed.\n");
1861
1862 /* Get previous options? */
1863 fos.ViewMode = fos.fFlags = 0;
1864 if(!(This->options & FOS_ALLOWMULTISELECT))
1865 fos.fFlags |= FWF_SINGLESEL;
1866
1867 IExplorerBrowser_SetFolderSettings(This->peb, &fos);
1868
1869 hr = IExplorerBrowser_QueryInterface(This->peb, &IID_IObjectWithSite, (void**)&client);
1870 if (hr == S_OK)
1871 {
1872 hr = IObjectWithSite_SetSite(client, (IUnknown*)&This->IFileDialog2_iface);
1873 IObjectWithSite_Release(client);
1874 if(FAILED(hr))
1875 ERR("SetSite failed, 0x%08x\n", hr);
1876 }
1877
1878 /* Browse somewhere */
1879 psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
1880 IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
1881
1882 return S_OK;
1883 }
1884
1885 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
1886 {
1887 HWND htoolbar;
1888 TBADDBITMAP tbab;
1889 TBBUTTON button[2];
1890
1891 htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
1892 0, 0, 0, 0,
1893 hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
1894
1895 tbab.hInst = HINST_COMMCTRL;
1896 tbab.nID = IDB_HIST_LARGE_COLOR;
1897 SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
1898
1899 button[0].iBitmap = HIST_BACK;
1900 button[0].idCommand = IDC_NAVBACK;
1901 button[0].fsState = TBSTATE_ENABLED;
1902 button[0].fsStyle = BTNS_BUTTON;
1903 button[0].dwData = 0;
1904 button[0].iString = 0;
1905
1906 button[1].iBitmap = HIST_FORWARD;
1907 button[1].idCommand = IDC_NAVFORWARD;
1908 button[1].fsState = TBSTATE_ENABLED;
1909 button[1].fsStyle = BTNS_BUTTON;
1910 button[1].dwData = 0;
1911 button[1].iString = 0;
1912
1913 SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
1914 SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
1915 SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
1916 }
1917
1918 static void update_control_text(FileDialogImpl *This)
1919 {
1920 HWND hitem;
1921 LPCWSTR custom_okbutton;
1922 cctrl_item* item;
1923
1924 if(This->custom_title)
1925 SetWindowTextW(This->dlg_hwnd, This->custom_title);
1926
1927 if(This->hmenu_opendropdown && (item = get_first_item(&This->cctrl_opendropdown)))
1928 custom_okbutton = item->label;
1929 else
1930 custom_okbutton = This->custom_okbutton;
1931
1932 if(custom_okbutton &&
1933 (hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
1934 {
1935 SetWindowTextW(hitem, custom_okbutton);
1936 ctrl_resize(hitem, 50, 250, FALSE);
1937 }
1938
1939 if(This->custom_cancelbutton &&
1940 (hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
1941 {
1942 SetWindowTextW(hitem, This->custom_cancelbutton);
1943 ctrl_resize(hitem, 50, 250, FALSE);
1944 }
1945
1946 if(This->custom_filenamelabel &&
1947 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
1948 {
1949 SetWindowTextW(hitem, This->custom_filenamelabel);
1950 ctrl_resize(hitem, 50, 250, FALSE);
1951 }
1952 }
1953
1954 static LRESULT CALLBACK dropdown_subclass_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
1955 {
1956 static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
1957 static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
1958
1959 if (umessage == WM_LBUTTONDOWN)
1960 {
1961 FileDialogImpl *This = GetPropW(hwnd, prop_this);
1962
1963 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
1964 show_opendropdown(This);
1965 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
1966
1967 return 0;
1968 }
1969
1970 return CallWindowProcW((WNDPROC)GetPropW(hwnd, prop_oldwndproc), hwnd, umessage, wparam, lparam);
1971 }
1972
1973 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
1974 {
1975 FileDialogImpl *This = (FileDialogImpl*)lParam;
1976 HWND hitem;
1977
1978 TRACE("(%p, %p)\n", This, hwnd);
1979
1980 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
1981 This->dlg_hwnd = hwnd;
1982
1983 hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
1984 if(hitem) ShowWindow(hitem, SW_HIDE);
1985
1986 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
1987 if(hitem) ShowWindow(hitem, SW_HIDE);
1988
1989 /* Fill filetypes combobox, or hide it. */
1990 hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
1991 if(This->filterspec_count)
1992 {
1993 HDC hdc;
1994 HFONT font;
1995 SIZE size;
1996 UINT i, maxwidth = 0;
1997
1998 hdc = GetDC(hitem);
1999 font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
2000 SelectObject(hdc, font);
2001
2002 for(i = 0; i < This->filterspec_count; i++)
2003 {
2004 SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
2005
2006 if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
2007 maxwidth = max(maxwidth, size.cx);
2008 }
2009 ReleaseDC(hitem, hdc);
2010
2011 if(maxwidth > 0)
2012 {
2013 maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
2014 SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
2015 }
2016 else
2017 ERR("Failed to calculate width of filetype dropdown\n");
2018
2019 SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
2020 }
2021 else
2022 ShowWindow(hitem, SW_HIDE);
2023
2024 if(This->set_filename &&
2025 (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
2026 SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
2027
2028 if(This->hmenu_opendropdown)
2029 {
2030 HWND dropdown_hwnd;
2031 LOGFONTW lfw, lfw_marlett;
2032 HFONT dialog_font;
2033 static const WCHAR marlett[] = {'M','a','r','l','e','t','t',0};
2034 static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
2035 static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
2036
2037 dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
2038
2039 /* Change dropdown button font to Marlett */
2040 dialog_font = (HFONT)SendMessageW(dropdown_hwnd, WM_GETFONT, 0, 0);
2041
2042 GetObjectW(dialog_font, sizeof(lfw), &lfw);
2043
2044 memset(&lfw_marlett, 0, sizeof(lfw_marlett));
2045 lstrcpyW(lfw_marlett.lfFaceName, marlett);
2046 lfw_marlett.lfHeight = lfw.lfHeight;
2047 lfw_marlett.lfCharSet = SYMBOL_CHARSET;
2048
2049 This->hfont_opendropdown = CreateFontIndirectW(&lfw_marlett);
2050
2051 SendMessageW(dropdown_hwnd, WM_SETFONT, (LPARAM)This->hfont_opendropdown, 0);
2052
2053 /* Subclass button so we can handle LBUTTONDOWN */
2054 SetPropW(dropdown_hwnd, prop_this, This);
2055 SetPropW(dropdown_hwnd, prop_oldwndproc,
2056 (HANDLE)SetWindowLongPtrW(dropdown_hwnd, GWLP_WNDPROC, (LONG_PTR)dropdown_subclass_proc));
2057 }
2058
2059 ctrl_container_reparent(This, This->dlg_hwnd);
2060 init_explorerbrowser(This);
2061 init_toolbar(This, hwnd);
2062 update_control_text(This);
2063 update_layout(This);
2064
2065 if(This->filterspec_count)
2066 events_OnTypeChange(This);
2067
2068 if ((hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)))
2069 SetFocus(hitem);
2070
2071 return FALSE;
2072 }
2073
2074 static LRESULT on_wm_size(FileDialogImpl *This)
2075 {
2076 update_layout(This);
2077 return FALSE;
2078 }
2079
2080 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
2081 {
2082 MINMAXINFO *mmi = (MINMAXINFO*)lparam;
2083 TRACE("%p (%p)\n", This, mmi);
2084
2085 /* FIXME */
2086 mmi->ptMinTrackSize.x = 640;
2087 mmi->ptMinTrackSize.y = 480;
2088
2089 return FALSE;
2090 }
2091
2092 static LRESULT on_wm_destroy(FileDialogImpl *This)
2093 {
2094 TRACE("%p\n", This);
2095
2096 if(This->peb)
2097 {
2098 IExplorerBrowser_Destroy(This->peb);
2099 IExplorerBrowser_Release(This->peb);
2100 This->peb = NULL;
2101 }
2102
2103 ctrl_container_reparent(This, NULL);
2104 This->dlg_hwnd = NULL;
2105
2106 DeleteObject(This->hfont_opendropdown);
2107 This->hfont_opendropdown = NULL;
2108
2109 return TRUE;
2110 }
2111
2112 static LRESULT on_idok(FileDialogImpl *This)
2113 {
2114 TRACE("%p\n", This);
2115
2116 if(SUCCEEDED(on_default_action(This)))
2117 EndDialog(This->dlg_hwnd, S_OK);
2118
2119 return FALSE;
2120 }
2121
2122 static LRESULT on_idcancel(FileDialogImpl *This)
2123 {
2124 TRACE("%p\n", This);
2125
2126 EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
2127
2128 return FALSE;
2129 }
2130
2131 static LRESULT on_command_opendropdown(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2132 {
2133 if(HIWORD(wparam) == BN_CLICKED)
2134 {
2135 HWND hwnd = (HWND)lparam;
2136 SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
2137 show_opendropdown(This);
2138 SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
2139 }
2140
2141 return FALSE;
2142 }
2143
2144 static LRESULT on_browse_back(FileDialogImpl *This)
2145 {
2146 TRACE("%p\n", This);
2147 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
2148 return FALSE;
2149 }
2150
2151 static LRESULT on_browse_forward(FileDialogImpl *This)
2152 {
2153 TRACE("%p\n", This);
2154 IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
2155 return FALSE;
2156 }
2157
2158 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2159 {
2160 if(HIWORD(wparam) == CBN_SELCHANGE)
2161 {
2162 IShellView *psv;
2163 HRESULT hr;
2164 LPWSTR filename;
2165 UINT prev_index = This->filetypeindex;
2166
2167 This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
2168 TRACE("File type selection changed to %d.\n", This->filetypeindex);
2169
2170 if(prev_index == This->filetypeindex)
2171 return FALSE;
2172
2173 hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
2174 if(SUCCEEDED(hr))
2175 {
2176 IShellView_Refresh(psv);
2177 IShellView_Release(psv);
2178 }
2179
2180 if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
2181 {
2182 WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
2183
2184 ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
2185 if(ext)
2186 {
2187 lstrcpyW(buf, filename);
2188
2189 if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
2190 PathRemoveExtensionW(buf);
2191
2192 lstrcatW(buf, ext);
2193 set_file_name(This, buf);
2194 }
2195 CoTaskMemFree(filename);
2196 }
2197
2198 /* The documentation claims that OnTypeChange is called only
2199 * when the dialog is opened, but this is obviously not the
2200 * case. */
2201 events_OnTypeChange(This);
2202 }
2203
2204 return FALSE;
2205 }
2206
2207 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
2208 {
2209 switch(LOWORD(wparam))
2210 {
2211 case IDOK: return on_idok(This);
2212 case IDCANCEL: return on_idcancel(This);
2213 case psh1: return on_command_opendropdown(This, wparam, lparam);
2214 case IDC_NAVBACK: return on_browse_back(This);
2215 case IDC_NAVFORWARD: return on_browse_forward(This);
2216 case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
2217 default: TRACE("Unknown command.\n");
2218 }
2219 return FALSE;
2220 }
2221
2222 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
2223 {
2224 FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
2225
2226 switch(umessage)
2227 {
2228 case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
2229 case WM_COMMAND: return on_wm_command(This, wparam, lparam);
2230 case WM_SIZE: return on_wm_size(This);
2231 case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
2232 case WM_DESTROY: return on_wm_destroy(This);
2233 }
2234
2235 return FALSE;
2236 }
2237
2238 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
2239 {
2240 INT_PTR res;
2241
2242 SetLastError(0);
2243 res = DialogBoxParamW(COMDLG32_hInstance,
2244 MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
2245 parent, itemdlg_dlgproc, (LPARAM)This);
2246 This->dlg_hwnd = NULL;
2247 if(res == -1)
2248 {
2249 ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
2250 return E_FAIL;
2251 }
2252
2253 TRACE("Returning 0x%08x\n", (HRESULT)res);
2254 return (HRESULT)res;
2255 }
2256
2257 /**************************************************************************
2258 * IFileDialog implementation
2259 */
2260 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
2261 {
2262 return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
2263 }
2264
2265 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
2266 REFIID riid,
2267 void **ppvObject)
2268 {
2269 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2270 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
2271
2272 *ppvObject = NULL;
2273 if(IsEqualGUID(riid, &IID_IUnknown) ||
2274 IsEqualGUID(riid, &IID_IFileDialog) ||
2275 IsEqualGUID(riid, &IID_IFileDialog2))
2276 {
2277 *ppvObject = iface;
2278 }
2279 else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
2280 {
2281 *ppvObject = &This->u.IFileOpenDialog_iface;
2282 }
2283 else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
2284 {
2285 *ppvObject = &This->u.IFileSaveDialog_iface;
2286 }
2287 else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
2288 {
2289 *ppvObject = &This->IExplorerBrowserEvents_iface;
2290 }
2291 else if(IsEqualGUID(riid, &IID_IServiceProvider))
2292 {
2293 *ppvObject = &This->IServiceProvider_iface;
2294 }
2295 else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
2296 IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
2297 IsEqualGUID(&IID_ICommDlgBrowser, riid))
2298 {
2299 *ppvObject = &This->ICommDlgBrowser3_iface;
2300 }
2301 else if(IsEqualGUID(&IID_IOleWindow, riid))
2302 {
2303 *ppvObject = &This->IOleWindow_iface;
2304 }
2305 else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
2306 IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
2307 {
2308 *ppvObject = &This->IFileDialogCustomize_iface;
2309 }
2310 else
2311 FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
2312
2313 if(*ppvObject)
2314 {
2315 IUnknown_AddRef((IUnknown*)*ppvObject);
2316 return S_OK;
2317 }
2318
2319 return E_NOINTERFACE;
2320 }
2321
2322 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
2323 {
2324 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2325 LONG ref = InterlockedIncrement(&This->ref);
2326 TRACE("%p - ref %d\n", This, ref);
2327
2328 return ref;
2329 }
2330
2331 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
2332 {
2333 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2334 LONG ref = InterlockedDecrement(&This->ref);
2335 TRACE("%p - ref %d\n", This, ref);
2336
2337 if(!ref)
2338 {
2339 UINT i;
2340 for(i = 0; i < This->filterspec_count; i++)
2341 {
2342 LocalFree((void*)This->filterspecs[i].pszName);
2343 LocalFree((void*)This->filterspecs[i].pszSpec);
2344 }
2345 HeapFree(GetProcessHeap(), 0, This->filterspecs);
2346
2347 DestroyWindow(This->cctrls_hwnd);
2348
2349 if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
2350 if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
2351 if(This->psi_folder) IShellItem_Release(This->psi_folder);
2352 if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
2353 if(This->psia_results) IShellItemArray_Release(This->psia_results);
2354
2355 LocalFree(This->set_filename);
2356 LocalFree(This->default_ext);
2357 LocalFree(This->custom_title);
2358 LocalFree(This->custom_okbutton);
2359 LocalFree(This->custom_cancelbutton);
2360 LocalFree(This->custom_filenamelabel);
2361
2362 DestroyMenu(This->hmenu_opendropdown);
2363 DeleteObject(This->hfont_opendropdown);
2364
2365 HeapFree(GetProcessHeap(), 0, This);
2366 }
2367
2368 return ref;
2369 }
2370
2371 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
2372 {
2373 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2374 TRACE("%p (%p)\n", iface, hwndOwner);
2375
2376 This->opendropdown_has_selection = FALSE;
2377
2378 return create_dialog(This, hwndOwner);
2379 }
2380
2381 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
2382 const COMDLG_FILTERSPEC *rgFilterSpec)
2383 {
2384 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2385 UINT i;
2386 TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
2387
2388 if(This->filterspecs)
2389 return E_UNEXPECTED;
2390
2391 if(!rgFilterSpec)
2392 return E_INVALIDARG;
2393
2394 if(!cFileTypes)
2395 return S_OK;
2396
2397 This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
2398 for(i = 0; i < cFileTypes; i++)
2399 {
2400 This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
2401 This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
2402 }
2403 This->filterspec_count = cFileTypes;
2404
2405 return S_OK;
2406 }
2407
2408 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
2409 {
2410 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2411 TRACE("%p (%d)\n", This, iFileType);
2412
2413 if(!This->filterspecs)
2414 return E_FAIL;
2415
2416 iFileType = max(iFileType, 1);
2417 iFileType = min(iFileType, This->filterspec_count);
2418 This->filetypeindex = iFileType-1;
2419
2420 return S_OK;
2421 }
2422
2423 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
2424 {
2425 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2426 TRACE("%p (%p)\n", This, piFileType);
2427
2428 if(!piFileType)
2429 return E_INVALIDARG;
2430
2431 if(This->filterspec_count == 0)
2432 *piFileType = 0;
2433 else
2434 *piFileType = This->filetypeindex + 1;
2435
2436 return S_OK;
2437 }
2438
2439 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
2440 {
2441 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2442 events_client *client;
2443 TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
2444
2445 if(!pfde || !pdwCookie)
2446 return E_INVALIDARG;
2447
2448 client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
2449 client->pfde = pfde;
2450 client->cookie = ++This->events_next_cookie;
2451
2452 IFileDialogEvents_AddRef(pfde);
2453 *pdwCookie = client->cookie;
2454
2455 list_add_tail(&This->events_clients, &client->entry);
2456
2457 return S_OK;
2458 }
2459
2460 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
2461 {
2462 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2463 events_client *client, *found = NULL;
2464 TRACE("%p (%d)\n", This, dwCookie);
2465
2466 LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
2467 {
2468 if(client->cookie == dwCookie)
2469 {
2470 found = client;
2471 break;
2472 }
2473 }
2474
2475 if(found)
2476 {
2477 list_remove(&found->entry);
2478 IFileDialogEvents_Release(found->pfde);
2479 HeapFree(GetProcessHeap(), 0, found);
2480 return S_OK;
2481 }
2482
2483 return E_INVALIDARG;
2484 }
2485
2486 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
2487 {
2488 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2489 TRACE("%p (0x%x)\n", This, fos);
2490
2491 if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
2492 {
2493 WCHAR buf[30];
2494 LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, sizeof(buf)/sizeof(WCHAR));
2495 IFileDialog2_SetTitle(iface, buf);
2496 }
2497
2498 This->options = fos;
2499
2500 return S_OK;
2501 }
2502
2503 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
2504 {
2505 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2506 TRACE("%p (%p)\n", This, pfos);
2507
2508 if(!pfos)
2509 return E_INVALIDARG;
2510
2511 *pfos = This->options;
2512
2513 return S_OK;
2514 }
2515
2516 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
2517 {
2518 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2519 TRACE("%p (%p)\n", This, psi);
2520 if(This->psi_defaultfolder)
2521 IShellItem_Release(This->psi_defaultfolder);
2522
2523 This->psi_defaultfolder = psi;
2524
2525 if(This->psi_defaultfolder)
2526 IShellItem_AddRef(This->psi_defaultfolder);
2527
2528 return S_OK;
2529 }
2530
2531 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
2532 {
2533 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2534 TRACE("%p (%p)\n", This, psi);
2535 if(This->psi_setfolder)
2536 IShellItem_Release(This->psi_setfolder);
2537
2538 This->psi_setfolder = psi;
2539
2540 if(This->psi_setfolder)
2541 IShellItem_AddRef(This->psi_setfolder);
2542
2543 return S_OK;
2544 }
2545
2546 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
2547 {
2548 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2549 TRACE("%p (%p)\n", This, ppsi);
2550 if(!ppsi)
2551 return E_INVALIDARG;
2552
2553 /* FIXME:
2554 If the dialog is shown, return the current(ly selected) folder. */
2555
2556 *ppsi = NULL;
2557 if(This->psi_folder)
2558 *ppsi = This->psi_folder;
2559 else if(This->psi_setfolder)
2560 *ppsi = This->psi_setfolder;
2561 else if(This->psi_defaultfolder)
2562 *ppsi = This->psi_defaultfolder;
2563
2564 if(*ppsi)
2565 {
2566 IShellItem_AddRef(*ppsi);
2567 return S_OK;
2568 }
2569
2570 return E_FAIL;
2571 }
2572
2573 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
2574 {
2575 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2576 HRESULT hr;
2577 TRACE("%p (%p)\n", This, ppsi);
2578
2579 if(!ppsi)
2580 return E_INVALIDARG;
2581
2582 if(This->psia_selection)
2583 {
2584 /* FIXME: Check filename edit box */
2585 hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
2586 return hr;
2587 }
2588
2589 return E_FAIL;
2590 }
2591
2592 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
2593 {
2594 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2595 TRACE("%p (%s)\n", iface, debugstr_w(pszName));
2596
2597 set_file_name(This, pszName);
2598
2599 return S_OK;
2600 }
2601
2602 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
2603 {
2604 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2605 TRACE("%p (%p)\n", iface, pszName);
2606
2607 if(!pszName)
2608 return E_INVALIDARG;
2609
2610 *pszName = NULL;
2611 get_file_name(This, pszName);
2612 return *pszName ? S_OK : E_FAIL;
2613 }
2614
2615 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
2616 {
2617 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2618 TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
2619
2620 LocalFree(This->custom_title);
2621 This->custom_title = StrDupW(pszTitle);
2622 update_control_text(This);
2623
2624 return S_OK;
2625 }
2626
2627 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
2628 {
2629 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2630 TRACE("%p (%s)\n", This, debugstr_w(pszText));
2631
2632 LocalFree(This->custom_okbutton);
2633 This->custom_okbutton = StrDupW(pszText);
2634 update_control_text(This);
2635 update_layout(This);
2636
2637 return S_OK;
2638 }
2639
2640 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2641 {
2642 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2643 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2644
2645 LocalFree(This->custom_filenamelabel);
2646 This->custom_filenamelabel = StrDupW(pszLabel);
2647 update_control_text(This);
2648 update_layout(This);
2649
2650 return S_OK;
2651 }
2652
2653 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
2654 {
2655 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2656 HRESULT hr;
2657 TRACE("%p (%p)\n", This, ppsi);
2658
2659 if(!ppsi)
2660 return E_INVALIDARG;
2661
2662 if(This->psia_results)
2663 {
2664 UINT item_count;
2665 hr = IShellItemArray_GetCount(This->psia_results, &item_count);
2666 if(SUCCEEDED(hr))
2667 {
2668 if(item_count != 1)
2669 return E_FAIL;
2670
2671 /* Adds a reference. */
2672 hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
2673 }
2674
2675 return hr;
2676 }
2677
2678 return E_UNEXPECTED;
2679 }
2680
2681 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
2682 {
2683 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2684 FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
2685 return S_OK;
2686 }
2687
2688 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
2689 {
2690 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2691 TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
2692
2693 LocalFree(This->default_ext);
2694 This->default_ext = StrDupW(pszDefaultExtension);
2695
2696 return S_OK;
2697 }
2698
2699 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
2700 {
2701 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2702 TRACE("%p (0x%08x)\n", This, hr);
2703
2704 if(This->dlg_hwnd)
2705 EndDialog(This->dlg_hwnd, hr);
2706
2707 return S_OK;
2708 }
2709
2710 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
2711 {
2712 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2713 TRACE("%p (%s)\n", This, debugstr_guid(guid));
2714 This->client_guid = *guid;
2715 return S_OK;
2716 }
2717
2718 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
2719 {
2720 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2721 FIXME("stub - %p\n", This);
2722 return E_NOTIMPL;
2723 }
2724
2725 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
2726 {
2727 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2728 FIXME("stub - %p (%p)\n", This, pFilter);
2729 return E_NOTIMPL;
2730 }
2731
2732 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
2733 {
2734 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2735 TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
2736
2737 LocalFree(This->custom_cancelbutton);
2738 This->custom_cancelbutton = StrDupW(pszLabel);
2739 update_control_text(This);
2740 update_layout(This);
2741
2742 return S_OK;
2743 }
2744
2745 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
2746 {
2747 FileDialogImpl *This = impl_from_IFileDialog2(iface);
2748 FIXME("stub - %p (%p)\n", This, psi);
2749 return E_NOTIMPL;
2750 }
2751
2752 static const IFileDialog2Vtbl vt_IFileDialog2 = {
2753 IFileDialog2_fnQueryInterface,
2754 IFileDialog2_fnAddRef,
2755 IFileDialog2_fnRelease,
2756 IFileDialog2_fnShow,
2757 IFileDialog2_fnSetFileTypes,
2758 IFileDialog2_fnSetFileTypeIndex,
2759 IFileDialog2_fnGetFileTypeIndex,
2760 IFileDialog2_fnAdvise,
2761 IFileDialog2_fnUnadvise,
2762 IFileDialog2_fnSetOptions,
2763 IFileDialog2_fnGetOptions,
2764 IFileDialog2_fnSetDefaultFolder,
2765 IFileDialog2_fnSetFolder,
2766 IFileDialog2_fnGetFolder,
2767 IFileDialog2_fnGetCurrentSelection,
2768 IFileDialog2_fnSetFileName,
2769 IFileDialog2_fnGetFileName,
2770 IFileDialog2_fnSetTitle,
2771 IFileDialog2_fnSetOkButtonLabel,
2772 IFileDialog2_fnSetFileNameLabel,
2773 IFileDialog2_fnGetResult,
2774 IFileDialog2_fnAddPlace,
2775 IFileDialog2_fnSetDefaultExtension,
2776 IFileDialog2_fnClose,
2777 IFileDialog2_fnSetClientGuid,
2778 IFileDialog2_fnClearClientData,
2779 IFileDialog2_fnSetFilter,
2780 IFileDialog2_fnSetCancelButtonLabel,
2781 IFileDialog2_fnSetNavigationRoot
2782 };
2783
2784 /**************************************************************************
2785 * IFileOpenDialog
2786 */
2787 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
2788 {
2789 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
2790 }
2791
2792 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
2793 REFIID riid, void **ppvObject)
2794 {
2795 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2796 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
2797 }
2798
2799 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
2800 {
2801 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2802 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
2803 }
2804
2805 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
2806 {
2807 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2808 return IFileDialog2_Release(&This->IFileDialog2_iface);
2809 }
2810
2811 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
2812 {
2813 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2814 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
2815 }
2816
2817 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
2818 const COMDLG_FILTERSPEC *rgFilterSpec)
2819 {
2820 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2821 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
2822 }
2823
2824 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
2825 {
2826 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2827 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
2828 }
2829
2830 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
2831 {
2832 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2833 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
2834 }
2835
2836 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
2837 DWORD *pdwCookie)
2838 {
2839 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2840 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
2841 }
2842
2843 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
2844 {
2845 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2846 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
2847 }
2848
2849 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
2850 {
2851 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2852 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
2853 }
2854
2855 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
2856 {
2857 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2858 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
2859 }
2860
2861 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
2862 {
2863 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2864 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
2865 }
2866
2867 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
2868 {
2869 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2870 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
2871 }
2872
2873 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
2874 {
2875 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2876 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
2877 }
2878
2879 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
2880 {
2881 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2882 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
2883 }
2884
2885 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
2886 {
2887 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2888 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
2889 }
2890
2891 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
2892 {
2893 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2894 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
2895 }
2896
2897 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
2898 {
2899 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2900 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
2901 }
2902
2903 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
2904 {
2905 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2906 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
2907 }
2908
2909 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
2910 {
2911 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2912 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
2913 }
2914
2915 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
2916 {
2917 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2918 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
2919 }
2920
2921 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
2922 {
2923 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2924 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
2925 }
2926
2927 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
2928 LPCWSTR pszDefaultExtension)
2929 {
2930 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2931 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
2932 }
2933
2934 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
2935 {
2936 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2937 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
2938 }
2939
2940 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
2941 {
2942 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2943 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
2944 }
2945
2946 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
2947 {
2948 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2949 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
2950 }
2951
2952 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
2953 {
2954 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2955 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
2956 }
2957
2958 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
2959 {
2960 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2961 TRACE("%p (%p)\n", This, ppenum);
2962
2963 *ppenum = This->psia_results;
2964
2965 if(*ppenum)
2966 {
2967 IShellItemArray_AddRef(*ppenum);
2968 return S_OK;
2969 }
2970
2971 return E_FAIL;
2972 }
2973
2974 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
2975 {
2976 FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
2977 TRACE("%p (%p)\n", This, ppsai);
2978
2979 if(This->psia_selection)
2980 {
2981 *ppsai = This->psia_selection;
2982 IShellItemArray_AddRef(*ppsai);
2983 return S_OK;
2984 }
2985
2986 return E_FAIL;
2987 }
2988
2989 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
2990 IFileOpenDialog_fnQueryInterface,
2991 IFileOpenDialog_fnAddRef,
2992 IFileOpenDialog_fnRelease,
2993 IFileOpenDialog_fnShow,
2994 IFileOpenDialog_fnSetFileTypes,
2995 IFileOpenDialog_fnSetFileTypeIndex,
2996 IFileOpenDialog_fnGetFileTypeIndex,
2997 IFileOpenDialog_fnAdvise,
2998 IFileOpenDialog_fnUnadvise,
2999 IFileOpenDialog_fnSetOptions,
3000 IFileOpenDialog_fnGetOptions,
3001 IFileOpenDialog_fnSetDefaultFolder,
3002 IFileOpenDialog_fnSetFolder,
3003 IFileOpenDialog_fnGetFolder,
3004 IFileOpenDialog_fnGetCurrentSelection,
3005 IFileOpenDialog_fnSetFileName,
3006 IFileOpenDialog_fnGetFileName,
3007 IFileOpenDialog_fnSetTitle,
3008 IFileOpenDialog_fnSetOkButtonLabel,
3009 IFileOpenDialog_fnSetFileNameLabel,
3010 IFileOpenDialog_fnGetResult,
3011 IFileOpenDialog_fnAddPlace,
3012 IFileOpenDialog_fnSetDefaultExtension,
3013 IFileOpenDialog_fnClose,
3014 IFileOpenDialog_fnSetClientGuid,
3015 IFileOpenDialog_fnClearClientData,
3016 IFileOpenDialog_fnSetFilter,
3017 IFileOpenDialog_fnGetResults,
3018 IFileOpenDialog_fnGetSelectedItems
3019 };
3020
3021 /**************************************************************************
3022 * IFileSaveDialog
3023 */
3024 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
3025 {
3026 return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
3027 }
3028
3029 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
3030 REFIID riid,
3031 void **ppvObject)
3032 {
3033 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3034 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3035 }
3036
3037 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
3038 {
3039 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3040 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3041 }
3042
3043 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
3044 {
3045 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3046 return IFileDialog2_Release(&This->IFileDialog2_iface);
3047 }
3048
3049 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
3050 {
3051 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3052 return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
3053 }
3054
3055 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
3056 const COMDLG_FILTERSPEC *rgFilterSpec)
3057 {
3058 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3059 return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
3060 }
3061
3062 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
3063 {
3064 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3065 return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
3066 }
3067
3068 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
3069 {
3070 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3071 return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
3072 }
3073
3074 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
3075 DWORD *pdwCookie)
3076 {
3077 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3078 return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
3079 }
3080
3081 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
3082 {
3083 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3084 return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
3085 }
3086
3087 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
3088 {
3089 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3090 return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
3091 }
3092
3093 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
3094 {
3095 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3096 return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
3097 }
3098
3099 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
3100 {
3101 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3102 return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
3103 }
3104
3105 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
3106 {
3107 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3108 return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
3109 }
3110
3111 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
3112 {
3113 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3114 return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
3115 }
3116
3117 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
3118 {
3119 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3120 return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
3121 }
3122
3123 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
3124 {
3125 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3126 return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
3127 }
3128
3129 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
3130 {
3131 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3132 return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
3133 }
3134
3135 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
3136 {
3137 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3138 return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
3139 }
3140
3141 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
3142 {
3143 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3144 return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
3145 }
3146
3147 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
3148 {
3149 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3150 return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
3151 }
3152
3153 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
3154 {
3155 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3156 return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
3157 }
3158
3159 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
3160 {
3161 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3162 return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
3163 }
3164
3165 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
3166 LPCWSTR pszDefaultExtension)
3167 {
3168 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3169 return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
3170 }
3171
3172 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
3173 {
3174 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3175 return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
3176 }
3177
3178 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
3179 {
3180 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3181 return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
3182 }
3183
3184 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
3185 {
3186 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3187 return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
3188 }
3189
3190 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
3191 {
3192 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3193 return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
3194 }
3195
3196 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
3197 {
3198 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3199 FIXME("stub - %p (%p)\n", This, psi);
3200 return E_NOTIMPL;
3201 }
3202
3203 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
3204 {
3205 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3206 FIXME("stub - %p (%p)\n", This, pStore);
3207 return E_NOTIMPL;
3208 }
3209
3210 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
3211 IPropertyDescriptionList *pList,
3212 BOOL fAppendDefault)
3213 {
3214 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3215 FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
3216 return E_NOTIMPL;
3217 }
3218
3219 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
3220 {
3221 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3222 FIXME("stub - %p (%p)\n", This, ppStore);
3223 return E_NOTIMPL;
3224 }
3225
3226 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
3227 IShellItem *psi,
3228 IPropertyStore *pStore,
3229 HWND hwnd,
3230 IFileOperationProgressSink *pSink)
3231 {
3232 FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
3233 FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
3234 return E_NOTIMPL;
3235 }
3236
3237 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
3238 IFileSaveDialog_fnQueryInterface,
3239 IFileSaveDialog_fnAddRef,
3240 IFileSaveDialog_fnRelease,
3241 IFileSaveDialog_fnShow,
3242 IFileSaveDialog_fnSetFileTypes,
3243 IFileSaveDialog_fnSetFileTypeIndex,
3244 IFileSaveDialog_fnGetFileTypeIndex,
3245 IFileSaveDialog_fnAdvise,
3246 IFileSaveDialog_fnUnadvise,
3247 IFileSaveDialog_fnSetOptions,
3248 IFileSaveDialog_fnGetOptions,
3249 IFileSaveDialog_fnSetDefaultFolder,
3250 IFileSaveDialog_fnSetFolder,
3251 IFileSaveDialog_fnGetFolder,
3252 IFileSaveDialog_fnGetCurrentSelection,
3253 IFileSaveDialog_fnSetFileName,
3254 IFileSaveDialog_fnGetFileName,
3255 IFileSaveDialog_fnSetTitle,
3256 IFileSaveDialog_fnSetOkButtonLabel,
3257 IFileSaveDialog_fnSetFileNameLabel,
3258 IFileSaveDialog_fnGetResult,
3259 IFileSaveDialog_fnAddPlace,
3260 IFileSaveDialog_fnSetDefaultExtension,
3261 IFileSaveDialog_fnClose,
3262 IFileSaveDialog_fnSetClientGuid,
3263 IFileSaveDialog_fnClearClientData,
3264 IFileSaveDialog_fnSetFilter,
3265 IFileSaveDialog_fnSetSaveAsItem,
3266 IFileSaveDialog_fnSetProperties,
3267 IFileSaveDialog_fnSetCollectedProperties,
3268 IFileSaveDialog_fnGetProperties,
3269 IFileSaveDialog_fnApplyProperties
3270 };
3271
3272 /**************************************************************************
3273 * IExplorerBrowserEvents implementation
3274 */
3275 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
3276 {
3277 return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
3278 }
3279
3280 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
3281 REFIID riid, void **ppvObject)
3282 {
3283 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3284 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
3285
3286 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3287 }
3288
3289 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
3290 {
3291 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3292 TRACE("%p\n", This);
3293 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3294 }
3295
3296 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
3297 {
3298 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3299 TRACE("%p\n", This);
3300 return IFileDialog2_Release(&This->IFileDialog2_iface);
3301 }
3302
3303 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
3304 PCIDLIST_ABSOLUTE pidlFolder)
3305 {
3306 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3307 IShellItem *psi;
3308 HRESULT hr;
3309 TRACE("%p (%p)\n", This, pidlFolder);
3310
3311 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
3312 if(SUCCEEDED(hr))
3313 {
3314 hr = events_OnFolderChanging(This, psi);
3315 IShellItem_Release(psi);
3316
3317 /* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
3318 if(hr == S_FALSE)
3319 hr = E_FAIL;
3320
3321 return hr;
3322 }
3323 else
3324 ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
3325
3326 return S_OK;
3327 }
3328
3329 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
3330 IShellView *psv)
3331 {
3332 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3333 TRACE("%p (%p)\n", This, psv);
3334 return S_OK;
3335 }
3336
3337 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
3338 PCIDLIST_ABSOLUTE pidlFolder)
3339 {
3340 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3341 HRESULT hr;
3342 TRACE("%p (%p)\n", This, pidlFolder);
3343
3344 if(This->psi_folder)
3345 IShellItem_Release(This->psi_folder);
3346
3347 hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
3348 if(FAILED(hr))
3349 {
3350 ERR("Failed to get the current folder.\n");
3351 This->psi_folder = NULL;
3352 }
3353
3354 events_OnFolderChange(This);
3355
3356 return S_OK;
3357 }
3358
3359 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
3360 PCIDLIST_ABSOLUTE pidlFolder)
3361 {
3362 FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
3363 TRACE("%p (%p)\n", This, pidlFolder);
3364 return S_OK;
3365 }
3366
3367 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
3368 IExplorerBrowserEvents_fnQueryInterface,
3369 IExplorerBrowserEvents_fnAddRef,
3370 IExplorerBrowserEvents_fnRelease,
3371 IExplorerBrowserEvents_fnOnNavigationPending,
3372 IExplorerBrowserEvents_fnOnViewCreated,
3373 IExplorerBrowserEvents_fnOnNavigationComplete,
3374 IExplorerBrowserEvents_fnOnNavigationFailed
3375 };
3376
3377 /**************************************************************************
3378 * IServiceProvider implementation
3379 */
3380 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
3381 {
3382 return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
3383 }
3384
3385 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
3386 REFIID riid, void **ppvObject)
3387 {
3388 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3389 TRACE("%p\n", This);
3390 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3391 }
3392
3393 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
3394 {
3395 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3396 TRACE("%p\n", This);
3397 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3398 }
3399
3400 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
3401 {
3402 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3403 TRACE("%p\n", This);
3404 return IFileDialog2_Release(&This->IFileDialog2_iface);
3405 }
3406
3407 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
3408 REFGUID guidService,
3409 REFIID riid, void **ppv)
3410 {
3411 FileDialogImpl *This = impl_from_IServiceProvider(iface);
3412 HRESULT hr = E_NOTIMPL;
3413 TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
3414
3415 *ppv = NULL;
3416 if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
3417 hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
3418 else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
3419 hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
3420 else
3421 FIXME("Interface %s requested from unknown service %s\n",
3422 debugstr_guid(riid), debugstr_guid(guidService));
3423
3424 return hr;
3425 }
3426
3427 static const IServiceProviderVtbl vt_IServiceProvider = {
3428 IServiceProvider_fnQueryInterface,
3429 IServiceProvider_fnAddRef,
3430 IServiceProvider_fnRelease,
3431 IServiceProvider_fnQueryService
3432 };
3433
3434 /**************************************************************************
3435 * ICommDlgBrowser3 implementation
3436 */
3437 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
3438 {
3439 return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
3440 }
3441
3442 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
3443 REFIID riid, void **ppvObject)
3444 {
3445 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3446 TRACE("%p\n", This);
3447 return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
3448 }
3449
3450 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
3451 {
3452 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3453 TRACE("%p\n", This);
3454 return IFileDialog2_AddRef(&This->IFileDialog2_iface);
3455 }
3456
3457 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
3458 {
3459 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3460 TRACE("%p\n", This);
3461 return IFileDialog2_Release(&This->IFileDialog2_iface);
3462 }
3463
3464 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
3465 IShellView *shv)
3466 {
3467 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3468 HRESULT hr;
3469 TRACE("%p (%p)\n", This, shv);
3470
3471 hr = on_default_action(This);
3472
3473 if(SUCCEEDED(hr))
3474 EndDialog(This->dlg_hwnd, S_OK);
3475
3476 return S_OK;
3477 }
3478
3479 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
3480 IShellView *shv, ULONG uChange )
3481 {
3482 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3483 IDataObject *new_selection;
3484 HRESULT hr;
3485 TRACE("%p (%p, %x)\n", This, shv, uChange);
3486
3487 switch(uChange)
3488 {
3489 case CDBOSC_SELCHANGE:
3490 if(This->psia_selection)
3491 {
3492 IShellItemArray_Release(This->psia_selection);
3493 This->psia_selection = NULL;
3494 }
3495
3496 hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
3497 if(SUCCEEDED(hr))
3498 {
3499 hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
3500 (void**)&This->psia_selection);
3501 if(SUCCEEDED(hr))
3502 {
3503 fill_filename_from_selection(This);
3504 events_OnSelectionChange(This);
3505 }
3506
3507 IDataObject_Release(new_selection);
3508 }
3509 break;
3510 default:
3511 TRACE("Unhandled state change\n");
3512 }
3513 return S_OK;
3514 }
3515
3516 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
3517 IShellView *shv, LPCITEMIDLIST pidl)
3518 {
3519 FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
3520 IShellItem *psi;
3521 LPWSTR filename;
3522 LPITEMIDLIST parent_pidl;
3523 HRESULT hr;
3524 ULONG attr;
3525 TRACE("%p (%p, %p)\n", This, shv, pidl);
3526
3527 if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
3528 return S_OK;
3529
3530 hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
3531 if(SUCCEEDED(hr))
3532 {
3533 LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
3534 hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
3535 ILFree(parent_pidl);
3536 ILFree(full_pidl);
3537 }
3538 if(FAILED(hr))
3539 {
3540 ERR("Failed to get shellitem (%08x).\n", hr);
3541 return S_OK;
3542 }
3543
3544 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
3545 if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
3546 {