FolderDlg.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /////////////////////////////////////////////////////////////////////////////
  2. /*
  3. DESCRIPTION:
  4. CFolderDialog - Folder Selection Dialog Class
  5. Copyright(C) Armen Hakobyan, 2002 - 2005
  6. http://www.codeproject.com/dialog/cfolderdialog.asp
  7. VERSION HISTORY:
  8. 24 Mar 2002 - First release
  9. 30 Mar 2003 - Some minor changes
  10. - Added missing in old Platform SDK new flag definitions
  11. - Added support for both MFC 6.0 and 7.0
  12. - Added OnIUnknown handler for Windows XP folder filtration
  13. - Added SetExpanded and SetOKText and GetSelectedFolder functions
  14. 24 May 2003 - Added OnSelChanged implementation
  15. 14 Jul 2003 - Added custom filtration for Windows XP, thanks to Arik Poznanski
  16. 29 Nov 2003 - Added SetRootFolder, thanks to Eckhard Schwabe ( and Jose Insa )
  17. 02 Jan 2004 - Added GetRootFolder, uncomment if needed
  18. 15 Feb 2005 - Small bug fix in DoModal, thanks to WindSeven
  19. */
  20. /////////////////////////////////////////////////////////////////////////////
  21. #include "stdafx.h"
  22. #include "FolderDlg.h"
  23. /////////////////////////////////////////////////////////////////////////////
  24. #ifndef BFFM_VALIDATEFAILED
  25. #ifndef UNICODE
  26. #define BFFM_VALIDATEFAILED 3
  27. #else
  28. #define BFFM_VALIDATEFAILED 4
  29. #endif
  30. #endif
  31. #ifndef BFFM_IUNKNOWN
  32. #define BFFM_IUNKNOWN 5
  33. #endif
  34. /////////////////////////////////////////////////////////////////////////////
  35. // CFolderDialog
  36. //IMPLEMENT_DYNAMIC( CFolderDialog, CDialog )
  37. CFolderDialog::CFolderDialog( IN LPCTSTR pszTitle /*NULL*/,
  38. IN LPCTSTR pszSelPath /*NULL*/,
  39. IN CWnd* pWndParent /*NULL*/,
  40. IN UINT uFlags /*BIF_RETURNONLYFSDIRS*/ )
  41. : CCommonDialog( pWndParent )
  42. , m_hWnd( NULL )
  43. {
  44. ::ZeroMemory( &m_bi, sizeof( BROWSEINFO ) );
  45. ::ZeroMemory( m_szFolPath, MAX_PATH );
  46. ::ZeroMemory( m_szSelPath, MAX_PATH );
  47. // Fill data
  48. m_bi.hwndOwner = pWndParent->GetSafeHwnd();
  49. m_bi.pidlRoot = NULL;
  50. m_bi.lpszTitle = pszTitle;
  51. m_bi.ulFlags = uFlags;
  52. m_bi.lpfn = (BFFCALLBACK)&BrowseCallbackProc;
  53. m_bi.lParam = (LPARAM)this;
  54. // The size of this buffer is assumed to be MAX_PATH bytes:
  55. m_bi.pszDisplayName = new TCHAR[ MAX_PATH ];
  56. ASSERT( m_bi.pszDisplayName != NULL );
  57. SAFE_ZEROMEMORY(
  58. m_bi.pszDisplayName, ( MAX_PATH * sizeof( TCHAR ) )
  59. );
  60. if( pszSelPath )
  61. SetSelectedFolder( pszSelPath );
  62. }
  63. CFolderDialog::~CFolderDialog( VOID )
  64. {
  65. SAFE_COTASKMEMFREE( m_bi.pidlRoot );
  66. SAFE_DELETE2( m_bi.pszDisplayName );
  67. ::ZeroMemory( &m_bi, sizeof( BROWSEINFO ) );
  68. }
  69. BEGIN_MESSAGE_MAP( CFolderDialog, CCommonDialog )
  70. END_MESSAGE_MAP()
  71. /////////////////////////////////////////////////////////////////////////////
  72. // CFolderDialog message handlers
  73. // SetRootFolder By Jose Insa
  74. // Microsoft knowledge Base Article
  75. // ID Q132750: Convert a File Path to an ITEMIDLIST
  76. BOOL CFolderDialog::SetRootFolder( IN LPCTSTR pszPath )
  77. {
  78. ASSERT_VALID( this );
  79. if( !pszPath )
  80. {
  81. SAFE_COTASKMEMFREE( m_bi.pidlRoot );
  82. return TRUE;
  83. }
  84. ASSERT( AfxIsValidString( pszPath, MAX_PATH ) );
  85. HRESULT hResult = S_FALSE;
  86. IShellFolder* pDeskFolder = NULL;
  87. hResult = ::SHGetDesktopFolder( &pDeskFolder );
  88. if ( hResult == S_OK )
  89. {
  90. LPITEMIDLIST pidlRoot = NULL;
  91. LPTSTR pszRoot = const_cast< LPTSTR >( pszPath );
  92. // Convert the path to an ITEMIDLIST:
  93. USES_CONVERSION;
  94. hResult = pDeskFolder->ParseDisplayName(
  95. NULL, NULL, T2W( pszRoot ), NULL, &pidlRoot, NULL
  96. );
  97. if( hResult == S_OK )
  98. {
  99. SAFE_COTASKMEMFREE( m_bi.pidlRoot );
  100. m_bi.pidlRoot = pidlRoot;
  101. }
  102. SAFE_RELEASE( pDeskFolder );
  103. }
  104. return ( hResult == S_OK );
  105. }
  106. // NOTE: pszPath buffer must be at least
  107. // MAX_PATH characters in size:
  108. BOOL CFolderDialog::GetRootFolder( IN OUT LPTSTR pszPath )
  109. {
  110. ASSERT_VALID( this );
  111. ASSERT( AfxIsValidString( pszPath, MAX_PATH ) );
  112. return ::SHGetPathFromIDList( m_bi.pidlRoot, pszPath );
  113. }
  114. BOOL CFolderDialog::SetSelectedFolder( IN LPCTSTR pszPath )
  115. {
  116. ASSERT( AfxIsValidString( pszPath, MAX_PATH ) );
  117. return (BOOL)::lstrcpy( m_szSelPath, pszPath );
  118. }
  119. /////////////////////////////////////////////////////////////////////////////
  120. #if ( _MFC_VER >= 0x0700 )
  121. INT_PTR CFolderDialog::DoModal( VOID )
  122. #else
  123. INT CFolderDialog::DoModal( VOID )
  124. #endif
  125. {
  126. ASSERT_VALID( this );
  127. ASSERT( m_bi.lpfn != NULL );
  128. INT_PTR nRet = -1;
  129. m_bi.hwndOwner = PreModal();
  130. LPITEMIDLIST pItemIDList = ::SHBrowseForFolder( &m_bi );
  131. if( pItemIDList )
  132. {
  133. if( ::SHGetPathFromIDList( pItemIDList, m_szFolPath ) )
  134. nRet = IDOK;
  135. SAFE_COTASKMEMFREE( pItemIDList );
  136. }
  137. else
  138. nRet = IDCANCEL;
  139. PostModal();
  140. return ( nRet );
  141. }
  142. /////////////////////////////////////////////////////////////////////////////
  143. // Overridables:
  144. VOID CFolderDialog::OnInitialized( VOID )
  145. {
  146. if( ::lstrlen( m_szSelPath ) > 0 )
  147. SetSelection( m_szSelPath );
  148. }
  149. VOID CFolderDialog::OnSelChanged( IN LPITEMIDLIST pItemIDList )
  150. {
  151. if( m_bi.ulFlags & BIF_STATUSTEXT )
  152. {
  153. TCHAR szSelFol[ MAX_PATH ] = { 0 };
  154. if( ::SHGetPathFromIDList( pItemIDList, szSelFol ) )
  155. SetStatusText( szSelFol );
  156. }
  157. }
  158. INT CFolderDialog::OnValidateFailed( IN LPCTSTR /*pszPath*/ )
  159. {
  160. ::MessageBeep( MB_ICONHAND );
  161. return 1; // Return 1 to leave dialog open, 0 - to end one
  162. }
  163. VOID CFolderDialog::OnIUnknown( IN IUnknown* /*pIUnknown*/ )
  164. {
  165. }
  166. /////////////////////////////////////////////////////////////////////////////
  167. // Callback function used with the SHBrowseForFolder function.
  168. INT CALLBACK CFolderDialog::BrowseCallbackProc( IN HWND hWnd,
  169. IN UINT uMsg,
  170. IN LPARAM lParam,
  171. IN LPARAM lpData )
  172. {
  173. CFolderDialog* pThis = (CFolderDialog*)lpData;
  174. ASSERT( pThis != NULL );
  175. INT nRet = 0;
  176. pThis->m_hWnd = hWnd;
  177. switch( uMsg )
  178. {
  179. case BFFM_INITIALIZED:
  180. pThis->OnInitialized();
  181. break;
  182. case BFFM_SELCHANGED:
  183. pThis->OnSelChanged( (LPITEMIDLIST)lParam );
  184. break;
  185. case BFFM_VALIDATEFAILED:
  186. nRet = pThis->OnValidateFailed( (LPCTSTR)lParam );
  187. break;
  188. case BFFM_IUNKNOWN:
  189. pThis->OnIUnknown( (IUnknown*)lParam );
  190. break;
  191. default:
  192. ASSERT( FALSE );
  193. break;
  194. }
  195. pThis->m_hWnd = NULL;
  196. return nRet;
  197. }
  198. /////////////////////////////////////////////////////////////////////////////
  199. // Commands, valid to call only from handlers
  200. VOID CFolderDialog::SetExpanded( IN LPCTSTR pszPath )
  201. {
  202. USES_CONVERSION;
  203. ASSERT( m_hWnd != NULL );
  204. ASSERT( AfxIsValidString( pszPath, MAX_PATH ) );
  205. ::SendMessage(
  206. m_hWnd, BFFM_SETEXPANDED,
  207. (WPARAM)TRUE, (LPARAM)T2CW( pszPath )
  208. );
  209. }
  210. VOID CFolderDialog::SetOKText( IN LPCTSTR pszText )
  211. {
  212. USES_CONVERSION;
  213. ASSERT( m_hWnd != NULL );
  214. ::SendMessage(
  215. m_hWnd, BFFM_SETOKTEXT,
  216. (WPARAM)0, (LPARAM)T2CW( pszText )
  217. );
  218. }
  219. VOID CFolderDialog::EnableOK( IN BOOL bEnable /*TRUE*/ )
  220. {
  221. ASSERT( m_hWnd != NULL );
  222. ::SendMessage(
  223. m_hWnd, BFFM_ENABLEOK, (WPARAM)bEnable, 0L
  224. );
  225. }
  226. VOID CFolderDialog::SetSelection( IN LPITEMIDLIST pItemIDList )
  227. {
  228. ASSERT( m_hWnd != NULL );
  229. ::SendMessage(
  230. m_hWnd, BFFM_SETSELECTION,
  231. (WPARAM)FALSE, (LPARAM)pItemIDList
  232. );
  233. }
  234. VOID CFolderDialog::SetSelection( IN LPCTSTR pszPath )
  235. {
  236. ASSERT( m_hWnd != NULL );
  237. ASSERT( AfxIsValidString( pszPath, MAX_PATH ) );
  238. ::SendMessage(
  239. m_hWnd, BFFM_SETSELECTION,
  240. (WPARAM)TRUE, (LPARAM)pszPath
  241. );
  242. }
  243. VOID CFolderDialog::SetStatusText( IN LPCTSTR pszText )
  244. {
  245. ASSERT( m_hWnd != NULL );
  246. ::SendMessage(
  247. m_hWnd, BFFM_SETSTATUSTEXT,
  248. (WPARAM)0, (LPARAM)pszText
  249. );
  250. }
  251. // Shell version 5.0 or later:
  252. VOID CFolderDialog::SetExpanded( IN LPITEMIDLIST pItemIDList )
  253. {
  254. ASSERT( m_hWnd != NULL );
  255. ::SendMessage(
  256. m_hWnd, BFFM_SETEXPANDED,
  257. (WPARAM)FALSE, (LPARAM)pItemIDList
  258. );
  259. }
  260. /////////////////////////////////////////////////////////////////////////////