2
0

BsWin32BrowseDialogs.cpp 3.8 KB

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