comdlg32: Implement some folder and file selection functions for the Item Dialog.
[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
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
40
41 enum ITEMDLG_TYPE {
42     ITEMDLG_TYPE_OPEN,
43     ITEMDLG_TYPE_SAVE
44 };
45
46 typedef struct FileDialogImpl {
47     IFileDialog2 IFileDialog2_iface;
48     union {
49         IFileOpenDialog IFileOpenDialog_iface;
50         IFileSaveDialog IFileSaveDialog_iface;
51     } u;
52     enum ITEMDLG_TYPE dlg_type;
53     LONG ref;
54
55     FILEOPENDIALOGOPTIONS options;
56     COMDLG_FILTERSPEC *filterspecs;
57     UINT filterspec_count;
58     UINT filetypeindex;
59
60     IShellItemArray *psia_selection;
61     IShellItemArray *psia_results;
62     IShellItem *psi_defaultfolder;
63     IShellItem *psi_setfolder;
64     IShellItem *psi_folder;
65 } FileDialogImpl;
66
67 /**************************************************************************
68  * IFileDialog implementation
69  */
70 static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
71 {
72     return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
73 }
74
75 static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
76                                                     REFIID riid,
77                                                     void **ppvObject)
78 {
79     FileDialogImpl *This = impl_from_IFileDialog2(iface);
80     TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
81
82     *ppvObject = NULL;
83     if(IsEqualGUID(riid, &IID_IUnknown) ||
84        IsEqualGUID(riid, &IID_IFileDialog) ||
85        IsEqualGUID(riid, &IID_IFileDialog2))
86     {
87         *ppvObject = iface;
88     }
89     else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
90     {
91         *ppvObject = &This->u.IFileOpenDialog_iface;
92     }
93     else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
94     {
95         *ppvObject = &This->u.IFileSaveDialog_iface;
96     }
97     else
98         FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
99
100     if(*ppvObject)
101     {
102         IUnknown_AddRef((IUnknown*)*ppvObject);
103         return S_OK;
104     }
105
106     return E_NOINTERFACE;
107 }
108
109 static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
110 {
111     FileDialogImpl *This = impl_from_IFileDialog2(iface);
112     LONG ref = InterlockedIncrement(&This->ref);
113     TRACE("%p - ref %d\n", This, ref);
114
115     return ref;
116 }
117
118 static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
119 {
120     FileDialogImpl *This = impl_from_IFileDialog2(iface);
121     LONG ref = InterlockedDecrement(&This->ref);
122     TRACE("%p - ref %d\n", This, ref);
123
124     if(!ref)
125     {
126         UINT i;
127         for(i = 0; i < This->filterspec_count; i++)
128         {
129             LocalFree((void*)This->filterspecs[i].pszName);
130             LocalFree((void*)This->filterspecs[i].pszSpec);
131         }
132         HeapFree(GetProcessHeap(), 0, This->filterspecs);
133
134         if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
135         if(This->psi_setfolder)     IShellItem_Release(This->psi_setfolder);
136         if(This->psi_folder)        IShellItem_Release(This->psi_folder);
137         if(This->psia_selection)    IShellItemArray_Release(This->psia_selection);
138         if(This->psia_results)      IShellItemArray_Release(This->psia_results);
139
140         HeapFree(GetProcessHeap(), 0, This);
141     }
142
143     return ref;
144 }
145
146 static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
147 {
148     FileDialogImpl *This = impl_from_IFileDialog2(iface);
149     FIXME("stub - %p (%p)\n", This, hwndOwner);
150     return E_NOTIMPL;
151 }
152
153 static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
154                                                   const COMDLG_FILTERSPEC *rgFilterSpec)
155 {
156     FileDialogImpl *This = impl_from_IFileDialog2(iface);
157     UINT i;
158     TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
159
160     if(This->filterspecs)
161         return E_UNEXPECTED;
162
163     if(!rgFilterSpec)
164         return E_INVALIDARG;
165
166     if(!cFileTypes)
167         return S_OK;
168
169     This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
170     for(i = 0; i < cFileTypes; i++)
171     {
172         This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
173         This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
174     }
175     This->filterspec_count = cFileTypes;
176
177     return S_OK;
178 }
179
180 static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
181 {
182     FileDialogImpl *This = impl_from_IFileDialog2(iface);
183     TRACE("%p (%d)\n", This, iFileType);
184
185     if(!This->filterspecs)
186         return E_FAIL;
187
188     if(iFileType >= This->filterspec_count)
189         This->filetypeindex = This->filterspec_count - 1;
190     else
191         This->filetypeindex = iFileType;
192
193     return S_OK;
194 }
195
196 static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
197 {
198     FileDialogImpl *This = impl_from_IFileDialog2(iface);
199     TRACE("%p (%p)\n", This, piFileType);
200
201     if(!piFileType)
202         return E_INVALIDARG;
203
204     *piFileType = This->filetypeindex;
205
206     return S_OK;
207 }
208
209 static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
210 {
211     FileDialogImpl *This = impl_from_IFileDialog2(iface);
212     FIXME("stub - %p (%p, %p)\n", This, pfde, pdwCookie);
213     return E_NOTIMPL;
214 }
215
216 static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
217 {
218     FileDialogImpl *This = impl_from_IFileDialog2(iface);
219     FIXME("stub - %p (%d)\n", This, dwCookie);
220     return E_NOTIMPL;
221 }
222
223 static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
224 {
225     FileDialogImpl *This = impl_from_IFileDialog2(iface);
226     TRACE("%p (0x%x)\n", This, fos);
227
228     This->options = fos;
229
230     return S_OK;
231 }
232
233 static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
234 {
235     FileDialogImpl *This = impl_from_IFileDialog2(iface);
236     TRACE("%p (%p)\n", This, pfos);
237
238     if(!pfos)
239         return E_INVALIDARG;
240
241     *pfos = This->options;
242
243     return S_OK;
244 }
245
246 static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
247 {
248     FileDialogImpl *This = impl_from_IFileDialog2(iface);
249     TRACE("%p (%p)\n", This, psi);
250     if(This->psi_defaultfolder)
251         IShellItem_Release(This->psi_defaultfolder);
252
253     This->psi_defaultfolder = psi;
254
255     if(This->psi_defaultfolder)
256         IShellItem_AddRef(This->psi_defaultfolder);
257
258     return S_OK;
259 }
260
261 static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
262 {
263     FileDialogImpl *This = impl_from_IFileDialog2(iface);
264     TRACE("%p (%p)\n", This, psi);
265     if(This->psi_setfolder)
266         IShellItem_Release(This->psi_setfolder);
267
268     This->psi_setfolder = psi;
269
270     if(This->psi_setfolder)
271         IShellItem_AddRef(This->psi_setfolder);
272
273     return S_OK;
274 }
275
276 static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
277 {
278     FileDialogImpl *This = impl_from_IFileDialog2(iface);
279     TRACE("%p (%p)\n", This, ppsi);
280     if(!ppsi)
281         return E_INVALIDARG;
282
283     /* FIXME:
284        If the dialog is shown, return the current(ly selected) folder. */
285
286     *ppsi = NULL;
287     if(This->psi_folder)
288         *ppsi = This->psi_folder;
289     else if(This->psi_setfolder)
290         *ppsi = This->psi_setfolder;
291     else if(This->psi_defaultfolder)
292         *ppsi = This->psi_defaultfolder;
293
294     if(*ppsi)
295     {
296         IShellItem_AddRef(*ppsi);
297         return S_OK;
298     }
299
300     return E_FAIL;
301 }
302
303 static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
304 {
305     FileDialogImpl *This = impl_from_IFileDialog2(iface);
306     HRESULT hr;
307     TRACE("%p (%p)\n", This, ppsi);
308
309     if(!ppsi)
310         return E_INVALIDARG;
311
312     if(This->psia_selection)
313     {
314         /* FIXME: Check filename edit box */
315         hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
316         return hr;
317     }
318
319     return E_FAIL;
320 }
321
322 static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
323 {
324     FileDialogImpl *This = impl_from_IFileDialog2(iface);
325     FIXME("stub - %p (%p)\n", This, pszName);
326     return E_NOTIMPL;
327 }
328
329 static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
330 {
331     FileDialogImpl *This = impl_from_IFileDialog2(iface);
332     FIXME("stub - %p (%p)\n", This, pszName);
333     return E_NOTIMPL;
334 }
335
336 static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
337 {
338     FileDialogImpl *This = impl_from_IFileDialog2(iface);
339     FIXME("stub - %p (%p)\n", This, pszTitle);
340     return E_NOTIMPL;
341 }
342
343 static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
344 {
345     FileDialogImpl *This = impl_from_IFileDialog2(iface);
346     FIXME("stub - %p (%p)\n", This, pszText);
347     return E_NOTIMPL;
348 }
349
350 static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
351 {
352     FileDialogImpl *This = impl_from_IFileDialog2(iface);
353     FIXME("stub - %p (%p)\n", This, pszLabel);
354     return E_NOTIMPL;
355 }
356
357 static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
358 {
359     FileDialogImpl *This = impl_from_IFileDialog2(iface);
360     HRESULT hr;
361     TRACE("%p (%p)\n", This, ppsi);
362
363     if(!ppsi)
364         return E_INVALIDARG;
365
366     if(This->psia_results)
367     {
368         UINT item_count;
369         hr = IShellItemArray_GetCount(This->psia_results, &item_count);
370         if(SUCCEEDED(hr))
371         {
372             if(item_count != 1)
373                 return E_FAIL;
374
375             /* Adds a reference. */
376             hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
377         }
378
379         return hr;
380     }
381
382     return E_UNEXPECTED;
383 }
384
385 static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
386 {
387     FileDialogImpl *This = impl_from_IFileDialog2(iface);
388     FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
389     return E_NOTIMPL;
390 }
391
392 static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
393 {
394     FileDialogImpl *This = impl_from_IFileDialog2(iface);
395     FIXME("stub - %p (%s)\n", This, debugstr_w(pszDefaultExtension));
396     return E_NOTIMPL;
397 }
398
399 static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
400 {
401     FileDialogImpl *This = impl_from_IFileDialog2(iface);
402     FIXME("stub - %p (0x%08x)\n", This, hr);
403     return E_NOTIMPL;
404 }
405
406 static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
407 {
408     FileDialogImpl *This = impl_from_IFileDialog2(iface);
409     FIXME("stub - %p (%s)\n", This, debugstr_guid(guid));
410     return E_NOTIMPL;
411 }
412
413 static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
414 {
415     FileDialogImpl *This = impl_from_IFileDialog2(iface);
416     FIXME("stub - %p\n", This);
417     return E_NOTIMPL;
418 }
419
420 static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
421 {
422     FileDialogImpl *This = impl_from_IFileDialog2(iface);
423     FIXME("stub - %p (%p)\n", This, pFilter);
424     return E_NOTIMPL;
425 }
426
427 static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
428 {
429     FileDialogImpl *This = impl_from_IFileDialog2(iface);
430     FIXME("stub - %p (%s)\n", This, debugstr_w(pszLabel));
431     return E_NOTIMPL;
432 }
433
434 static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
435 {
436     FileDialogImpl *This = impl_from_IFileDialog2(iface);
437     FIXME("stub - %p (%p)\n", This, psi);
438     return E_NOTIMPL;
439 }
440
441 static const IFileDialog2Vtbl vt_IFileDialog2 = {
442     IFileDialog2_fnQueryInterface,
443     IFileDialog2_fnAddRef,
444     IFileDialog2_fnRelease,
445     IFileDialog2_fnShow,
446     IFileDialog2_fnSetFileTypes,
447     IFileDialog2_fnSetFileTypeIndex,
448     IFileDialog2_fnGetFileTypeIndex,
449     IFileDialog2_fnAdvise,
450     IFileDialog2_fnUnadvise,
451     IFileDialog2_fnSetOptions,
452     IFileDialog2_fnGetOptions,
453     IFileDialog2_fnSetDefaultFolder,
454     IFileDialog2_fnSetFolder,
455     IFileDialog2_fnGetFolder,
456     IFileDialog2_fnGetCurrentSelection,
457     IFileDialog2_fnSetFileName,
458     IFileDialog2_fnGetFileName,
459     IFileDialog2_fnSetTitle,
460     IFileDialog2_fnSetOkButtonLabel,
461     IFileDialog2_fnSetFileNameLabel,
462     IFileDialog2_fnGetResult,
463     IFileDialog2_fnAddPlace,
464     IFileDialog2_fnSetDefaultExtension,
465     IFileDialog2_fnClose,
466     IFileDialog2_fnSetClientGuid,
467     IFileDialog2_fnClearClientData,
468     IFileDialog2_fnSetFilter,
469     IFileDialog2_fnSetCancelButtonLabel,
470     IFileDialog2_fnSetNavigationRoot
471 };
472
473 /**************************************************************************
474  * IFileOpenDialog
475  */
476 static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
477 {
478     return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
479 }
480
481 static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
482                                                        REFIID riid, void **ppvObject)
483 {
484     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
485     return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
486 }
487
488 static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
489 {
490     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
491     return IFileDialog2_AddRef(&This->IFileDialog2_iface);
492 }
493
494 static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
495 {
496     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
497     return IFileDialog2_Release(&This->IFileDialog2_iface);
498 }
499
500 static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
501 {
502     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
503     return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
504 }
505
506 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
507                                                      const COMDLG_FILTERSPEC *rgFilterSpec)
508 {
509     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
510     return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
511 }
512
513 static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
514 {
515     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
516     return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
517 }
518
519 static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
520 {
521     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
522     return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
523 }
524
525 static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
526                                                DWORD *pdwCookie)
527 {
528     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
529     return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
530 }
531
532 static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
533 {
534     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
535     return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
536 }
537
538 static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
539 {
540     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
541     return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
542 }
543
544 static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
545 {
546     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
547     return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
548 }
549
550 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
551 {
552     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
553     return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
554 }
555
556 static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
557 {
558     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
559     return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
560 }
561
562 static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
563 {
564     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
565     return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
566 }
567
568 static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
569 {
570     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
571     return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
572 }
573
574 static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
575 {
576     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
577     return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
578 }
579
580 static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
581 {
582     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
583     return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
584 }
585
586 static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
587 {
588     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
589     return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
590 }
591
592 static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
593 {
594     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
595     return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
596 }
597
598 static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
599 {
600     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
601     return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
602 }
603
604 static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
605 {
606     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
607     return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
608 }
609
610 static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
611 {
612     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
613     return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
614 }
615
616 static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
617                                                             LPCWSTR pszDefaultExtension)
618 {
619     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
620     return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
621 }
622
623 static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
624 {
625     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
626     return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
627 }
628
629 static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
630 {
631     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
632     return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
633 }
634
635 static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
636 {
637     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
638     return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
639 }
640
641 static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
642 {
643     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
644     return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
645 }
646
647 static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
648 {
649     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
650     TRACE("%p (%p)\n", This, ppenum);
651
652     *ppenum = This->psia_results;
653
654     if(*ppenum)
655     {
656         IShellItemArray_AddRef(*ppenum);
657         return S_OK;
658     }
659
660     return E_FAIL;
661 }
662
663 static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
664 {
665     FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
666     TRACE("%p (%p)\n", This, ppsai);
667
668     if(This->psia_selection)
669     {
670         *ppsai = This->psia_selection;
671         IShellItemArray_AddRef(*ppsai);
672         return S_OK;
673     }
674
675     return E_FAIL;
676 }
677
678 static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
679     IFileOpenDialog_fnQueryInterface,
680     IFileOpenDialog_fnAddRef,
681     IFileOpenDialog_fnRelease,
682     IFileOpenDialog_fnShow,
683     IFileOpenDialog_fnSetFileTypes,
684     IFileOpenDialog_fnSetFileTypeIndex,
685     IFileOpenDialog_fnGetFileTypeIndex,
686     IFileOpenDialog_fnAdvise,
687     IFileOpenDialog_fnUnadvise,
688     IFileOpenDialog_fnSetOptions,
689     IFileOpenDialog_fnGetOptions,
690     IFileOpenDialog_fnSetDefaultFolder,
691     IFileOpenDialog_fnSetFolder,
692     IFileOpenDialog_fnGetFolder,
693     IFileOpenDialog_fnGetCurrentSelection,
694     IFileOpenDialog_fnSetFileName,
695     IFileOpenDialog_fnGetFileName,
696     IFileOpenDialog_fnSetTitle,
697     IFileOpenDialog_fnSetOkButtonLabel,
698     IFileOpenDialog_fnSetFileNameLabel,
699     IFileOpenDialog_fnGetResult,
700     IFileOpenDialog_fnAddPlace,
701     IFileOpenDialog_fnSetDefaultExtension,
702     IFileOpenDialog_fnClose,
703     IFileOpenDialog_fnSetClientGuid,
704     IFileOpenDialog_fnClearClientData,
705     IFileOpenDialog_fnSetFilter,
706     IFileOpenDialog_fnGetResults,
707     IFileOpenDialog_fnGetSelectedItems
708 };
709
710 /**************************************************************************
711  * IFileSaveDialog
712  */
713 static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
714 {
715     return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
716 }
717
718 static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
719                                                        REFIID riid,
720                                                        void **ppvObject)
721 {
722     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
723     return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
724 }
725
726 static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
727 {
728     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
729     return IFileDialog2_AddRef(&This->IFileDialog2_iface);
730 }
731
732 static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
733 {
734     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
735     return IFileDialog2_Release(&This->IFileDialog2_iface);
736 }
737
738 static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
739 {
740     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
741     return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
742 }
743
744 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
745                                                      const COMDLG_FILTERSPEC *rgFilterSpec)
746 {
747     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
748     return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
749 }
750
751 static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
752 {
753     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
754     return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
755 }
756
757 static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
758 {
759     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
760     return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
761 }
762
763 static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
764                                                DWORD *pdwCookie)
765 {
766     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
767     return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
768 }
769
770 static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
771 {
772     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
773     return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
774 }
775
776 static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
777 {
778     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
779     return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
780 }
781
782 static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
783 {
784     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
785     return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
786 }
787
788 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
789 {
790     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
791     return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
792 }
793
794 static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
795 {
796     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
797     return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
798 }
799
800 static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
801 {
802     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
803     return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
804 }
805
806 static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
807 {
808     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
809     return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
810 }
811
812 static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
813 {
814     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
815     return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
816 }
817
818 static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
819 {
820     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
821     return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
822 }
823
824 static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
825 {
826     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
827     return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
828 }
829
830 static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
831 {
832     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
833     return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
834 }
835
836 static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
837 {
838     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
839     return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
840 }
841
842 static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
843 {
844     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
845     return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
846 }
847
848 static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
849 {
850     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
851     return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
852 }
853
854 static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
855                                                             LPCWSTR pszDefaultExtension)
856 {
857     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
858     return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
859 }
860
861 static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
862 {
863     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
864     return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
865 }
866
867 static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
868 {
869     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
870     return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
871 }
872
873 static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
874 {
875     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
876     return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
877 }
878
879 static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
880 {
881     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
882     return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
883 }
884
885 static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
886 {
887     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
888     FIXME("stub - %p (%p)\n", This, psi);
889     return E_NOTIMPL;
890 }
891
892 static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
893 {
894     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
895     FIXME("stub - %p (%p)\n", This, pStore);
896     return E_NOTIMPL;
897 }
898
899 static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
900                                                                IPropertyDescriptionList *pList,
901                                                                BOOL fAppendDefault)
902 {
903     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
904     FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
905     return E_NOTIMPL;
906 }
907
908 static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
909 {
910     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
911     FIXME("stub - %p (%p)\n", This, ppStore);
912     return E_NOTIMPL;
913 }
914
915 static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
916                                                         IShellItem *psi,
917                                                         IPropertyStore *pStore,
918                                                         HWND hwnd,
919                                                         IFileOperationProgressSink *pSink)
920 {
921     FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
922     FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
923     return E_NOTIMPL;
924 }
925
926 static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
927     IFileSaveDialog_fnQueryInterface,
928     IFileSaveDialog_fnAddRef,
929     IFileSaveDialog_fnRelease,
930     IFileSaveDialog_fnShow,
931     IFileSaveDialog_fnSetFileTypes,
932     IFileSaveDialog_fnSetFileTypeIndex,
933     IFileSaveDialog_fnGetFileTypeIndex,
934     IFileSaveDialog_fnAdvise,
935     IFileSaveDialog_fnUnadvise,
936     IFileSaveDialog_fnSetOptions,
937     IFileSaveDialog_fnGetOptions,
938     IFileSaveDialog_fnSetDefaultFolder,
939     IFileSaveDialog_fnSetFolder,
940     IFileSaveDialog_fnGetFolder,
941     IFileSaveDialog_fnGetCurrentSelection,
942     IFileSaveDialog_fnSetFileName,
943     IFileSaveDialog_fnGetFileName,
944     IFileSaveDialog_fnSetTitle,
945     IFileSaveDialog_fnSetOkButtonLabel,
946     IFileSaveDialog_fnSetFileNameLabel,
947     IFileSaveDialog_fnGetResult,
948     IFileSaveDialog_fnAddPlace,
949     IFileSaveDialog_fnSetDefaultExtension,
950     IFileSaveDialog_fnClose,
951     IFileSaveDialog_fnSetClientGuid,
952     IFileSaveDialog_fnClearClientData,
953     IFileSaveDialog_fnSetFilter,
954     IFileSaveDialog_fnSetSaveAsItem,
955     IFileSaveDialog_fnSetProperties,
956     IFileSaveDialog_fnSetCollectedProperties,
957     IFileSaveDialog_fnGetProperties,
958     IFileSaveDialog_fnApplyProperties
959 };
960
961 static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
962 {
963     FileDialogImpl *fdimpl;
964     HRESULT hr;
965     IShellFolder *psf;
966     TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
967
968     if(!ppv)
969         return E_POINTER;
970     if(pUnkOuter)
971         return CLASS_E_NOAGGREGATION;
972
973     fdimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(FileDialogImpl));
974     if(!fdimpl)
975         return E_OUTOFMEMORY;
976
977     fdimpl->ref = 1;
978     fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
979
980     if(type == ITEMDLG_TYPE_OPEN)
981     {
982         fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
983         fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
984         fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
985     }
986     else
987     {
988         fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
989         fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
990         fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
991     }
992
993     fdimpl->filterspecs = NULL;
994     fdimpl->filterspec_count = 0;
995     fdimpl->filetypeindex = 0;
996
997     fdimpl->psia_selection = fdimpl->psia_results = NULL;
998     fdimpl->psi_setfolder = fdimpl->psi_folder = NULL;
999
1000     /* FIXME: The default folder setting should be restored for the
1001      * application if it was previously set. */
1002     SHGetDesktopFolder(&psf);
1003     SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
1004     IShellFolder_Release(psf);
1005
1006     hr = IUnknown_QueryInterface((IUnknown*)fdimpl, riid, ppv);
1007     IUnknown_Release((IUnknown*)fdimpl);
1008     return hr;
1009 }
1010
1011 HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1012 {
1013     return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
1014 }
1015
1016 HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1017 {
1018     return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);
1019 }