PageRenderTime 87ms CodeModel.GetById 10ms app.highlight 71ms RepoModel.GetById 2ms app.codeStats 0ms

/Visual Studio 2008/CppShellCommonFileDialog/CppShellCommonFileDialog.cpp

#
C++ | 872 lines | 563 code | 114 blank | 195 comment | 87 complexity | 9a3fca2792b1f7fe118f85b7e05150ce MD5 | raw file
  1/************************************ Module Header ******************************\
  2Module Name:  CppShellCommonFileDialog.cpp
  3Project:      CppShellCommonFileDialog
  4Copyright (c) Microsoft Corporation.
  5
  6The code sample demos the use of shell common file dialogs.
  7
  8This source is subject to the Microsoft Public License.
  9See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
 10All other rights reserved.
 11
 12THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
 13EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF 
 14MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 15\**********************************************************************************/
 16
 17#pragma region Includes and Manifest Dependencies
 18#include <stdio.h>
 19#include <windows.h>
 20#include <windowsx.h>
 21#include <strsafe.h>
 22#include "Resource.h"
 23
 24#include <new>
 25#include <shlobj.h>
 26#include <shlwapi.h>
 27
 28// Enable Visual Style
 29#if defined _M_IX86
 30#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
 31#elif defined _M_IA64
 32#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
 33#elif defined _M_X64
 34#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
 35#else
 36#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
 37#endif
 38#pragma endregion
 39
 40
 41HINSTANCE g_hInst;        // Current instance
 42
 43
 44//
 45//   FUNCTION: ReportError(LPWSTR, DWORD)
 46//
 47//   PURPOSE: Display an error dialog for the failure of a certain function.
 48//
 49//   PARAMETERS:
 50//   * pszFunction - the name of the function that failed.
 51//   * hr - the HRESULT value.
 52//
 53void ReportError(LPCWSTR pszFunction, HRESULT hr)
 54{
 55    wchar_t szMessage[200];
 56    if (SUCCEEDED(StringCchPrintf(szMessage, ARRAYSIZE(szMessage), 
 57        L"%s failed w/hr 0x%08lx", pszFunction, hr)))
 58    {
 59        MessageBox(NULL, szMessage, L"Error", MB_ICONERROR);
 60    }
 61}
 62
 63
 64#pragma region Basic Open File Dialogs
 65
 66const COMDLG_FILTERSPEC c_rgFileTypes[] =
 67{
 68    { L"Word Documents (*.docx)",   L"*.docx" },
 69    { L"Text Files (*.txt)",        L"*.txt" },
 70    { L"All Files (*.*)",           L"*.*" }
 71};
 72
 73//
 74//   FUNCTION: OnOpenAFile(HWND)
 75//
 76//   PURPOSE: Use the common file open dialog to select a file.
 77//
 78void OnOpenAFile(HWND hWnd)
 79{
 80    HRESULT hr = S_OK;
 81
 82    // Create a new common open file dialog.
 83    IFileDialog *pfd = NULL;
 84    hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, 
 85        IID_PPV_ARGS(&pfd));
 86    if (SUCCEEDED(hr))
 87    {
 88        // Control the default folder of the file dialog. Here we set it as the 
 89        // Music library known folder. 
 90        IShellItem *psiMusic = NULL;
 91        hr = SHCreateItemInKnownFolder(FOLDERID_Music, 0, NULL, 
 92            IID_PPV_ARGS(&psiMusic));
 93        if (SUCCEEDED(hr))
 94        {
 95            hr = pfd->SetFolder(psiMusic);
 96            psiMusic->Release();
 97        }
 98
 99        // Set the title of the dialog.
100        if (SUCCEEDED(hr))
101        {
102            hr = pfd->SetTitle(L"Select a File");
103        }
104
105        // Specify file types for the file dialog.
106        if (SUCCEEDED(hr))
107        {
108            hr = pfd->SetFileTypes(ARRAYSIZE(c_rgFileTypes), c_rgFileTypes);
109            if (SUCCEEDED(hr))
110            {
111                // Set the selected file type index to Word Document.
112                hr = pfd->SetFileTypeIndex(1);
113            }
114        }
115
116        // Set the default extension to be added to file names as ".docx"
117        if (SUCCEEDED(hr))
118        {
119            hr = pfd->SetDefaultExtension(L"docx");
120        }
121
122        // Show the open file dialog.
123        if (SUCCEEDED(hr))
124        {
125            hr = pfd->Show(hWnd);
126            if (SUCCEEDED(hr))
127            {
128                // Get the result of the open file dialog.
129                IShellItem *psiResult = NULL;
130                hr = pfd->GetResult(&psiResult);
131                if (SUCCEEDED(hr))
132                {
133                    PWSTR pszPath = NULL;
134                    hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
135                    if (SUCCEEDED(hr))
136                    {
137                        MessageBox(hWnd, pszPath, L"The selected file is", MB_OK);
138                        CoTaskMemFree(pszPath);
139                    }
140                    psiResult->Release();
141                }
142            }
143            else
144            {
145                if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
146                {
147                    // User cancelled the dialog...
148                }
149            }
150        }
151
152        pfd->Release();
153    }
154
155    // Report the error. 
156    if (FAILED(hr))
157    {
158        // If it's not that the user cancelled the dialog, report the error in a 
159        // message box.
160        if (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED))
161        {
162            ReportError(L"OnOpenAFile", hr);
163        }
164    }
165}
166
167
168//
169//   FUNCTION: OnOpenAFolder(HWND)
170//
171//   PURPOSE:  Use the common file open dialog to select a folder.
172//
173void OnOpenAFolder(HWND hWnd)
174{
175    HRESULT hr = S_OK; 
176
177    // Create a new common open file dialog.
178    IFileOpenDialog *pfd = NULL;
179    hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, 
180        IID_PPV_ARGS(&pfd));
181    if (SUCCEEDED(hr))
182    {
183        // Set the dialog as a folder picker.
184        DWORD dwOptions;
185        hr = pfd->GetOptions(&dwOptions);
186        if (SUCCEEDED(hr))
187        {
188            hr = pfd->SetOptions(dwOptions | FOS_PICKFOLDERS);
189        }
190
191        // Set the title of the dialog.
192        if (SUCCEEDED(hr))
193        {
194            hr = pfd->SetTitle(L"Select a Folder");
195        }
196
197        // Show the open file dialog.
198        if (SUCCEEDED(hr))
199        {
200            hr = pfd->Show(hWnd);
201            if (SUCCEEDED(hr))
202            {
203                // Get the selection from the user.
204                IShellItem *psiResult = NULL;
205                hr = pfd->GetResult(&psiResult);
206                if (SUCCEEDED(hr))
207                {
208                    PWSTR pszPath = NULL;
209                    hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
210                    if (SUCCEEDED(hr))
211                    {
212                        MessageBox(hWnd, pszPath, L"The selected folder is", MB_OK);
213                        CoTaskMemFree(pszPath);
214                    }
215                    psiResult->Release();
216                }
217            }
218            else
219            {
220                if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
221                {
222                    // User cancelled the dialog...
223                }
224            }
225        }
226
227        pfd->Release();
228    }
229
230    // Report the error.
231    if (FAILED(hr))
232    {
233        // If it's not that the user cancelled the dialog, report the error in a 
234        // message box.
235        if (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED))
236        {
237            ReportError(L"OnOpenAFolder", hr);
238        }
239    }
240}
241
242
243//
244//   FUNCTION: OnOpenFiles(HWND)
245//
246//   PURPOSE:  Use the common file open dialog to select multiple files.
247//
248void OnOpenFiles(HWND hWnd)
249{
250    HRESULT hr = S_OK;
251
252    // Create a new common open file dialog.
253    IFileOpenDialog *pfd = NULL;
254    hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, 
255        IID_PPV_ARGS(&pfd));
256    if (SUCCEEDED(hr))
257    {
258        // Allow multi-selection in the common file dialog.
259        DWORD dwOptions;
260        hr = pfd->GetOptions(&dwOptions);
261        if (SUCCEEDED(hr))
262        {
263            hr = pfd->SetOptions(dwOptions | FOS_ALLOWMULTISELECT);
264        }
265
266        // Set the title of the dialog.
267        if (SUCCEEDED(hr))
268        {
269            hr = pfd->SetTitle(L"Select Files");
270        }
271
272        // Show the open file dialog.
273        if (SUCCEEDED(hr))
274        {
275            hr = pfd->Show(hWnd);
276            if (SUCCEEDED(hr))
277            {
278                // Obtain the results of the user interaction.
279                IShellItemArray *psiaResults = NULL;
280                hr = pfd->GetResults(&psiaResults);
281                if (SUCCEEDED(hr))
282                {
283                    // Get the number of files being selected.
284                    DWORD dwFolderCount;
285                    hr = psiaResults->GetCount(&dwFolderCount);
286                    if (SUCCEEDED(hr))
287                    {
288                        // Allocate a zero buffer for concatting all file paths.
289                        DWORD cch = dwFolderCount * MAX_PATH;
290                        PWSTR pszPaths = new wchar_t[cch];
291                        ZeroMemory(pszPaths, cch * sizeof(*pszPaths));
292
293                        // Iterate through all selected files.
294                        for (DWORD i = 0; i < dwFolderCount; i++)
295                        {
296                            IShellItem *psi = NULL;
297                            if (SUCCEEDED(psiaResults->GetItemAt(i, &psi)))
298                            {
299                                // Retrieve the file path.
300                                PWSTR pszPath = NULL;
301                                if (SUCCEEDED(psi->GetDisplayName(SIGDN_FILESYSPATH, 
302                                    &pszPath)))
303                                {
304                                    StringCchCat(pszPaths, cch, pszPath);
305                                    StringCchCat(pszPaths, cch, L"\r\n");
306                                    CoTaskMemFree(pszPath);
307                                }
308                                psi->Release();
309                            }
310                        }
311
312                        // Display the result.
313                        MessageBox(hWnd, pszPaths, L"The selected files are", MB_OK);
314
315                        delete[] pszPaths;
316                    }                    
317                }
318
319                psiaResults->Release();
320            }
321            else
322            {
323                if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
324                {
325                    // User cancelled the dialog...
326                }
327            }
328        }
329
330        pfd->Release();
331    }
332
333    // Report the error.
334    if (FAILED(hr))
335    {
336        // If it's not that the user cancelled the dialog, report the error in a 
337        // message box.
338        if (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED))
339        {
340            ReportError(L"OnOpenFiles", hr);
341        }
342    }
343}
344
345#pragma endregion
346
347
348#pragma region Customized Open File Dialogs
349
350// Controls
351// It is OK for CONTROL_RADIOBUTTON2 to have the same ID as CONTROL_RADIOBUTTONLIST, 
352// because it is a child control under CONTROL_RADIOBUTTONLIST.
353#define CONTROL_GROUP           2000
354#define CONTROL_RADIOBUTTONLIST 2
355#define CONTROL_RADIOBUTTON1    1
356#define CONTROL_RADIOBUTTON2    2
357
358
359//
360//   CLASS: CFileDialogEventHandler
361//
362//   PURPOSE: 
363//   File Dialog Event Handler that reesponds to Events in Added Controls. The 
364//   events handler provided by the calling process can implement 
365//   IFileDialogControlEvents in addition to IFileDialogEvents. 
366//   IFileDialogControlEvents enables the calling process to react to these events: 
367//     1) PushButton clicked. 
368//     2) CheckButton state changed. 
369//     3) Item selected from a menu, ComboBox, or RadioButton list. 
370//     4) Control activating. This is sent when a menu is about to display a 
371//        drop-down list, in case the calling process wants to change the items in 
372//        the list.
373//
374class CFileDialogEventHandler : 
375    public IFileDialogEvents, 
376    public IFileDialogControlEvents
377{
378public:
379
380    // 
381    // IUnknown methods
382    // 
383
384    IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv)
385    {
386        static const QITAB qit[] = 
387        {
388            QITABENT(CFileDialogEventHandler, IFileDialogEvents),
389            QITABENT(CFileDialogEventHandler, IFileDialogControlEvents),
390            { 0 }
391        };
392        return QISearch(this, qit, riid, ppv);
393    }
394
395    IFACEMETHODIMP_(ULONG) AddRef()
396    {
397        return InterlockedIncrement(&m_cRef);
398    }
399
400    IFACEMETHODIMP_(ULONG) Release()
401    {
402        long cRef = InterlockedDecrement(&m_cRef);
403        if (!cRef)
404        {
405            delete this;
406        }
407        return cRef;
408    }
409
410    // 
411    // IFileDialogEvents methods
412    // 
413
414    IFACEMETHODIMP OnFileOk(IFileDialog*)
415    { return S_OK; }
416    IFACEMETHODIMP OnFolderChange(IFileDialog*)
417    { return S_OK; }
418    IFACEMETHODIMP OnFolderChanging(IFileDialog*, IShellItem*)
419    { return S_OK; }
420    IFACEMETHODIMP OnHelp(IFileDialog*)
421    { return S_OK; }
422    IFACEMETHODIMP OnSelectionChange(IFileDialog*)
423    { return S_OK; }
424    IFACEMETHODIMP OnTypeChange(IFileDialog*)
425    { return S_OK; }
426    IFACEMETHODIMP OnShareViolation(IFileDialog*, IShellItem*, FDE_SHAREVIOLATION_RESPONSE*)
427    { return S_OK; }
428    IFACEMETHODIMP OnOverwrite(IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*)
429    { return S_OK; }
430
431    // 
432    // IFileDialogControlEvents methods
433    // 
434
435    IFACEMETHODIMP OnItemSelected(IFileDialogCustomize*pfdc, DWORD dwIDCtl, DWORD dwIDItem)
436    {
437        IFileDialog *pfd = NULL;
438        HRESULT hr = pfdc->QueryInterface(&pfd);
439        if (SUCCEEDED(hr))
440        {
441            if (dwIDCtl == CONTROL_RADIOBUTTONLIST)
442            {
443                switch (dwIDItem)
444                {
445                case CONTROL_RADIOBUTTON1:
446                    hr = pfd->SetTitle(L"Windows Vista");
447                    break;
448
449                case CONTROL_RADIOBUTTON2:
450                    hr = pfd->SetTitle(L"Windows 7");
451                    break;
452                }
453            }
454            pfd->Release();
455        }
456        return hr;
457    }
458
459    IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize*, DWORD)
460    { return S_OK; }
461    IFACEMETHODIMP OnControlActivating(IFileDialogCustomize*, DWORD)
462    { return S_OK; }
463    IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize*, DWORD, BOOL)
464    { return S_OK; }
465
466    CFileDialogEventHandler() : m_cRef(1) { }
467
468protected:
469
470    ~CFileDialogEventHandler() { }
471    long m_cRef;
472};
473
474
475//
476//   FUNCTION: CFileDialogEventHandler_CreateInstance(REFIID, void**)
477//
478//   PURPOSE:  CFileDialogEventHandler instance creation helper function.
479//
480HRESULT CFileDialogEventHandler_CreateInstance(REFIID riid, void **ppv)
481{
482    *ppv = NULL;
483    CFileDialogEventHandler* pFileDialogEventHandler = 
484        new(std::nothrow)CFileDialogEventHandler();
485    HRESULT hr = pFileDialogEventHandler ? S_OK : E_OUTOFMEMORY;
486    if (SUCCEEDED(hr))
487    {
488        hr = pFileDialogEventHandler->QueryInterface(riid, ppv);
489        pFileDialogEventHandler->Release();
490    }
491    return hr;
492}
493
494
495//
496//   FUNCTION: OnAddCustomControls(HWND)
497// 
498//   PURPOSE:  
499//   The function demonstrates how to add custom controls in the Common File Dialog.
500//
501//
502void OnAddCustomControls(HWND hWnd)
503{
504    HRESULT hr = S_OK;
505
506    // Create a new common open file dialog
507    IFileDialog *pfd = NULL;
508    hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, 
509        IID_PPV_ARGS(&pfd));
510    if (SUCCEEDED(hr))
511    {
512        // Create an event handling object, and hook it up to the dialog.
513        IFileDialogEvents *pfde = NULL;
514        hr = CFileDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
515        if (SUCCEEDED(hr))
516        {
517            // Hook up the event handler.
518            DWORD dwCookie = 0;
519            hr = pfd->Advise(pfde, &dwCookie);
520            if (SUCCEEDED(hr))
521            {
522                // Set up the customization.
523                IFileDialogCustomize *pfdc = NULL;
524                hr = pfd->QueryInterface(IID_PPV_ARGS(&pfdc));
525                if (SUCCEEDED(hr))
526                {
527                    // Create a visual group.
528                    hr = pfdc->StartVisualGroup(CONTROL_GROUP, L"Change Title to ");
529                    if (SUCCEEDED(hr))
530                    {
531                        // Add a radio-button list.
532                        hr = pfdc->AddRadioButtonList(CONTROL_RADIOBUTTONLIST);
533                        if (SUCCEEDED(hr))
534                        {
535                            // Set the state of the added radio-button list.
536                            hr = pfdc->SetControlState(CONTROL_RADIOBUTTONLIST, 
537                                CDCS_VISIBLE | CDCS_ENABLED);
538                        }
539
540                        // Add individual buttons to the radio-button list.
541                        if (SUCCEEDED(hr))
542                        {
543                            hr = pfdc->AddControlItem(CONTROL_RADIOBUTTONLIST, 
544                                CONTROL_RADIOBUTTON1, L"Windows Vista");
545                        }
546                        if (SUCCEEDED(hr))
547                        {
548                            hr = pfdc->AddControlItem(CONTROL_RADIOBUTTONLIST, 
549                                CONTROL_RADIOBUTTON2, L"Windows 7");
550                        }
551
552                        // Set the default selection to option 1.
553                        if (SUCCEEDED(hr))
554                        {
555                            hr = pfdc->SetSelectedControlItem(
556                                CONTROL_RADIOBUTTONLIST, CONTROL_RADIOBUTTON1);
557                        }
558
559                        // End the visual group
560                        pfdc->EndVisualGroup();
561                    }
562                    pfdc->Release();
563                }
564
565                // Show the open file dialog.
566                if (SUCCEEDED(hr))
567                {
568                    hr = pfd->Show(hWnd);
569                    if (SUCCEEDED(hr))
570                    {                        
571                        // You can add your own code here to handle the results...
572                    }
573                }
574
575                // Unhook the event handler
576                pfd->Unadvise(dwCookie);
577            }
578            pfde->Release();
579        }
580        pfd->Release();
581    }
582
583    // Report the error. 
584    if (FAILED(hr))
585    {
586        // If it's not that the user cancelled the dialog, report the error in a 
587        // message box.
588        if (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED))
589        {
590            ReportError(L"OnAddCustomControls", hr);
591        }
592    }
593}
594
595
596//
597//   FUNCTION: OnAddCommonPlaces(HWND)
598//
599//   PURPOSE:  
600//   The Common Places area in the Common File Dialog is extensible. This code 
601//   snippet demonstrates how to extend the Common Places area.
602//
603//
604void OnAddCommonPlaces(HWND hWnd)
605{
606    HRESULT hr = S_OK;
607
608    // Create a new common open file dialog.
609    IFileDialog *pfd = NULL;
610    hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, 
611        IID_PPV_ARGS(&pfd));
612    if (SUCCEEDED(hr))
613    {
614        // Get the shell item of the PublicMusic known folder.
615        IShellItem *psiPublicMusic = NULL;
616        hr = SHCreateItemInKnownFolder(FOLDERID_PublicMusic, 0, NULL, 
617            IID_PPV_ARGS(&psiPublicMusic));
618        if (SUCCEEDED(hr))
619        {
620            // Add the place to the bottom of default list in Common File Dialog.
621            hr = pfd->AddPlace(psiPublicMusic, FDAP_BOTTOM);
622            psiPublicMusic->Release();
623        }
624
625        // Show the open file dialog.
626        if (SUCCEEDED(hr))
627        {
628            hr = pfd->Show(hWnd);
629            if (SUCCEEDED(hr))
630            {
631                // You can add your own code here to handle the results...
632            }
633        }
634
635        pfd->Release();
636    }
637
638    // Report the error. 
639    if (FAILED(hr))
640    {
641        // If it's not that the user cancelled the dialog, report the error in a 
642        // message box.
643        if (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED))
644        {
645            ReportError(L"OnAddCommonPlaces", hr);
646        }
647    }
648}
649
650#pragma endregion
651
652
653#pragma region Basic Save File Dialogs
654
655const COMDLG_FILTERSPEC c_rgSaveTypes[] =
656{
657    { L"Word Documents (*.docx)",   L"*.docx" },
658    { L"Text Files (*.txt)",        L"*.txt" }
659};
660
661//
662//   FUNCTION: OnSaveAFile(HWND)
663//
664//   PURPOSE: Use the common file save dialog to save a file.
665//
666void OnSaveAFile(HWND hWnd)
667{
668    HRESULT hr = S_OK;
669
670    // Create a new common save file dialog.
671    IFileDialog *pfd = NULL;
672    hr = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_INPROC_SERVER, 
673        IID_PPV_ARGS(&pfd));
674    if (SUCCEEDED(hr))
675    {
676        // (Optional) Set the title of the dialog.
677        hr = pfd->SetTitle(L"Save a File");
678
679        // (Optional) Specify file types for the file dialog.
680        if (SUCCEEDED(hr))
681        {
682            hr = pfd->SetFileTypes(ARRAYSIZE(c_rgSaveTypes), c_rgSaveTypes);
683            if (SUCCEEDED(hr))
684            {
685                // Set the selected file type index to Word Document.
686                hr = pfd->SetFileTypeIndex(1);
687            }
688        }
689
690        // (Optional) Set the default extension to be added as ".docx".
691        if (SUCCEEDED(hr))
692        {
693            hr = pfd->SetDefaultExtension(L"docx");
694        }
695
696        // (Optional) Display a warning if the user specifies a file name that 
697        // aleady exists. This is a default value for the Save dialog.
698        if (SUCCEEDED(hr))
699        {
700            DWORD dwOptions;
701            hr = pfd->GetOptions(&dwOptions);
702            if (SUCCEEDED(hr))
703            {
704                hr = pfd->SetOptions(dwOptions | FOS_OVERWRITEPROMPT);
705            }
706        }
707
708        // Show the save file dialog.
709        if (SUCCEEDED(hr))
710        {
711            hr = pfd->Show(hWnd);
712            if (SUCCEEDED(hr))
713            {
714                // Get the result of the save file dialog.
715                IShellItem *psiResult = NULL;
716                hr = pfd->GetResult(&psiResult);
717                if (SUCCEEDED(hr))
718                {
719                    PWSTR pszPath = NULL;
720                    hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
721                    if (SUCCEEDED(hr))
722                    {
723                        // Open and save to the file.
724                        HANDLE hFile = CreateFile(pszPath, 
725                            GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, 
726                            FILE_ATTRIBUTE_NORMAL, NULL);
727                        if (hFile != INVALID_HANDLE_VALUE)
728                        {
729                            // Write to the file stream.
730                            // ...
731
732                            CloseHandle(hFile);
733
734                            MessageBox(hWnd, pszPath, L"The saved file is", MB_OK);
735                        }
736
737                        CoTaskMemFree(pszPath);
738                    }
739                    psiResult->Release();
740                }
741            }
742        }
743
744        pfd->Release();
745    }
746
747    // Report the error. 
748    if (FAILED(hr))
749    {
750        // If it's not that the user cancelled the dialog, report the error in a 
751        // message box.
752        if (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED))
753        {
754            ReportError(L"OnSaveAFile", hr);
755        }
756    }
757}
758
759#pragma endregion
760
761
762#pragma region Customized Save File Dialogs
763
764
765
766#pragma endregion
767
768
769#pragma region Main Window
770
771// 
772//   FUNCTION: OnInitDialog(HWND, HWND, LPARAM)
773//
774//   PURPOSE: Process the WM_INITDIALOG message. 
775//
776BOOL OnInitDialog(HWND hWnd, HWND hwndFocus, LPARAM lParam)
777{
778    return TRUE;
779}
780
781
782//
783//   FUNCTION: OnCommand(HWND, int, HWND, UINT)
784//
785//   PURPOSE: Process the WM_COMMAND message
786//
787void OnCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify)
788{
789    switch (id)
790    {
791    case IDC_BUTTON_OPENAFILE:
792        OnOpenAFile(hWnd);
793        break;
794
795    case IDC_BUTTON_OPENAFOLDER:
796        OnOpenAFolder(hWnd);
797        break;
798
799    case IDC_BUTTON_OPENFILES:
800        OnOpenFiles(hWnd);
801        break;
802
803    case IDC_BUTTON_ADDCUSTOMCONTROLS:
804        OnAddCustomControls(hWnd);
805        break;
806
807    case IDC_BUTTON_ADDCOMMONPLACES:
808        OnAddCommonPlaces(hWnd);
809        break;
810
811    case IDC_BUTTON_SAVEAFILE:
812        OnSaveAFile(hWnd);
813        break;
814
815    case IDOK:
816    case IDCANCEL:
817        EndDialog(hWnd, 0);
818        break;
819    }
820}
821
822
823//
824//   FUNCTION: OnClose(HWND)
825//
826//   PURPOSE: Process the WM_CLOSE message
827//
828void OnClose(HWND hWnd)
829{
830    EndDialog(hWnd, 0);
831}
832
833
834//
835//  FUNCTION: DialogProc(HWND, UINT, WPARAM, LPARAM)
836//
837//  PURPOSE:  Processes messages for the main dialog.
838//
839INT_PTR CALLBACK DialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
840{
841    switch (message)
842    {
843        // Handle the WM_INITDIALOG message in OnInitDialog
844        HANDLE_MSG (hWnd, WM_INITDIALOG, OnInitDialog);
845
846        // Handle the WM_COMMAND message in OnCommand
847        HANDLE_MSG (hWnd, WM_COMMAND, OnCommand);
848
849        // Handle the WM_CLOSE message in OnClose
850        HANDLE_MSG (hWnd, WM_CLOSE, OnClose);
851
852    default:
853        return FALSE;
854    }
855    return 0;
856}
857
858#pragma endregion
859
860
861//
862//  FUNCTION: wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
863//
864//  PURPOSE:  The entry point of the application.
865//
866int APIENTRY wWinMain(HINSTANCE hInstance,
867                      HINSTANCE hPrevInstance,
868                      LPWSTR    lpCmdLine,
869                      int       nCmdShow)
870{
871    return DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAINDIALOG), NULL, DialogProc);
872}