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