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