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