BsWin32BrowseDialogs.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsPrerequisitesUtil.h"
  4. #include "Win32/BsWin32Window.h"
  5. #include <atlbase.h>
  6. #include <ShObjIdl.h>
  7. namespace BansheeEngine
  8. {
  9. void addFiltersToDialog(IFileDialog* fileDialog, const WString& filterList)
  10. {
  11. const wchar_t EMPTY_WSTR[] = L"";
  12. const wchar_t WILDCARD[] = L"*.*";
  13. if (filterList.empty())
  14. return;
  15. Vector<WString> filters = StringUtil::split(filterList, L";");
  16. UINT32 numFilters = (UINT32)filters.size();
  17. if (numFilters == 0)
  18. return;
  19. COMDLG_FILTERSPEC* specList = bs_newN<COMDLG_FILTERSPEC>(numFilters);
  20. for (size_t i = 0; i < numFilters; ++i)
  21. {
  22. specList[i].pszName = EMPTY_WSTR;
  23. specList[i].pszSpec = filters[i].c_str();
  24. }
  25. fileDialog->SetFileTypes(numFilters, specList);
  26. bs_deleteN(specList, numFilters);
  27. }
  28. void setDefaultPath(IFileDialog* dialog, const Path& defaultPath)
  29. {
  30. WString pathStr = defaultPath.toWString();
  31. const wchar_t* defaultPathW = pathStr.c_str();
  32. IShellItem* folder;
  33. HRESULT result = SHCreateItemFromParsingName(defaultPathW, NULL, IID_PPV_ARGS(&folder));
  34. // Valid non results.
  35. if (result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || result == HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE))
  36. return;
  37. if (!SUCCEEDED(result))
  38. return;
  39. dialog->SetFolder(folder);
  40. folder->Release();
  41. }
  42. void getPaths(IShellItemArray* shellItems, Vector<Path>& paths)
  43. {
  44. DWORD numShellItems;
  45. shellItems->GetCount(&numShellItems);
  46. for (DWORD i = 0; i < numShellItems; ++i)
  47. {
  48. IShellItem* shellItem = nullptr;
  49. shellItems->GetItemAt(i, &shellItem);
  50. SFGAOF attribs;
  51. shellItem->GetAttributes(SFGAO_FILESYSTEM, &attribs);
  52. if (!(attribs & SFGAO_FILESYSTEM))
  53. continue;
  54. LPWSTR name;
  55. shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name);
  56. paths.push_back((Path)name);
  57. CoTaskMemFree(name);
  58. }
  59. }
  60. bool PlatformUtility::openBrowseDialog(FileDialogType type, const Path& defaultPath, const WString& filterList,
  61. Vector<Path>& paths)
  62. {
  63. // Init COM library.
  64. CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
  65. IFileDialog* fileDialog = nullptr;
  66. UINT32 dialogType = ((UINT32)type & (UINT32)FileDialogType::TypeMask);
  67. bool isOpenDialog = dialogType == (UINT32)FileDialogType::OpenFile || dialogType == (UINT32)FileDialogType::OpenFolder;
  68. // Create dialog
  69. IID classId = isOpenDialog ? CLSID_FileOpenDialog : CLSID_FileSaveDialog;
  70. CoCreateInstance(classId, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&fileDialog));
  71. addFiltersToDialog(fileDialog, filterList);
  72. setDefaultPath(fileDialog, defaultPath);
  73. // Apply multiselect flags
  74. bool isMultiselect = false;
  75. if (isOpenDialog)
  76. {
  77. if (dialogType == (UINT32)FileDialogType::OpenFile)
  78. {
  79. if (((UINT32)type & (UINT32)FileDialogType::Multiselect) != 0)
  80. {
  81. DWORD dwFlags;
  82. fileDialog->GetOptions(&dwFlags);
  83. fileDialog->SetOptions(dwFlags | FOS_ALLOWMULTISELECT);
  84. isMultiselect = true;
  85. }
  86. }
  87. else
  88. {
  89. DWORD dwFlags;
  90. fileDialog->GetOptions(&dwFlags);
  91. fileDialog->SetOptions(dwFlags | FOS_PICKFOLDERS);
  92. }
  93. }
  94. // Show the dialog
  95. bool finalResult = false;
  96. if (SUCCEEDED(fileDialog->Show(nullptr)))
  97. {
  98. if (isMultiselect)
  99. {
  100. // Get file names
  101. IFileOpenDialog* fileOpenDialog;
  102. fileDialog->QueryInterface(IID_IFileOpenDialog, (void**)&fileOpenDialog);
  103. IShellItemArray* shellItems = nullptr;
  104. fileOpenDialog->GetResults(&shellItems);
  105. getPaths(shellItems, paths);
  106. shellItems->Release();
  107. fileOpenDialog->Release();
  108. }
  109. else
  110. {
  111. // Get the file name
  112. IShellItem* shellItem = nullptr;
  113. fileDialog->GetResult(&shellItem);
  114. LPWSTR filePath = nullptr;
  115. shellItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath);
  116. paths.push_back((Path)filePath);
  117. CoTaskMemFree(filePath);
  118. shellItem->Release();
  119. }
  120. finalResult = true;
  121. }
  122. CoUninitialize();
  123. return finalResult;
  124. }
  125. }