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