BsWin32BrowseDialogs.cpp 3.8 KB

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