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