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