Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
7.8 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: Browse.cpp
  6. //
  7. // Owner: EdDude
  8. //
  9. // Description:
  10. //
  11. // Implements the CBrowseFolder class.
  12. //
  13. // Browse for a Folder for downloads.
  14. //
  15. //=======================================================================
  16. #include "iuengine.h"
  17. #include <shlobj.h>
  18. #include <logging.h>
  19. #include <fileutil.h>
  20. #include "Browse.h"
  21. //************************************************************************
  22. //
  23. // IUENGINE.DLL EXPORTED API BrowseForFolder()
  24. //
  25. //************************************************************************
  26. HRESULT CEngUpdate::BrowseForFolder(BSTR bstrStartFolder,
  27. LONG flag,
  28. BSTR* pbstrFolder)
  29. {
  30. LOG_Block("BrowseForFolder()");
  31. TCHAR szFolder[MAX_PATH];
  32. HRESULT hr = E_FAIL;
  33. CBrowseFolder br(flag);
  34. USES_IU_CONVERSION;
  35. LPTSTR lpszStartFolder = OLE2T(bstrStartFolder);
  36. LOG_Out(_T("BroseForFolder passed in start folder %s, flag %x"), lpszStartFolder, (DWORD)flag);
  37. if (IUBROWSE_NOBROWSE & flag)
  38. {
  39. //
  40. // if not browse dlgbox required, the purpose of this call is
  41. // to validate the folder
  42. //
  43. DWORD dwRet = ValidateFolder(lpszStartFolder, (IUBROWSE_WRITE_ACCESS & flag));
  44. hr = (ERROR_SUCCESS == dwRet) ? S_OK : HRESULT_FROM_WIN32(dwRet);
  45. if (SUCCEEDED(hr))
  46. {
  47. *pbstrFolder = SysAllocString(T2OLE(lpszStartFolder));
  48. }
  49. }
  50. else
  51. {
  52. //
  53. // pop up the browse dlgbox
  54. //
  55. hr = br.BrowseFolder(NULL, lpszStartFolder, szFolder, ARRAYSIZE(szFolder));
  56. if (SUCCEEDED(hr))
  57. {
  58. *pbstrFolder = SysAllocString(T2OLE(szFolder));
  59. }
  60. }
  61. if (FAILED(hr))
  62. {
  63. LOG_ErrorMsg(hr);
  64. *pbstrFolder = NULL;
  65. }
  66. return hr;
  67. }
  68. //
  69. //Only allow one of these dialogs at a time.
  70. //
  71. bool CBrowseFolder::s_bBrowsing = false;
  72. //
  73. //Max length of compacted path string in dialog status line (so it doesn't get too long).
  74. //
  75. #define MAX_BROWSEDLG_COMPACT_PATH 30
  76. //
  77. //Ctor
  78. //
  79. CBrowseFolder::CBrowseFolder(LONG lFlag)
  80. : m_hwParent(0)
  81. {
  82. m_szFolder[0] = _T('\0');
  83. m_fValidateWrite = 0 == (IUBROWSE_WRITE_ACCESS & lFlag) ? FALSE : TRUE;
  84. m_fValidateUI = 0 == (IUBROWSE_AFFECT_UI & lFlag) ? FALSE : TRUE;
  85. }
  86. //
  87. //Dtor
  88. //
  89. CBrowseFolder::~CBrowseFolder()
  90. {
  91. }
  92. //----------------------------------------------------------------------
  93. // BrowseCallbackProc
  94. //
  95. // Callback procedure used by SHBrowseForFolder() API call.
  96. //
  97. // This callback function handles the initialization of the browse dialog and when
  98. // the user changes the selection in the tree-view. We want to keep updating the
  99. // g_szBrowsePath buffer with selection changes until the user clicks OK.
  100. //
  101. // Returns:
  102. // 0
  103. //
  104. //----------------------------------------------------------------------
  105. int CALLBACK CBrowseFolder::_BrowseCallbackProc( HWND hwDlg, UINT uMsg, LPARAM lParam, LPARAM lpData )
  106. {
  107. CBrowseFolder* pThis = (CBrowseFolder*) lpData;
  108. int iRet = 0;
  109. BOOL bValidated = FALSE;
  110. switch(uMsg)
  111. {
  112. case BFFM_INITIALIZED:
  113. {
  114. //
  115. // Initialize the dialog with the OK button and m_szFolder
  116. //
  117. bValidated = (ERROR_SUCCESS == ValidateFolder(pThis->m_szFolder, pThis->m_fValidateWrite) || !pThis->m_fValidateUI);
  118. SendMessage(hwDlg, BFFM_ENABLEOK, 0, bValidated);
  119. //
  120. // 469738 IU - BrowseForFolder shows incorrect selection when passed in a start folder name
  121. //
  122. // Always select the folder passed in regardless of the bValidated flag
  123. //
  124. SendMessage(hwDlg, BFFM_SETSELECTION, TRUE, (LPARAM) pThis->m_szFolder);
  125. return 0;
  126. break;
  127. } //case BFFM_INITIALIZED
  128. case BFFM_SELCHANGED:
  129. {
  130. HRESULT hr = S_OK;
  131. TCHAR pszPath[MAX_PATH];
  132. LPITEMIDLIST pidl = (LPITEMIDLIST) lParam;
  133. //
  134. // Validate folder with a status message
  135. //
  136. if (SHGetPathFromIDList(pidl, pszPath))
  137. {
  138. //
  139. // if it's file system, validate the path
  140. //
  141. bValidated = (ERROR_SUCCESS == ValidateFolder(pszPath, pThis->m_fValidateWrite) || !pThis->m_fValidateUI);
  142. if (bValidated)
  143. {
  144. hr = StringCchCopyEx(pThis->m_szFolder, ARRAYSIZE(pThis->m_szFolder), pszPath,
  145. NULL, NULL, MISTSAFE_STRING_FLAGS);
  146. if (FAILED(hr))
  147. {
  148. pThis->m_szFolder[0] = _T('\0');
  149. // since we've failed, just set bValidated to FALSE and use that failure path
  150. bValidated = FALSE;
  151. }
  152. }
  153. SendMessage(hwDlg, BFFM_ENABLEOK, 0, bValidated);
  154. if (bValidated)
  155. {
  156. //SendMessage(hwDlg, BFFM_SETSTATUSTEXT, 0, (LPARAM) (LPCTSTR)pszCompactPath);
  157. SendMessage(hwDlg, BFFM_SETSTATUSTEXT, 0, (LPARAM) (LPCTSTR)pszPath);
  158. }
  159. }
  160. break;
  161. } //case BFFM_SELCHANGED
  162. } //switch(uMsg)
  163. return iRet;
  164. }
  165. //----------------------------------------------------------------------
  166. //
  167. // main public function
  168. //
  169. //----------------------------------------------------------------------
  170. HRESULT CBrowseFolder::BrowseFolder(HWND hwParent, LPCTSTR lpszDefaultPath,
  171. LPTSTR szPathSelected, DWORD cchPathSelected)
  172. {
  173. HRESULT hr = S_OK;
  174. BROWSEINFO br;
  175. LPCITEMIDLIST pidl;
  176. LOG_Block("BrowseFolder");
  177. m_szFolder[0] = szPathSelected[0] = _T('\0');
  178. //
  179. //Only allow one of thes Browse dialogs at a time.
  180. //
  181. if (s_bBrowsing)
  182. {
  183. hr = HRESULT_FROM_WIN32(ERROR_BUSY);
  184. LOG_ErrorMsg(hr);
  185. return hr;
  186. }
  187. else
  188. {
  189. s_bBrowsing = true;
  190. }
  191. m_hwParent = hwParent;
  192. hr = StringCchCopyEx(m_szFolder, ARRAYSIZE(m_szFolder), lpszDefaultPath,
  193. NULL, NULL, MISTSAFE_STRING_FLAGS);
  194. if (FAILED(hr))
  195. {
  196. m_szFolder[0] = _T('\0');
  197. LOG_ErrorMsg(hr);
  198. return hr;
  199. }
  200. //
  201. //Browse dialog parameters
  202. //
  203. br.hwndOwner = hwParent;
  204. br.pidlRoot = NULL; //rooted at desktop
  205. br.pszDisplayName = NULL;
  206. br.lpszTitle = NULL;
  207. br.ulFlags = BIF_RETURNONLYFSDIRS|BIF_STATUSTEXT; //only want FS dirs, and a status line
  208. br.lpfn = _BrowseCallbackProc;
  209. br.lParam = (__int3264)this;
  210. br.iImage = 0;
  211. //
  212. // Popup browse dialog
  213. //
  214. pidl = SHBrowseForFolder(&br);
  215. if (0 == pidl)
  216. {
  217. //
  218. // Cancel pressed
  219. //
  220. LOG_Out(_T("User clicked CANCEL button!"));
  221. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  222. }
  223. else
  224. {
  225. //
  226. // 469729 IU - BrowseForFolder does not return error when passed IUBROWSE_WRITE_ACCESS flag
  227. //
  228. // For the case of IUBROWSE_WRITE_ACCESS, but **NO** IUBROWSE_AFFECT_UI flag, the user may
  229. // have selected a folder that has no write access and clicked OK, which will return the
  230. // folder with no write access. We have to call ValidateFolder once again here. We
  231. // probably shouldn't allow IUBROWSE_WRITE_ACCESS without IUBROWSE_AFFECT_UI, but since
  232. // we do we have to have this fix.
  233. //
  234. if (m_fValidateWrite && ERROR_SUCCESS != ValidateFolder(m_szFolder, m_fValidateWrite))
  235. {
  236. LOG_Out(_T("We should have write access to the folder, but don't -- return E_ACCESSDENIED"));
  237. hr = E_ACCESSDENIED;
  238. }
  239. //
  240. // Return the folder even if E_ACCESSDENIED, so caller can advise user
  241. //
  242. hr = StringCchCopyEx(szPathSelected, cchPathSelected, m_szFolder,
  243. NULL, NULL, MISTSAFE_STRING_FLAGS);
  244. if (FAILED(hr))
  245. {
  246. szPathSelected[0] = _T('\0');
  247. LOG_ErrorMsg(hr);
  248. }
  249. LOG_Out(_T("User selected path %s"), m_szFolder);
  250. LPMALLOC pMalloc = NULL;
  251. if (SUCCEEDED(SHGetMalloc(&pMalloc)) && NULL != pMalloc)
  252. {
  253. pMalloc->Free((LPVOID) pidl);
  254. pMalloc->Release();
  255. }
  256. /*
  257. throughout MSDN, there is no mentioning of what to do if failed to get shell malloc object.
  258. so, we'll have to assume SHGetMalloc() never fail.
  259. else
  260. {
  261. CoTaskMemFree((void*)pidl);
  262. }
  263. */
  264. pidl = 0;
  265. }
  266. s_bBrowsing = false;
  267. return hr;
  268. }