FolderBrowseEx.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #include "main.h"
  2. #include "./folderbrowseex.h"
  3. #include "../nu/CGlobalAtom.h"
  4. #include <shobjidl.h>
  5. #include "../replicant/nu/AutoWide.h"
  6. static CGlobalAtom CLSPROP(L"FBEXDLG");
  7. #ifdef _WIN64
  8. #define LONGPTR_CAST LONG_PTR
  9. #else
  10. #define LONGPTR_CAST LONG
  11. #endif
  12. #define PATHTYPE_PIDL FALSE
  13. #define PATHTYPE_STRING TRUE
  14. BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam)
  15. {
  16. wchar_t cl[32] = {0};
  17. GetClassName(hwnd, cl, ARRAYSIZE(cl));
  18. if (!lstrcmpi(cl, WC_TREEVIEW))
  19. {
  20. PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd));
  21. return FALSE;
  22. }
  23. return TRUE;
  24. }
  25. static int WINAPI BrowseCallback_Helper(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  26. {
  27. FolderBrowseEx *lpfbex = reinterpret_cast<FolderBrowseEx*>(lpData);
  28. if (!lpfbex) return 0;
  29. switch (uMsg)
  30. {
  31. case BFFM_INITIALIZED:
  32. lpfbex->hwnd = hwnd;
  33. if(SetPropW(hwnd, CLSPROP, (void*)lpData))
  34. {
  35. lpfbex->oldProc = (LONG_PTR) ((IsWindowUnicode(hwnd)) ? SetWindowLongPtrW(hwnd, DWLP_DLGPROC, (LONGPTR_CAST)WindowProc_Helper) : SetWindowLongPtrA(hwnd, DWLP_DLGPROC, (LONGPTR_CAST)WindowProc_Helper));
  36. if (NULL == lpfbex->oldProc) RemovePropW(hwnd, CLSPROP);
  37. }
  38. // this is not nice but it fixes the selection not working correctly on all OSes
  39. EnumChildWindows(hwnd, browseEnumProc, 0);
  40. break;
  41. }
  42. return lpfbex->BrowseCallback(uMsg, lParam);
  43. }
  44. static LRESULT WINAPI WindowProc_Helper(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  45. {
  46. FolderBrowseEx *lpfbex = static_cast<FolderBrowseEx*>(GetPropW(hwnd, CLSPROP));
  47. if (!lpfbex) return 0;
  48. switch(uMsg)
  49. {
  50. case WM_NCDESTROY:
  51. lpfbex->DialogProc(uMsg, wParam, lParam);
  52. if (IsWindowUnicode(hwnd)) SetWindowLongPtrW(hwnd, DWLP_DLGPROC, (LONGPTR_CAST)lpfbex->oldProc);
  53. else SetWindowLongPtrA(hwnd, DWLP_DLGPROC, (LONGPTR_CAST)lpfbex->oldProc);
  54. RemovePropW(hwnd, CLSPROP);
  55. lpfbex->oldProc = NULL;
  56. lpfbex->hwnd = NULL;
  57. return 0;
  58. }
  59. return lpfbex->DialogProc(uMsg, wParam, lParam);
  60. }
  61. static void Initialize(FolderBrowseEx *lpfbx, LPCITEMIDLIST pidlRoot, UINT ulFlags, LPCWSTR lpszCaption, LPCWSTR lpszTitle)
  62. {
  63. lpfbx->pidlRoot = pidlRoot;
  64. lpfbx->ulFlags = ulFlags;
  65. lpfbx->lpszCaption = NULL;
  66. lpfbx->lpszTitle = NULL;
  67. lpfbx->image = -1;
  68. lpfbx->pidl = NULL;
  69. lpfbx->hwnd = NULL;
  70. lpfbx->oldProc = NULL;
  71. CoInitialize(NULL);
  72. lpfbx->pathExpanded.empty = TRUE;
  73. lpfbx->pathSelection.empty = TRUE;
  74. if (lpszCaption) lpfbx->SetCaption(lpszCaption);
  75. if (lpszTitle) lpfbx->SetTitle(lpszTitle);
  76. }
  77. FolderBrowseEx::FolderBrowseEx(LPCITEMIDLIST pidlRoot, UINT ulFlags, LPCWSTR lpszCaption, LPCWSTR lpszTitle)
  78. {
  79. Initialize(this, pidlRoot, ulFlags, lpszCaption, lpszTitle);
  80. }
  81. FolderBrowseEx::FolderBrowseEx(UINT ulFlags, LPCWSTR lpszCaption, LPCWSTR lpszTitle)
  82. {
  83. Initialize(this, NULL, ulFlags, lpszCaption, lpszTitle);
  84. }
  85. FolderBrowseEx::FolderBrowseEx(UINT ulFlags, LPCWSTR lpszTitle)
  86. {
  87. Initialize(this, NULL, ulFlags, L"", lpszTitle);
  88. }
  89. FolderBrowseEx::FolderBrowseEx(void)
  90. {
  91. Initialize(this, NULL, 0, L"", L"");
  92. }
  93. FolderBrowseEx::~FolderBrowseEx(void)
  94. {
  95. if (pidl) CoTaskMemFree(pidl);
  96. if (lpszTitle) free(lpszTitle);
  97. if (lpszCaption) free(lpszCaption);
  98. CoUninitialize();
  99. }
  100. HRESULT FolderBrowseEx::ParseDisplayName(LPCWSTR lpszPath, IBindCtx *pbc, LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut)
  101. {
  102. IShellFolder *isf = NULL;
  103. HRESULT result;
  104. SFGAOF attrib;
  105. if (NOERROR != (result = SHGetDesktopFolder(&isf))) return result;
  106. attrib = sfgaoIn;
  107. result = isf->ParseDisplayName(NULL, pbc, (LPWSTR)lpszPath, NULL, ppidl, &attrib);
  108. isf->Release();
  109. if (S_OK != result) *ppidl = NULL;
  110. else if (psfgaoOut) *psfgaoOut = attrib;
  111. return result;
  112. }
  113. void FolderBrowseEx::SetExpanded(LPCITEMIDLIST pidlExpand)
  114. {
  115. pathExpanded.empty = FALSE;
  116. pathExpanded.type = PATHTYPE_PIDL;
  117. pathExpanded.value = (void*)pidlExpand;
  118. if (hwnd) SendMessage(BFFM_SETEXPANDED, pathExpanded.type, (LPARAM)pathExpanded.value);
  119. }
  120. void FolderBrowseEx::SetExpanded(LPCWSTR lpszExpand)
  121. {
  122. pathExpanded.empty = FALSE;
  123. pathExpanded.type = PATHTYPE_STRING;
  124. pathExpanded.value = (void*)lpszExpand;
  125. if (hwnd) SendMessage(BFFM_SETEXPANDED, pathExpanded.type, (LPARAM)pathExpanded.value);
  126. }
  127. void FolderBrowseEx::SetSelection(LPCITEMIDLIST pidlSelect)
  128. {
  129. pathSelection.empty = FALSE;
  130. pathSelection.type = PATHTYPE_PIDL;
  131. pathSelection.value = (void*)pidlSelect;
  132. if (hwnd) SendMessage(BFFM_SETSELECTIONW, pathSelection.type, (LPARAM)pathSelection.value);
  133. }
  134. void FolderBrowseEx::SetSelection(LPCWSTR lpszSelect)
  135. {
  136. pathSelection.empty = FALSE;
  137. pathSelection.type = PATHTYPE_STRING;
  138. pathSelection.value = (void*)lpszSelect;
  139. if (hwnd) SendMessage(BFFM_SETSELECTIONW, pathSelection.type, (LPARAM)pathSelection.value);
  140. }
  141. void FolderBrowseEx::SetCaption(LPCWSTR lpszCaption)
  142. {
  143. if (this->lpszCaption) free(this->lpszCaption);
  144. this->lpszCaption = _wcsdup((lpszCaption) ? lpszCaption : L"");
  145. if (hwnd) SetWindowText(lpszCaption);
  146. }
  147. void FolderBrowseEx::SetTitle(LPCWSTR lpszTitle)
  148. {
  149. if (this->lpszTitle) free(this->lpszTitle);
  150. this->lpszTitle = _wcsdup((lpszTitle) ? lpszTitle : L"");
  151. }
  152. LPITEMIDLIST FolderBrowseEx::Browse(HWND hwndOwner)
  153. {
  154. BROWSEINFOW bi = {0};
  155. bi.hwndOwner = hwndOwner;
  156. bi.pidlRoot = pidlRoot;
  157. bi.pszDisplayName = pszDisplayName;
  158. bi.lpszTitle = lpszTitle;
  159. bi.ulFlags = ulFlags;
  160. bi.lpfn = BrowseCallback_Helper;
  161. bi.lParam = (LPARAM)this;
  162. pidl = SHBrowseForFolderW(&bi);
  163. if (pidl) OnSelectionDone(pidl);
  164. image = (pidl) ? bi.iImage : -1;
  165. return pidl;
  166. }
  167. INT FolderBrowseEx::BrowseCallback(UINT uMsg, LPARAM lParam)
  168. {
  169. switch(uMsg)
  170. {
  171. case BFFM_INITIALIZED: OnInitialized(); break;
  172. case BFFM_IUNKNOWN: OnIUnknown((IUnknown*)lParam); break;
  173. case BFFM_SELCHANGED: OnSelectionChanged((LPCITEMIDLIST)lParam); break;
  174. case BFFM_VALIDATEFAILEDA: return OnValidateFailed(AutoWide((LPCSTR)lParam));
  175. case BFFM_VALIDATEFAILEDW: return OnValidateFailed((LPCWSTR)lParam);
  176. }
  177. return 0;
  178. }
  179. void FolderBrowseEx::OnInitialized(void)
  180. {
  181. if (!pathSelection.empty) SendMessage(BFFM_SETSELECTIONW, pathSelection.type, (LPARAM)pathSelection.value);
  182. if (!pathExpanded.empty) SendMessage(BFFM_SETEXPANDED, pathExpanded.type, (LPARAM)pathExpanded.value);
  183. SetWindowText(lpszCaption);
  184. }
  185. void FolderBrowseEx::OnSelectionChanged(LPCITEMIDLIST pidl)
  186. {
  187. }
  188. INT_PTR FolderBrowseEx::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  189. {
  190. return CallWindowProc(uMsg, wParam, lParam);
  191. }
  192. INT_PTR FolderBrowseEx::CallWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  193. {
  194. return (IsWindowUnicode(hwnd)) ? ::CallWindowProcW((WNDPROC)oldProc, hwnd, uMsg, wParam, lParam)
  195. : ::CallWindowProcA((WNDPROC)oldProc, hwnd, uMsg, wParam, lParam);
  196. }
  197. void FolderBrowseEx::SetDialogResult(LRESULT result)
  198. {
  199. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG)(LONG_PTR)result);
  200. }