comdlg32: Fetch rectangle from the correct control.
[wine] / dlls / 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 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "wingdi.h"
31 #include "winreg.h"
32 #include "shlwapi.h"
33
34 #include "commdlg.h"
35 #include "cdlg.h"
36 #include "filedlgbrowser.h"
37
38 #include "wine/debug.h"
39 #include "wine/list.h"
40
41 #define IDC_NAV_TOOLBAR      200
42 #define IDC_NAVBACK          201
43 #define IDC_NAVFORWARD       202
44
45 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
46
47 enum ITEMDLG_TYPE {
48     ITEMDLG_TYPE_OPEN,
49     ITEMDLG_TYPE_SAVE
50 };
51
52 typedef struct {
53     struct list entry;
54     IFileDialogEvents *pfde;
55     DWORD cookie;
56 } events_client;
57
58 typedef struct FileDialogImpl {
59     IFileDialog2 IFileDialog2_iface;
60     union {
61         IFileOpenDialog IFileOpenDialog_iface;
62         IFileSaveDialog IFileSaveDialog_iface;
63     } u;
64     enum ITEMDLG_TYPE dlg_type;
65     IExplorerBrowserEvents IExplorerBrowserEvents_iface;
66     IServiceProvider       IServiceProvider_iface;
67     ICommDlgBrowser3       ICommDlgBrowser3_iface;
68     LONG ref;
69
70     FILEOPENDIALOGOPTIONS options;
71     COMDLG_FILTERSPEC *filterspecs;
72     UINT filterspec_count;
73     UINT filetypeindex;
74
75     struct list events_clients;
76     DWORD events_next_cookie;
77
78     IShellItemArray *psia_selection;
79     IShellItemArray *psia_results;
80     IShellItem *psi_defaultfolder;
81     IShellItem *psi_setfolder;
82     IShellItem *psi_folder;
83
84     HWND dlg_hwnd;
85     IExplorerBrowser *peb;
86     DWORD ebevents_cookie;
87
88     LPWSTR set_filename;
89 } FileDialogImpl;
90
91 /**************************************************************************
92  * Helper functions.
93  */
94 static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
95 {
96     HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
97     UINT len;
98
99     if(!hwnd_edit)
100     {
101         if(This->set_filename)
102         {
103             len = lstrlenW(This->set_filename);
104             *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
105             lstrcpyW(*str, This->set_filename);
106             return len;
107         }
108         return FALSE;
109     }
110
111     len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
112     *str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
113     if(!*str)
114         return FALSE;
115
116     SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
117     return len;
118 }
119
120 static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
121 {
122     HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
123
124     if(This->set_filename)
125         LocalFree(This->set_filename);
126
127     This->set_filename = StrDupW(str);
128
129     return SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str);
130 }
131
132 static void fill_filename_from_selection(FileDialogImpl *This)
133 {
134     IShellItem *psi;
135     LPWSTR *names;
136     HRESULT hr;
137     UINT item_count, valid_count;
138     UINT len_total, i;
139
140     if(!This->psia_selection)
141         return;
142
143     hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
144     if(FAILED(hr) || !item_count)
145         return;
146
147     names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
148
149     /* Get names of the selected items */
150     valid_count = 0; len_total = 0;
151     for(i = 0; i < item_count; i++)
152     {
153         hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
154         if(SUCCEEDED(hr))
155         {
156             UINT attr;
157
158             hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
159             if(SUCCEEDED(hr) && (attr & SFGAO_FOLDER))
160                 continue; /* FIXME: FOS_PICKFOLDERS */
161
162             hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
163             if(SUCCEEDED(hr))
164             {
165                 len_total += lstrlenW(names[valid_count]) + 3;
166                 valid_count++;
167             }
168             IShellItem_Release(psi);
169         }
170     }
171
172     if(valid_count == 1)
173     {
174         set_file_name(This, names[0]);
175         CoTaskMemFree(names[0]);
176     }
177     else if(valid_count > 1)
178     {
179         LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
180         LPWSTR cur_point = string;
181
182         for(i = 0; i < valid_count; i++)
183         {
184             LPWSTR file = names[i];
185             *cur_point++ = '\"';
186             lstrcpyW(cur_point, file);
187             cur_point += lstrlenW(file);
188             *cur_point++ = '\"';
189             *cur_point++ = ' ';
190             CoTaskMemFree(file);
191         }
192         *(cur_point-1) = '\0';
193
194         set_file_name(This, string);
195         HeapFree(GetProcessHeap(), 0, string);
196     }
197
198     HeapFree(GetProcessHeap(), 0, names);
199     return;
200 }
201
202 static HRESULT on_default_action(FileDialogImpl *This)
203 {
204     IShellFolder *psf_parent, *psf_desktop;
205     LPITEMIDLIST *pidla;
206     LPITEMIDLIST current_folder;
207     LPWSTR fn_iter, files, tmp_files;
208     UINT file_count = 0, len, i;
209     int open_action;
210     HRESULT hr, ret = E_FAIL;
211
212     len = get_file_name(This, &tmp_files);
213     if(len)
214     {
215         UINT size_used;
216         file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
217     }
218     if(!file_count) return E_FAIL;
219
220     hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, &current_folder);
221     if(FAILED(hr))
222     {
223         ERR("Failed to get pidl for current directory.\n");
224         return hr;
225     }
226
227     TRACE("Acting on %d file(s).\n", file_count);
228
229     pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
230     open_action = ONOPEN_OPEN;
231     fn_iter = files;
232
233     for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
234     {
235         WCHAR canon_filename[MAX_PATH];
236         psf_parent = NULL;
237
238         COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
239
240         if( (This->options & FOS_NOVALIDATE) &&
241             !(This->options & FOS_FILEMUSTEXIST) )
242             open_action = ONOPEN_OPEN;
243         else
244             open_action = ONOPEN_BROWSE;
245
246         open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
247                                                    This->options, (This->dlg_type == ITEMDLG_TYPE_SAVE),
248                                                    open_action);
249
250         pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
251
252         if(psf_parent && !(open_action == ONOPEN_BROWSE))
253             IShellItem_Release(psf_parent);
254
255         fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
256     }
257
258     HeapFree(GetProcessHeap(), 0, files);
259     ILFree(current_folder);
260
261     if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
262         open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
263
264     switch(open_action)
265     {
266     case ONOPEN_SEARCH:
267         FIXME("Filtering not implemented.\n");
268         break;
269
270     case ONOPEN_BROWSE:
271         hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
272         if(FAILED(hr))
273             ERR("Failed to browse to directory: %08x\n", hr);
274
275         IShellItem_Release(psf_parent);
276         break;
277
278     case ONOPEN_OPEN:
279         hr = SHGetDesktopFolder(&psf_desktop);
280         if(SUCCEEDED(hr))
281         {
282             if(This->psia_results)
283                 IShellItemArray_Release(This->psia_results);
284
285             hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
286                                         &This->psia_results);
287
288             if(SUCCEEDED(hr))
289                 ret = S_OK;
290
291             IShellFolder_Release(psf_desktop);
292         }
293         break;
294
295     default:
296         ERR("Failed.\n");
297         break;
298     }
299
300     /* Clean up */
301     for(i = 0; i < file_count; i++)
302         ILFree(pidla[i]);
303     HeapFree(GetProcessHeap(), 0, pidla);
304
305     /* Success closes the dialog */
306     return ret;
307 }
308
309 /**************************************************************************
310  * Window related functions.
311  */
312 static SIZE update_layout(FileDialogImpl *This)
313 {
314     HDWP hdwp;
315     HWND hwnd;
316     RECT dialog_rc;
317     RECT cancel_rc, open_rc;
318     RECT filetype_rc, filename_rc, filenamelabel_rc;
319     RECT toolbar_rc, ebrowser_rc;
320     int missing_width, missing_height;
321     static const UINT vspacing = 4, hspacing = 4;
322     SIZE ret;
323
324     GetClientRect(This->dlg_hwnd, &dialog_rc);
325
326     missing_width = max(0, 320 - dialog_rc.right);
327     missing_height = max(0, 200 - dialog_rc.bottom);
328
329     if(missing_width || missing_height)
330     {
331         TRACE("Missing (%d, %d)\n", missing_width, missing_height);
332         ret.cx = missing_width;
333         ret.cy = missing_height;
334         return ret;
335     }
336
337     /****
338      * Calculate the size of the dialog and all the parts.
339      */
340
341     /* Cancel button */
342     hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
343     if(hwnd)
344     {
345         int cancel_width, cancel_height;
346         GetWindowRect(hwnd, &cancel_rc);
347         cancel_width = cancel_rc.right - cancel_rc.left;
348         cancel_height = cancel_rc.bottom - cancel_rc.top;
349
350         cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
351         cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
352         cancel_rc.right = cancel_rc.left + cancel_width;
353         cancel_rc.bottom = cancel_rc.top + cancel_height;
354     }
355
356     /* Open/Save button */
357     hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
358     if(hwnd)
359     {
360         int open_width, open_height;
361         GetWindowRect(hwnd, &open_rc);
362         open_width = open_rc.right - open_rc.left;
363         open_height = open_rc.bottom - open_rc.top;
364
365         open_rc.left = cancel_rc.left - open_width - hspacing;
366         open_rc.top = cancel_rc.top;
367         open_rc.right = open_rc.left + open_width;
368         open_rc.bottom = open_rc.top + open_height;
369     }
370
371     /* The filetype combobox. */
372     hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
373     if(hwnd)
374     {
375         int filetype_width, filetype_height;
376         GetWindowRect(hwnd, &filetype_rc);
377
378         filetype_width = filetype_rc.right - filetype_rc.left;
379         filetype_height = filetype_rc.bottom - filetype_rc.top;
380
381         filetype_rc.right = cancel_rc.right;
382
383         filetype_rc.left = filetype_rc.right - filetype_width;
384         filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
385         filetype_rc.bottom = filetype_rc.top + filetype_height;
386
387         if(!This->filterspec_count)
388             filetype_rc.left = filetype_rc.right;
389     }
390
391     /* Filename label. */
392     hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
393     if(hwnd)
394     {
395         int filetypelabel_width, filetypelabel_height;
396         GetWindowRect(hwnd, &filenamelabel_rc);
397
398         filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
399         filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
400
401         filenamelabel_rc.left = 160; /* FIXME */
402         filenamelabel_rc.top = filetype_rc.top;
403         filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
404         filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
405     }
406
407     /* Filename edit box. */
408     hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
409     if(hwnd)
410     {
411         int filename_width, filename_height;
412         GetWindowRect(hwnd, &filename_rc);
413
414         filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
415         filename_height = filename_rc.bottom - filename_rc.top;
416
417         filename_rc.left = filenamelabel_rc.right + hspacing;
418         filename_rc.top = filetype_rc.top;
419         filename_rc.right = filename_rc.left + filename_width;
420         filename_rc.bottom = filename_rc.top + filename_height;
421     }
422
423     hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
424     if(hwnd)
425     {
426         GetWindowRect(hwnd, &toolbar_rc);
427         MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
428     }
429
430     /* The ExplorerBrowser control. */
431     ebrowser_rc.left = dialog_rc.left + vspacing;
432     ebrowser_rc.top = toolbar_rc.bottom + vspacing;
433     ebrowser_rc.right = dialog_rc.right - hspacing;
434     ebrowser_rc.bottom = filename_rc.top - hspacing;
435
436     /****
437      * Move everything to the right place.
438      */
439
440     /* FIXME: The Save Dialog uses a slightly different layout. */
441     hdwp = BeginDeferWindowPos(6);
442
443     if(hdwp && This->peb)
444         IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
445
446     /* The default controls */
447     if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
448         DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
449                        SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
450
451     if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
452         DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
453                        filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
454                        SWP_NOZORDER | SWP_NOACTIVATE);
455
456     if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
457         DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
458                        SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
459
460     if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
461         DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
462                        SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
463
464     if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
465         DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
466                        SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
467
468     if(hdwp)
469         EndDeferWindowPos(hdwp);
470     else
471         ERR("Failed to position dialog controls.\n");
472
473     ret.cx = 0; ret.cy = 0;
474     return ret;
475 }
476
477 static HRESULT init_explorerbrowser(FileDialogImpl *This)
478 {
479     IShellItem *psi_folder;
480     FOLDERSETTINGS fos;
481     RECT rc = {0};
482     HRESULT hr;
483
484     /* Create ExplorerBrowser instance */
485     OleInitialize(NULL);
486
487     hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
488                           &IID_IExplorerBrowser, (void**)&This->peb);
489     if(FAILED(hr))
490     {
491         ERR("Failed to instantiate ExplorerBrowser control.\n");
492         return hr;
493     }
494
495     IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES);
496
497     hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
498     if(FAILED(hr))
499     {
500         ERR("Failed to initialize the ExplorerBrowser control.\n");
501         IExplorerBrowser_Release(This->peb);
502         This->peb = NULL;
503         return hr;
504     }
505     hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
506     if(FAILED(hr))
507         ERR("Advise (ExplorerBrowser) failed.\n");
508
509     /* Get previous options? */
510     fos.ViewMode = fos.fFlags = 0;
511     if(!(This->options & FOS_ALLOWMULTISELECT))
512         fos.fFlags |= FWF_SINGLESEL;
513
514     IExplorerBrowser_SetFolderSettings(This->peb, &fos);
515
516     hr = IUnknown_SetSite((IUnknown*)This->peb, (IUnknown*)This);
517     if(FAILED(hr))
518         ERR("SetSite (ExplorerBrowser) failed.\n");
519
520     /* Browse somewhere */
521     psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
522     IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
523
524     return S_OK;
525 }
526
527 static void init_toolbar(FileDialogImpl *This, HWND hwnd)
528 {
529     HWND htoolbar;
530     TBADDBITMAP tbab;
531     TBBUTTON button[2];
532
533     htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
534                                0, 0, 0, 0,
535                                hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
536
537     tbab.hInst = HINST_COMMCTRL;
538     tbab.nID = IDB_HIST_LARGE_COLOR;
539     SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
540
541     button[0].iBitmap = HIST_BACK;
542     button[0].idCommand = IDC_NAVBACK;
543     button[0].fsState = TBSTATE_ENABLED;
544     button[0].fsStyle = BTNS_BUTTON;
545     button[0].dwData = 0;
546     button[0].iString = 0;
547
548     button[1].iBitmap = HIST_FORWARD;
549     button[1].idCommand = IDC_NAVFORWARD;
550     button[1].fsState = TBSTATE_ENABLED;
551     button[1].fsStyle = BTNS_BUTTON;
552     button[1].dwData = 0;
553     button[1].iString = 0;
554
555     SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)&button);
556     SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
557     SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
558 }
559
560 static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
561 {
562     FileDialogImpl *This = (FileDialogImpl*)lParam;
563     HWND hitem;
564
565     TRACE("(%p, %p)\n", This, hwnd);
566
567     SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
568     This->dlg_hwnd = hwnd;
569
570     hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
571     if(hitem) ShowWindow(hitem, SW_HIDE);
572
573     hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
574     if(hitem) ShowWindow(hitem, SW_HIDE);
575
576     /* Fill filetypes combobox, or hide it. */
577     hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
578     if(This->filterspec_count)
579     {
580         UINT i;
581         for(i = 0; i < This->filterspec_count; i++)
582             SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
583
584         SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
585     }
586     else
587         ShowWindow(hitem, SW_HIDE);
588
589     if(This->set_filename &&
590        (hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
591         SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
592
593     init_explorerbrowser(This);
594     init_toolbar(This, hwnd);
595     update_layout(This);
596
597     return TRUE;
598 }
599
600 static LRESULT on_wm_size(FileDialogImpl *This)
601 {
602     update_layout(This);
603     return FALSE;
604 }
605
606 static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
607 {
608     MINMAXINFO *mmi = (MINMAXINFO*)lparam;
609     TRACE("%p (%p)\n", This, mmi);
610
611     /* FIXME */
612     mmi->ptMinTrackSize.x = 640;
613     mmi->ptMinTrackSize.y = 480;
614
615     return FALSE;
616 }
617
618 static LRESULT on_wm_destroy(FileDialogImpl *This)
619 {
620     TRACE("%p\n", This);
621
622     if(This->peb)
623     {
624         IExplorerBrowser_Destroy(This->peb);
625         IExplorerBrowser_Release(This->peb);
626         This->peb = NULL;
627     }
628
629     This->dlg_hwnd = NULL;
630
631     return TRUE;
632 }
633
634 static LRESULT on_idok(FileDialogImpl *This)
635 {
636     TRACE("%p\n", This);
637
638     if(SUCCEEDED(on_default_action(This)))
639         EndDialog(This->dlg_hwnd, S_OK);
640
641     return FALSE;
642 }
643
644 static LRESULT on_idcancel(FileDialogImpl *This)
645 {
646     TRACE("%p\n", This);
647
648     EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
649
650     return FALSE;
651 }
652
653 static LRESULT on_browse_back(FileDialogImpl *This)
654 {
655     TRACE("%p\n", This);
656     IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
657     return FALSE;
658 }
659
660 static LRESULT on_browse_forward(FileDialogImpl *This)
661 {
662     TRACE("%p\n", This);
663     IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
664     return FALSE;
665 }
666
667 static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
668 {
669     if(HIWORD(wparam) == CBN_SELCHANGE)
670     {
671         IShellView *psv;
672         HRESULT hr;
673
674         This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
675         TRACE("File type selection changed to %d.\n", This->filetypeindex);
676
677         hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
678         if(SUCCEEDED(hr))
679         {
680             IShellView_Refresh(psv);
681             IShellView_Release(psv);
682         }
683     }
684
685     return FALSE;
686 }
687
688 static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
689 {
690     switch(LOWORD(wparam))
691     {
692     case IDOK:                return on_idok(This);
693     case IDCANCEL:            return on_idcancel(This);
694     case IDC_NAVBACK:         return on_browse_back(This);
695     case IDC_NAVFORWARD:      return on_browse_forward(This);
696     case IDC_FILETYPE:        return on_command_filetype(This, wparam, lparam);
697     default:                  TRACE("Unknown command.\n");
698     }
699     return FALSE;
700 }
701
702 static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
703 {
704     FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
705
706     switch(umessage)
707     {
708     case WM_INITDIALOG:       return on_wm_initdialog(hwnd, lparam);
709     case WM_COMMAND:          return on_wm_command(This, wparam, lparam);
710     case WM_SIZE:             return on_wm_size(This);
711     case WM_GETMINMAXINFO:    return on_wm_getminmaxinfo(This, lparam);
712     case WM_DESTROY:          return on_wm_destroy(This);
713     }
714
715     return FALSE;
716 }
717
718 static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
719 {
720     INT_PTR res;
721
722     SetLastError(0);
723     res = DialogBoxParamW(COMDLG32_hInstance,
724                           MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
725                           parent, itemdlg_dlgproc, (LPARAM)This);
726     This->dlg_hwnd = NULL;
727     if(res == -1)
728     {
729         ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
730         return E_FAIL;
731     }
732
733     TRACE("Returning 0x%08x\n", (HRESULT)res);
734     return (HRESULT)res;
735 }
736
737 /**************************************************************************
738  * IFileDialog implementation
739  */
740 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
741 {
742     return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
743 }
744
745 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
746                                                     REFIID riid,
747                                                     void **ppvObject)
748 {
749     FileDialogImpl *This = impl_from_IFileDialog2(iface);
750     TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
751
752     *ppvObject = NULL;
753     if(IsEqualGUID(riid, &IID_IUnknown) ||
754        IsEqualGUID(riid, &IID_IFileDialog) ||
755        IsEqualGUID(riid, &IID_IFileDialog2))
756     {
757         *ppvObject = iface;
758     }
759     else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
760     {
761         *ppvObject = &This->u.IFileOpenDialog_iface;
762     }
763     else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
764     {
765         *ppvObject = &This->u.IFileSaveDialog_iface;
766     }
767     else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
768     {
769         *ppvObject = &This->IExplorerBrowserEvents_iface;
770     }
771     else if(IsEqualGUID(riid, &IID_IServiceProvider))
772     {
773         *ppvObject = &This->IServiceProvider_iface;
774     }
775     else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
776             IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
777             IsEqualGUID(&IID_ICommDlgBrowser, riid))
778     {
779         *ppvObject = &This->ICommDlgBrowser3_iface;
780     }
781     else
782         FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
783
784     if(*ppvObject)
785     {
786         IUnknown_AddRef((IUnknown*)*ppvObject);
787         return S_OK;
788     }
789
790     return E_NOINTERFACE;
791 }
792
793 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
794 {
795     FileDialogImpl *This = impl_from_IFileDialog2(iface);
796     LONG ref = InterlockedIncrement(&This->ref);
797     TRACE("%p - ref %d\n", This, ref);
798
799     return ref;
800 }
801
802 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
803 {
804     FileDialogImpl *This = impl_from_IFileDialog2(iface);
805     LONG ref = InterlockedDecrement(&This->ref);
806     TRACE("%p - ref %d\n", This, ref);
807
808     if(!ref)
809     {
810         UINT i;
811         for(i = 0; i < This->filterspec_count; i++)
812         {
813             LocalFree((void*)This->filterspecs[i].pszName);
814             LocalFree((void*)This->filterspecs[i].pszSpec);
815         }
816         HeapFree(GetProcessHeap(), 0, This->filterspecs);
817
818         if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
819         if(This->psi_setfolder)     IShellItem_Release(This->psi_setfolder);
820         if(This->psi_folder)        IShellItem_Release(This->psi_folder);
821         if(This->psia_selection)    IShellItemArray_Release(This->psia_selection);
822         if(This->psia_results)      IShellItemArray_Release(This->psia_results);
823
824         LocalFree(This->set_filename);
825
826         HeapFree(GetProcessHeap(), 0, This);
827     }
828
829     return ref;
830 }
831
832 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
833 {
834     FileDialogImpl *This = impl_from_IFileDialog2(iface);
835     TRACE("%p (%p)\n", iface, hwndOwner);
836
837     return create_dialog(This, hwndOwner);
838 }
839
840 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
841                                                   const COMDLG_FILTERSPEC *rgFilterSpec)
842 {
843     FileDialogImpl *This = impl_from_IFileDialog2(iface);
844     UINT i;
845     TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
846
847     if(This->filterspecs)
848         return E_UNEXPECTED;
849
850     if(!rgFilterSpec)
851         return E_INVALIDARG;
852
853     if(!cFileTypes)
854         return S_OK;
855
856     This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
857     for(i = 0; i < cFileTypes; i++)
858     {
859         This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
860         This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
861     }
862     This->filterspec_count = cFileTypes;
863
864     return S_OK;
865 }
866
867 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
868 {
869     FileDialogImpl *This = impl_from_IFileDialog2(iface);
870     TRACE("%p (%d)\n", This, iFileType);
871
872     if(!This->filterspecs)
873         return E_FAIL;
874
875     if(iFileType >= This->filterspec_count)
876         This->filetypeindex = This->filterspec_count - 1;
877     else
878         This->filetypeindex = iFileType;
879
880     return S_OK;
881 }
882
883 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
884 {
885     FileDialogImpl *This = impl_from_IFileDialog2(iface);
886     TRACE("%p (%p)\n", This, piFileType);
887
888     if(!piFileType)
889         return E_INVALIDARG;
890
891     *piFileType = This->filetypeindex;
892
893     return S_OK;
894 }
895
896 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
897 {
898     FileDialogImpl *This = impl_from_IFileDialog2(iface);
899     events_client *client;
900     TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
901
902     if(!pfde || !pdwCookie)
903         return E_INVALIDARG;
904
905     client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
906     client->pfde = pfde;
907     client->cookie = ++This->events_next_cookie;
908
909     IFileDialogEvents_AddRef(pfde);
910     *pdwCookie = client->cookie;
911
912     list_add_tail(&This->events_clients, &client->entry);
913
914     return S_OK;
915 }
916
917 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
918 {
919     FileDialogImpl *This = impl_from_IFileDialog2(iface);
920     events_client *client, *found = NULL;
921     TRACE("%p (%d)\n", This, dwCookie);
922
923     LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
924     {
925         if(client->cookie == dwCookie)
926         {
927             found = client;
928             break;
929         }
930     }
931
932     if(found)
933     {
934         list_remove(&found->entry);
935         IFileDialogEvents_Release(found->pfde);
936         HeapFree(GetProcessHeap(), 0, found);
937         return S_OK;
938     }
939
940     return E_INVALIDARG;
941 }
942
943 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
944 {
945     FileDialogImpl *This = impl_from_IFileDialog2(iface);
946     TRACE("%p (0x%x)\n", This, fos);
947
948     This->options = fos;
949
950     return S_OK;
951 }
952
953 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
954 {
955     FileDialogImpl *This = impl_from_IFileDialog2(iface);
956     TRACE("%p (%p)\n", This, pfos);
957
958     if(!pfos)
959         return E_INVALIDARG;
960
961     *pfos = This->options;
962
963     return S_OK;
964 }
965
966 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
967 {
968     FileDialogImpl *This = impl_from_IFileDialog2(iface);
969     TRACE("%p (%p)\n", This, psi);
970     if(This->psi_defaultfolder)
971         IShellItem_Release(This->psi_defaultfolder);
972
973     This->psi_defaultfolder = psi;
974
975     if(This->psi_defaultfolder)
976         IShellItem_AddRef(This->psi_defaultfolder);
977
978     return S_OK;
979 }
980
981 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
982 {
983     FileDialogImpl *This = impl_from_IFileDialog2(iface);
984     TRACE("%p (%p)\n", This, psi);
985     if(This->psi_setfolder)
986         IShellItem_Release(This->psi_setfolder);
987
988     This->psi_setfolder = psi;
989
990     if(This->psi_setfolder)
991         IShellItem_AddRef(This->psi_setfolder);
992
993     return S_OK;
994 }
995
996 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
997 {
998     FileDialogImpl *This = impl_from_IFileDialog2(iface);
999     TRACE("%p (%p)\n", This, ppsi);
1000     if(!ppsi)
1001         return E_INVALIDARG;
1002
1003     /* FIXME:
1004        If the dialog is shown, return the current(ly selected) folder. */
1005
1006     *ppsi = NULL;
1007     if(This->psi_folder)
1008         *ppsi = This->psi_folder;
1009     else if(This->psi_setfolder)
1010         *ppsi = This->psi_setfolder;
1011     else if(This->psi_defaultfolder)
1012         *ppsi = This->psi_defaultfolder;
1013
1014     if(*ppsi)
1015     {
1016         IShellItem_AddRef(*ppsi);
1017         return S_OK;
1018     }
1019
1020     return E_FAIL;
1021 }
1022
1023 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
1024 {
1025     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1026     HRESULT hr;
1027     TRACE("%p (%p)\n", This, ppsi);
1028
1029     if(!ppsi)
1030         return E_INVALIDARG;
1031
1032     if(This->psia_selection)
1033     {
1034         /* FIXME: Check filename edit box */
1035         hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
1036         return hr;
1037     }
1038
1039     return E_FAIL;
1040 }
1041
1042 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
1043 {
1044     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1045     TRACE("%p (%p)\n", iface, pszName);
1046
1047     set_file_name(This, pszName);
1048
1049     return S_OK;
1050 }
1051
1052 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
1053 {
1054     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1055     TRACE("%p (%p)\n", iface, pszName);
1056
1057     if(!pszName)
1058         return E_INVALIDARG;
1059
1060     *pszName = NULL;
1061     if(get_file_name(This, pszName))
1062         return S_OK;
1063     else
1064         return E_FAIL;
1065 }
1066
1067 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
1068 {
1069     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1070     FIXME("stub - %p (%p)\n", This, pszTitle);
1071     return E_NOTIMPL;
1072 }
1073
1074 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
1075 {
1076     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1077     FIXME("stub - %p (%p)\n", This, pszText);
1078     return E_NOTIMPL;
1079 }
1080
1081 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
1082 {
1083     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1084     FIXME("stub - %p (%p)\n", This, pszLabel);
1085     return E_NOTIMPL;
1086 }
1087
1088 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
1089 {
1090     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1091     HRESULT hr;
1092     TRACE("%p (%p)\n", This, ppsi);
1093
1094     if(!ppsi)
1095         return E_INVALIDARG;
1096
1097     if(This->psia_results)
1098     {
1099         UINT item_count;
1100         hr = IShellItemArray_GetCount(This->psia_results, &item_count);
1101         if(SUCCEEDED(hr))
1102         {
1103             if(item_count != 1)
1104                 return E_FAIL;
1105
1106             /* Adds a reference. */
1107             hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
1108         }
1109
1110         return hr;
1111     }
1112
1113     return E_UNEXPECTED;
1114 }
1115
1116 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
1117 {
1118     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1119     FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
1120     return E_NOTIMPL;
1121 }
1122
1123 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
1124 {
1125     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1126     FIXME("stub - %p (%s)\n", This, debugstr_w(pszDefaultExtension));
1127     return E_NOTIMPL;
1128 }
1129
1130 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
1131 {
1132     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1133     TRACE("%p (0x%08x)\n", This, hr);
1134
1135     if(This->dlg_hwnd)
1136         EndDialog(This->dlg_hwnd, hr);
1137
1138     return S_OK;
1139 }
1140
1141 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
1142 {
1143     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1144     FIXME("stub - %p (%s)\n", This, debugstr_guid(guid));
1145     return E_NOTIMPL;
1146 }
1147
1148 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
1149 {
1150     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1151     FIXME("stub - %p\n", This);
1152     return E_NOTIMPL;
1153 }
1154
1155 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
1156 {
1157     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1158     FIXME("stub - %p (%p)\n", This, pFilter);
1159     return E_NOTIMPL;
1160 }
1161
1162 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
1163 {
1164     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1165     FIXME("stub - %p (%s)\n", This, debugstr_w(pszLabel));
1166     return E_NOTIMPL;
1167 }
1168
1169 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
1170 {
1171     FileDialogImpl *This = impl_from_IFileDialog2(iface);
1172     FIXME("stub - %p (%p)\n", This, psi);
1173     return E_NOTIMPL;
1174 }
1175
1176 static const IFileDialog2Vtbl vt_IFileDialog2 = {
1177     IFileDialog2_fnQueryInterface,
1178     IFileDialog2_fnAddRef,
1179     IFileDialog2_fnRelease,
1180     IFileDialog2_fnShow,
1181     IFileDialog2_fnSetFileTypes,
1182     IFileDialog2_fnSetFileTypeIndex,
1183     IFileDialog2_fnGetFileTypeIndex,
1184     IFileDialog2_fnAdvise,
1185     IFileDialog2_fnUnadvise,
1186     IFileDialog2_fnSetOptions,
1187     IFileDialog2_fnGetOptions,
1188     IFileDialog2_fnSetDefaultFolder,
1189     IFileDialog2_fnSetFolder,
1190     IFileDialog2_fnGetFolder,
1191     IFileDialog2_fnGetCurrentSelection,
1192     IFileDialog2_fnSetFileName,
1193     IFileDialog2_fnGetFileName,
1194     IFileDialog2_fnSetTitle,
1195     IFileDialog2_fnSetOkButtonLabel,
1196     IFileDialog2_fnSetFileNameLabel,
1197     IFileDialog2_fnGetResult,
1198     IFileDialog2_fnAddPlace,
1199     IFileDialog2_fnSetDefaultExtension,
1200     IFileDialog2_fnClose,
1201     IFileDialog2_fnSetClientGuid,
1202     IFileDialog2_fnClearClientData,
1203     IFileDialog2_fnSetFilter,
1204     IFileDialog2_fnSetCancelButtonLabel,
1205     IFileDialog2_fnSetNavigationRoot
1206 };
1207
1208 /**************************************************************************
1209  * IFileOpenDialog
1210  */
1211 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
1212 {
1213     return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
1214 }
1215
1216 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
1217                                                        REFIID riid, void **ppvObject)
1218 {
1219     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1220     return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
1221 }
1222
1223 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
1224 {
1225     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1226     return IFileDialog2_AddRef(&This->IFileDialog2_iface);
1227 }
1228
1229 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
1230 {
1231     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1232     return IFileDialog2_Release(&This->IFileDialog2_iface);
1233 }
1234
1235 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
1236 {
1237     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1238     return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
1239 }
1240
1241 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
1242                                                      const COMDLG_FILTERSPEC *rgFilterSpec)
1243 {
1244     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1245     return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
1246 }
1247
1248 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
1249 {
1250     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1251     return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
1252 }
1253
1254 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
1255 {
1256     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1257     return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
1258 }
1259
1260 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
1261                                                DWORD *pdwCookie)
1262 {
1263     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1264     return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
1265 }
1266
1267 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
1268 {
1269     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1270     return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
1271 }
1272
1273 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
1274 {
1275     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1276     return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
1277 }
1278
1279 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
1280 {
1281     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1282     return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
1283 }
1284
1285 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
1286 {
1287     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1288     return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
1289 }
1290
1291 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
1292 {
1293     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1294     return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
1295 }
1296
1297 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
1298 {
1299     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1300     return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
1301 }
1302
1303 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
1304 {
1305     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1306     return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
1307 }
1308
1309 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
1310 {
1311     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1312     return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
1313 }
1314
1315 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
1316 {
1317     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1318     return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
1319 }
1320
1321 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
1322 {
1323     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1324     return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
1325 }
1326
1327 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
1328 {
1329     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1330     return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
1331 }
1332
1333 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
1334 {
1335     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1336     return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
1337 }
1338
1339 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
1340 {
1341     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1342     return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
1343 }
1344
1345 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
1346 {
1347     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1348     return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
1349 }
1350
1351 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
1352                                                             LPCWSTR pszDefaultExtension)
1353 {
1354     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1355     return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
1356 }
1357
1358 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
1359 {
1360     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1361     return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
1362 }
1363
1364 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
1365 {
1366     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1367     return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
1368 }
1369
1370 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
1371 {
1372     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1373     return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
1374 }
1375
1376 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
1377 {
1378     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1379     return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
1380 }
1381
1382 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
1383 {
1384     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1385     TRACE("%p (%p)\n", This, ppenum);
1386
1387     *ppenum = This->psia_results;
1388
1389     if(*ppenum)
1390     {
1391         IShellItemArray_AddRef(*ppenum);
1392         return S_OK;
1393     }
1394
1395     return E_FAIL;
1396 }
1397
1398 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
1399 {
1400     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
1401     TRACE("%p (%p)\n", This, ppsai);
1402
1403     if(This->psia_selection)
1404     {
1405         *ppsai = This->psia_selection;
1406         IShellItemArray_AddRef(*ppsai);
1407         return S_OK;
1408     }
1409
1410     return E_FAIL;
1411 }
1412
1413 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
1414     IFileOpenDialog_fnQueryInterface,
1415     IFileOpenDialog_fnAddRef,
1416     IFileOpenDialog_fnRelease,
1417     IFileOpenDialog_fnShow,
1418     IFileOpenDialog_fnSetFileTypes,
1419     IFileOpenDialog_fnSetFileTypeIndex,
1420     IFileOpenDialog_fnGetFileTypeIndex,
1421     IFileOpenDialog_fnAdvise,
1422     IFileOpenDialog_fnUnadvise,
1423     IFileOpenDialog_fnSetOptions,
1424     IFileOpenDialog_fnGetOptions,
1425     IFileOpenDialog_fnSetDefaultFolder,
1426     IFileOpenDialog_fnSetFolder,
1427     IFileOpenDialog_fnGetFolder,
1428     IFileOpenDialog_fnGetCurrentSelection,
1429     IFileOpenDialog_fnSetFileName,
1430     IFileOpenDialog_fnGetFileName,
1431     IFileOpenDialog_fnSetTitle,
1432     IFileOpenDialog_fnSetOkButtonLabel,
1433     IFileOpenDialog_fnSetFileNameLabel,
1434     IFileOpenDialog_fnGetResult,
1435     IFileOpenDialog_fnAddPlace,
1436     IFileOpenDialog_fnSetDefaultExtension,
1437     IFileOpenDialog_fnClose,
1438     IFileOpenDialog_fnSetClientGuid,
1439     IFileOpenDialog_fnClearClientData,
1440     IFileOpenDialog_fnSetFilter,
1441     IFileOpenDialog_fnGetResults,
1442     IFileOpenDialog_fnGetSelectedItems
1443 };
1444
1445 /**************************************************************************
1446  * IFileSaveDialog
1447  */
1448 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
1449 {
1450     return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
1451 }
1452
1453 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
1454                                                        REFIID riid,
1455                                                        void **ppvObject)
1456 {
1457     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1458     return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
1459 }
1460
1461 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
1462 {
1463     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1464     return IFileDialog2_AddRef(&This->IFileDialog2_iface);
1465 }
1466
1467 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
1468 {
1469     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1470     return IFileDialog2_Release(&This->IFileDialog2_iface);
1471 }
1472
1473 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
1474 {
1475     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1476     return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
1477 }
1478
1479 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
1480                                                      const COMDLG_FILTERSPEC *rgFilterSpec)
1481 {
1482     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1483     return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
1484 }
1485
1486 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
1487 {
1488     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1489     return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
1490 }
1491
1492 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
1493 {
1494     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1495     return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
1496 }
1497
1498 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
1499                                                DWORD *pdwCookie)
1500 {
1501     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1502     return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
1503 }
1504
1505 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
1506 {
1507     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1508     return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
1509 }
1510
1511 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
1512 {
1513     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1514     return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
1515 }
1516
1517 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
1518 {
1519     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1520     return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
1521 }
1522
1523 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
1524 {
1525     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1526     return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
1527 }
1528
1529 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
1530 {
1531     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1532     return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
1533 }
1534
1535 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
1536 {
1537     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1538     return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
1539 }
1540
1541 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
1542 {
1543     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1544     return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
1545 }
1546
1547 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
1548 {
1549     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1550     return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
1551 }
1552
1553 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
1554 {
1555     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1556     return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
1557 }
1558
1559 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
1560 {
1561     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1562     return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
1563 }
1564
1565 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
1566 {
1567     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1568     return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
1569 }
1570
1571 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
1572 {
1573     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1574     return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
1575 }
1576
1577 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
1578 {
1579     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1580     return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
1581 }
1582
1583 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
1584 {
1585     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1586     return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
1587 }
1588
1589 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
1590                                                             LPCWSTR pszDefaultExtension)
1591 {
1592     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1593     return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
1594 }
1595
1596 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
1597 {
1598     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1599     return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
1600 }
1601
1602 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
1603 {
1604     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1605     return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
1606 }
1607
1608 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
1609 {
1610     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1611     return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
1612 }
1613
1614 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
1615 {
1616     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1617     return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
1618 }
1619
1620 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
1621 {
1622     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1623     FIXME("stub - %p (%p)\n", This, psi);
1624     return E_NOTIMPL;
1625 }
1626
1627 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
1628 {
1629     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1630     FIXME("stub - %p (%p)\n", This, pStore);
1631     return E_NOTIMPL;
1632 }
1633
1634 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
1635                                                                IPropertyDescriptionList *pList,
1636                                                                BOOL fAppendDefault)
1637 {
1638     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1639     FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
1640     return E_NOTIMPL;
1641 }
1642
1643 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
1644 {
1645     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1646     FIXME("stub - %p (%p)\n", This, ppStore);
1647     return E_NOTIMPL;
1648 }
1649
1650 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
1651                                                         IShellItem *psi,
1652                                                         IPropertyStore *pStore,
1653                                                         HWND hwnd,
1654                                                         IFileOperationProgressSink *pSink)
1655 {
1656     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
1657     FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
1658     return E_NOTIMPL;
1659 }
1660
1661 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
1662     IFileSaveDialog_fnQueryInterface,
1663     IFileSaveDialog_fnAddRef,
1664     IFileSaveDialog_fnRelease,
1665     IFileSaveDialog_fnShow,
1666     IFileSaveDialog_fnSetFileTypes,
1667     IFileSaveDialog_fnSetFileTypeIndex,
1668     IFileSaveDialog_fnGetFileTypeIndex,
1669     IFileSaveDialog_fnAdvise,
1670     IFileSaveDialog_fnUnadvise,
1671     IFileSaveDialog_fnSetOptions,
1672     IFileSaveDialog_fnGetOptions,
1673     IFileSaveDialog_fnSetDefaultFolder,
1674     IFileSaveDialog_fnSetFolder,
1675     IFileSaveDialog_fnGetFolder,
1676     IFileSaveDialog_fnGetCurrentSelection,
1677     IFileSaveDialog_fnSetFileName,
1678     IFileSaveDialog_fnGetFileName,
1679     IFileSaveDialog_fnSetTitle,
1680     IFileSaveDialog_fnSetOkButtonLabel,
1681     IFileSaveDialog_fnSetFileNameLabel,
1682     IFileSaveDialog_fnGetResult,
1683     IFileSaveDialog_fnAddPlace,
1684     IFileSaveDialog_fnSetDefaultExtension,
1685     IFileSaveDialog_fnClose,
1686     IFileSaveDialog_fnSetClientGuid,
1687     IFileSaveDialog_fnClearClientData,
1688     IFileSaveDialog_fnSetFilter,
1689     IFileSaveDialog_fnSetSaveAsItem,
1690     IFileSaveDialog_fnSetProperties,
1691     IFileSaveDialog_fnSetCollectedProperties,
1692     IFileSaveDialog_fnGetProperties,
1693     IFileSaveDialog_fnApplyProperties
1694 };
1695
1696 /**************************************************************************
1697  * IExplorerBrowserEvents implementation
1698  */
1699 static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
1700 {
1701     return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
1702 }
1703
1704 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
1705                                                               REFIID riid, void **ppvObject)
1706 {
1707     FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
1708     TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
1709
1710     return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
1711 }
1712
1713 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
1714 {
1715     FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
1716     TRACE("%p\n", This);
1717     return IFileDialog2_AddRef(&This->IFileDialog2_iface);
1718 }
1719
1720 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
1721 {
1722     FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
1723     TRACE("%p\n", This);
1724     return IFileDialog2_Release(&This->IFileDialog2_iface);
1725 }
1726
1727 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
1728                                                                    PCIDLIST_ABSOLUTE pidlFolder)
1729 {
1730     FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
1731     TRACE("%p (%p)\n", This, pidlFolder);
1732     return S_OK;
1733 }
1734
1735 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
1736                                                              IShellView *psv)
1737 {
1738     FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
1739     TRACE("%p (%p)\n", This, psv);
1740     return S_OK;
1741 }
1742
1743 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
1744                                                                     PCIDLIST_ABSOLUTE pidlFolder)
1745 {
1746     FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
1747     HRESULT hr;
1748     TRACE("%p (%p)\n", This, pidlFolder);
1749
1750     if(This->psi_folder)
1751         IShellItem_Release(This->psi_folder);
1752
1753     hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
1754     if(FAILED(hr))
1755     {
1756         ERR("Failed to get the current folder.\n");
1757         This->psi_folder = NULL;
1758     }
1759
1760     return S_OK;
1761 }
1762
1763 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
1764                                                                   PCIDLIST_ABSOLUTE pidlFolder)
1765 {
1766     FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
1767     TRACE("%p (%p)\n", This, pidlFolder);
1768     return S_OK;
1769 }
1770
1771 static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
1772     IExplorerBrowserEvents_fnQueryInterface,
1773     IExplorerBrowserEvents_fnAddRef,
1774     IExplorerBrowserEvents_fnRelease,
1775     IExplorerBrowserEvents_fnOnNavigationPending,
1776     IExplorerBrowserEvents_fnOnViewCreated,
1777     IExplorerBrowserEvents_fnOnNavigationComplete,
1778     IExplorerBrowserEvents_fnOnNavigationFailed
1779 };
1780
1781 /**************************************************************************
1782  * IServiceProvider implementation
1783  */
1784 static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
1785 {
1786     return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
1787 }
1788
1789 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
1790                                                         REFIID riid, void **ppvObject)
1791 {
1792     FileDialogImpl *This = impl_from_IServiceProvider(iface);
1793     TRACE("%p\n", This);
1794     return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
1795 }
1796
1797 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
1798 {
1799     FileDialogImpl *This = impl_from_IServiceProvider(iface);
1800     TRACE("%p\n", This);
1801     return IFileDialog2_AddRef(&This->IFileDialog2_iface);
1802 }
1803
1804 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
1805 {
1806     FileDialogImpl *This = impl_from_IServiceProvider(iface);
1807     TRACE("%p\n", This);
1808     return IFileDialog2_Release(&This->IFileDialog2_iface);
1809 }
1810
1811 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
1812                                                       REFGUID guidService,
1813                                                       REFIID riid, void **ppv)
1814 {
1815     FileDialogImpl *This = impl_from_IServiceProvider(iface);
1816     HRESULT hr = E_FAIL;
1817     TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1818
1819     *ppv = NULL;
1820     if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
1821         hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
1822     else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
1823         hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
1824     else
1825         FIXME("Interface %s requested from unknown service %s\n",
1826               debugstr_guid(riid), debugstr_guid(guidService));
1827
1828     if(SUCCEEDED(hr) && *ppv)
1829     {
1830         IUnknown_AddRef((IUnknown*)*ppv);
1831         return S_OK;
1832     }
1833
1834     return E_FAIL;
1835 }
1836
1837 static const IServiceProviderVtbl vt_IServiceProvider = {
1838     IServiceProvider_fnQueryInterface,
1839     IServiceProvider_fnAddRef,
1840     IServiceProvider_fnRelease,
1841     IServiceProvider_fnQueryService
1842 };
1843
1844 /**************************************************************************
1845  * ICommDlgBrowser3 implementation
1846  */
1847 static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
1848 {
1849     return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
1850 }
1851
1852 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
1853                                                         REFIID riid, void **ppvObject)
1854 {
1855     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
1856     TRACE("%p\n", This);
1857     return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
1858 }
1859
1860 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
1861 {
1862     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
1863     TRACE("%p\n", This);
1864     return IFileDialog2_AddRef(&This->IFileDialog2_iface);
1865 }
1866
1867 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
1868 {
1869     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
1870     TRACE("%p\n", This);
1871     return IFileDialog2_Release(&This->IFileDialog2_iface);
1872 }
1873
1874 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
1875                                                           IShellView *shv)
1876 {
1877     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
1878     HRESULT hr;
1879     TRACE("%p (%p)\n", This, shv);
1880
1881     hr = on_default_action(This);
1882
1883     if(SUCCEEDED(hr))
1884         EndDialog(This->dlg_hwnd, S_OK);
1885
1886     return S_OK;
1887 }
1888
1889 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
1890                                                        IShellView *shv, ULONG uChange )
1891 {
1892     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
1893     IDataObject *new_selection;
1894     HRESULT hr;
1895     TRACE("%p (%p, %x)\n", This, shv, uChange);
1896
1897     switch(uChange)
1898     {
1899     case CDBOSC_SELCHANGE:
1900         if(This->psia_selection)
1901         {
1902             IShellItemArray_Release(This->psia_selection);
1903             This->psia_selection = NULL;
1904         }
1905
1906         hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
1907         if(SUCCEEDED(hr))
1908         {
1909             hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
1910                                                       (void**)&This->psia_selection);
1911             if(SUCCEEDED(hr))
1912                 fill_filename_from_selection(This);
1913
1914             IDataObject_Release(new_selection);
1915         }
1916         break;
1917     default:
1918         TRACE("Unhandled state change\n");
1919     }
1920     return S_OK;
1921 }
1922
1923 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
1924                                                        IShellView *shv, LPCITEMIDLIST pidl)
1925 {
1926     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
1927     IShellItem *psi;
1928     LPWSTR filename;
1929     LPITEMIDLIST parent_pidl;
1930     HRESULT hr;
1931     ULONG attr;
1932     TRACE("%p (%p, %p)\n", This, shv, pidl);
1933
1934     if(!This->filterspec_count)
1935         return S_OK;
1936
1937     hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
1938     if(SUCCEEDED(hr))
1939     {
1940         LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
1941         hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
1942         ILFree(parent_pidl);
1943         ILFree(full_pidl);
1944     }
1945     if(FAILED(hr))
1946     {
1947         ERR("Failed to get shellitem (%08x).\n", hr);
1948         return S_OK;
1949     }
1950
1951     hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
1952     if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
1953     {
1954         IShellItem_Release(psi);
1955         return S_OK;
1956     }
1957
1958     hr = S_OK;
1959     if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
1960     {
1961         if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
1962             hr = S_FALSE;
1963         CoTaskMemFree(filename);
1964     }
1965
1966     IShellItem_Release(psi);
1967     return hr;
1968 }
1969
1970 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
1971                                                 IShellView *ppshv, DWORD dwNotifyType)
1972 {
1973     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
1974     FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
1975     return E_NOTIMPL;
1976 }
1977
1978 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
1979                                                             IShellView *pshv,
1980                                                             LPWSTR pszText, int cchMax)
1981 {
1982     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
1983     FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
1984     return E_NOTIMPL;
1985 }
1986
1987 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
1988 {
1989     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
1990     FIXME("Stub: %p (%p)\n", This, pdwFlags);
1991     return E_NOTIMPL;
1992 }
1993
1994 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
1995                                                          IShellView *pshv, int iColumn)
1996 {
1997     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
1998     FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
1999     return E_NOTIMPL;
2000 }
2001
2002 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
2003                                                           LPWSTR pszFileSpec, int cchFileSpec)
2004 {
2005     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2006     FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
2007     return E_NOTIMPL;
2008 }
2009
2010 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
2011                                                           IShellView *pshv)
2012 {
2013     FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
2014     FIXME("Stub: %p (%p)\n", This, pshv);
2015     return E_NOTIMPL;
2016 }
2017
2018 static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
2019     ICommDlgBrowser3_fnQueryInterface,
2020     ICommDlgBrowser3_fnAddRef,
2021     ICommDlgBrowser3_fnRelease,
2022     ICommDlgBrowser3_fnOnDefaultCommand,
2023     ICommDlgBrowser3_fnOnStateChange,
2024     ICommDlgBrowser3_fnIncludeObject,
2025     ICommDlgBrowser3_fnNotify,
2026     ICommDlgBrowser3_fnGetDefaultMenuText,
2027     ICommDlgBrowser3_fnGetViewFlags,
2028     ICommDlgBrowser3_fnOnColumnClicked,
2029     ICommDlgBrowser3_fnGetCurrentFilter,
2030     ICommDlgBrowser3_fnOnPreviewCreated
2031 };
2032
2033 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
2034 {
2035     FileDialogImpl *fdimpl;
2036     HRESULT hr;
2037     IShellFolder *psf;
2038     TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
2039
2040     if(!ppv)
2041         return E_POINTER;
2042     if(pUnkOuter)
2043         return CLASS_E_NOAGGREGATION;
2044
2045     fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
2046     if(!fdimpl)
2047         return E_OUTOFMEMORY;
2048
2049     fdimpl->ref = 1;
2050     fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
2051     fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
2052     fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
2053     fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
2054
2055     if(type == ITEMDLG_TYPE_OPEN)
2056     {
2057         fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
2058         fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
2059         fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
2060     }
2061     else
2062     {
2063         fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
2064         fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
2065         fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
2066     }
2067
2068     fdimpl->filterspecs = NULL;
2069     fdimpl->filterspec_count = 0;
2070     fdimpl->filetypeindex = 0;
2071
2072     fdimpl->psia_selection = fdimpl->psia_results = NULL;
2073     fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
2074
2075     list_init(&fdimpl->events_clients);
2076     fdimpl->events_next_cookie = 0;
2077
2078     fdimpl->dlg_hwnd = NULL;
2079     fdimpl->peb = NULL;
2080
2081     fdimpl->set_filename = NULL;
2082
2083     /* FIXME: The default folder setting should be restored for the
2084      * application if it was previously set. */
2085     SHGetDesktopFolder(&psf);
2086     SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
2087     IShellFolder_Release(psf);
2088
2089     hr = IUnknown_QueryInterface((IUnknown*)fdimpl, riid, ppv);
2090     IUnknown_Release((IUnknown*)fdimpl);
2091     return hr;
2092 }
2093
2094 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
2095 {
2096     return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
2097 }
2098
2099 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
2100 {
2101     return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);
2102 }