dlgfile.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #include <dlgs.h> // for standard control IDs for commdlg
  12. #ifdef AFX_AUX_SEG
  13. #pragma code_seg(AFX_AUX_SEG)
  14. #endif
  15. #ifdef _DEBUG
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. #define new DEBUG_NEW
  20. ////////////////////////////////////////////////////////////////////////////
  21. // FileOpen/FileSaveAs common dialog helper
  22. CFileDialog::CFileDialog(BOOL bOpenFileDialog,
  23. LPCTSTR lpszDefExt, LPCTSTR lpszFileName, DWORD dwFlags,
  24. LPCTSTR lpszFilter, CWnd* pParentWnd) : CCommonDialog(pParentWnd)
  25. {
  26. memset(&m_ofn, 0, sizeof(m_ofn)); // initialize structure to 0/NULL
  27. m_szFileName[0] = '\0';
  28. m_szFileTitle[0] = '\0';
  29. m_pofnTemp = NULL;
  30. m_bOpenFileDialog = bOpenFileDialog;
  31. m_nIDHelp = bOpenFileDialog ? AFX_IDD_FILEOPEN : AFX_IDD_FILESAVE;
  32. m_ofn.lStructSize = sizeof(m_ofn);
  33. m_ofn.lpstrFile = m_szFileName;
  34. m_ofn.nMaxFile = _countof(m_szFileName);
  35. m_ofn.lpstrDefExt = lpszDefExt;
  36. m_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle;
  37. m_ofn.nMaxFileTitle = _countof(m_szFileTitle);
  38. m_ofn.Flags |= dwFlags | OFN_ENABLEHOOK | OFN_ENABLESIZING;
  39. if (!afxData.bWin4 && AfxHelpEnabled())
  40. m_ofn.Flags |= OFN_SHOWHELP;
  41. if (afxData.bWin4)
  42. {
  43. m_ofn.Flags |= OFN_EXPLORER;
  44. m_ofn.hInstance = AfxGetResourceHandle();
  45. }
  46. m_ofn.lpfnHook = (COMMDLGPROC)_AfxCommDlgProc;
  47. // setup initial file name
  48. if (lpszFileName != NULL)
  49. lstrcpyn(m_szFileName, lpszFileName, _countof(m_szFileName));
  50. // Translate filter into commdlg format (lots of \0)
  51. if (lpszFilter != NULL)
  52. {
  53. m_strFilter = lpszFilter;
  54. LPTSTR pch = m_strFilter.GetBuffer(0); // modify the buffer in place
  55. // MFC delimits with '|' not '\0'
  56. while ((pch = _tcschr(pch, '|')) != NULL)
  57. *pch++ = '\0';
  58. m_ofn.lpstrFilter = m_strFilter;
  59. // do not call ReleaseBuffer() since the string contains '\0' characters
  60. }
  61. }
  62. int CFileDialog::DoModal()
  63. {
  64. ASSERT_VALID(this);
  65. ASSERT(m_ofn.Flags & OFN_ENABLEHOOK);
  66. ASSERT(m_ofn.lpfnHook != NULL); // can still be a user hook
  67. // zero out the file buffer for consistent parsing later
  68. ASSERT(AfxIsValidAddress(m_ofn.lpstrFile, m_ofn.nMaxFile));
  69. DWORD nOffset = lstrlen(m_ofn.lpstrFile)+1;
  70. ASSERT(nOffset <= m_ofn.nMaxFile);
  71. memset(m_ofn.lpstrFile+nOffset, 0, (m_ofn.nMaxFile-nOffset)*sizeof(TCHAR));
  72. // WINBUG: This is a special case for the file open/save dialog,
  73. // which sometimes pumps while it is coming up but before it has
  74. // disabled the main window.
  75. HWND hWndFocus = ::GetFocus();
  76. BOOL bEnableParent = FALSE;
  77. m_ofn.hwndOwner = PreModal();
  78. AfxUnhookWindowCreate();
  79. if (m_ofn.hwndOwner != NULL && ::IsWindowEnabled(m_ofn.hwndOwner))
  80. {
  81. bEnableParent = TRUE;
  82. ::EnableWindow(m_ofn.hwndOwner, FALSE);
  83. }
  84. _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  85. ASSERT(pThreadState->m_pAlternateWndInit == NULL);
  86. if (m_ofn.Flags & OFN_EXPLORER)
  87. pThreadState->m_pAlternateWndInit = this;
  88. else
  89. AfxHookWindowCreate(this);
  90. int nResult;
  91. if (m_bOpenFileDialog)
  92. nResult = ::GetOpenFileName(&m_ofn);
  93. else
  94. nResult = ::GetSaveFileName(&m_ofn);
  95. if (nResult)
  96. ASSERT(pThreadState->m_pAlternateWndInit == NULL);
  97. pThreadState->m_pAlternateWndInit = NULL;
  98. // WINBUG: Second part of special case for file open/save dialog.
  99. if (bEnableParent)
  100. ::EnableWindow(m_ofn.hwndOwner, TRUE);
  101. if (::IsWindow(hWndFocus))
  102. ::SetFocus(hWndFocus);
  103. PostModal();
  104. return nResult ? nResult : IDCANCEL;
  105. }
  106. CString CFileDialog::GetPathName() const
  107. {
  108. if ((m_ofn.Flags & OFN_EXPLORER) && m_hWnd != NULL)
  109. {
  110. ASSERT(::IsWindow(m_hWnd));
  111. CString strResult;
  112. if (GetParent()->SendMessage(CDM_GETSPEC, (WPARAM)MAX_PATH,
  113. (LPARAM)strResult.GetBuffer(MAX_PATH)) < 0)
  114. {
  115. strResult.Empty();
  116. }
  117. else
  118. {
  119. strResult.ReleaseBuffer();
  120. }
  121. if (!strResult.IsEmpty())
  122. {
  123. if (GetParent()->SendMessage(CDM_GETFILEPATH, (WPARAM)MAX_PATH,
  124. (LPARAM)strResult.GetBuffer(MAX_PATH)) < 0)
  125. strResult.Empty();
  126. else
  127. {
  128. strResult.ReleaseBuffer();
  129. return strResult;
  130. }
  131. }
  132. }
  133. return m_ofn.lpstrFile;
  134. }
  135. CString CFileDialog::GetFileName() const
  136. {
  137. if ((m_ofn.Flags & OFN_EXPLORER) && m_hWnd != NULL)
  138. {
  139. ASSERT(::IsWindow(m_hWnd));
  140. CString strResult;
  141. if (GetParent()->SendMessage(CDM_GETSPEC, (WPARAM)MAX_PATH,
  142. (LPARAM)strResult.GetBuffer(MAX_PATH)) < 0)
  143. {
  144. strResult.Empty();
  145. }
  146. else
  147. {
  148. strResult.ReleaseBuffer();
  149. return strResult;
  150. }
  151. }
  152. return m_ofn.lpstrFileTitle;
  153. }
  154. CString CFileDialog::GetFileExt() const
  155. {
  156. if ((m_ofn.Flags & OFN_EXPLORER) && m_hWnd != NULL)
  157. {
  158. ASSERT(::IsWindow(m_hWnd));
  159. CString strResult;
  160. if (GetParent()->SendMessage(CDM_GETSPEC, (WPARAM)MAX_PATH,
  161. (LPARAM)strResult.GetBuffer(MAX_PATH)) < 0)
  162. strResult.Empty();
  163. else
  164. {
  165. strResult.ReleaseBuffer();
  166. int pos = strResult.ReverseFind('.');
  167. if (pos >= 0)
  168. return strResult.Right(strResult.GetLength() - pos - 1);
  169. strResult.Empty();
  170. }
  171. return strResult;
  172. }
  173. if (m_pofnTemp != NULL)
  174. if (m_pofnTemp->nFileExtension == 0)
  175. return &afxChNil;
  176. else
  177. return m_pofnTemp->lpstrFile + m_pofnTemp->nFileExtension;
  178. if (m_ofn.nFileExtension == 0)
  179. return &afxChNil;
  180. else
  181. return m_ofn.lpstrFile + m_ofn.nFileExtension;
  182. }
  183. CString CFileDialog::GetFileTitle() const
  184. {
  185. CString strResult = GetFileName();
  186. int pos = strResult.ReverseFind('.');
  187. if (pos >= 0)
  188. return strResult.Left(pos);
  189. return strResult;
  190. }
  191. CString CFileDialog::GetNextPathName(POSITION& pos) const
  192. {
  193. BOOL bExplorer = m_ofn.Flags & OFN_EXPLORER;
  194. TCHAR chDelimiter;
  195. if (bExplorer)
  196. chDelimiter = '\0';
  197. else
  198. chDelimiter = ' ';
  199. LPTSTR lpsz = (LPTSTR)pos;
  200. if (lpsz == m_ofn.lpstrFile) // first time
  201. {
  202. if ((m_ofn.Flags & OFN_ALLOWMULTISELECT) == 0)
  203. {
  204. pos = NULL;
  205. return m_ofn.lpstrFile;
  206. }
  207. // find char pos after first Delimiter
  208. while(*lpsz != chDelimiter && *lpsz != '\0')
  209. lpsz = _tcsinc(lpsz);
  210. lpsz = _tcsinc(lpsz);
  211. // if single selection then return only selection
  212. if (*lpsz == 0)
  213. {
  214. pos = NULL;
  215. return m_ofn.lpstrFile;
  216. }
  217. }
  218. CString strPath = m_ofn.lpstrFile;
  219. if (!bExplorer)
  220. {
  221. LPTSTR lpszPath = m_ofn.lpstrFile;
  222. while(*lpszPath != chDelimiter)
  223. lpszPath = _tcsinc(lpszPath);
  224. strPath = strPath.Left(lpszPath - m_ofn.lpstrFile);
  225. }
  226. LPTSTR lpszFileName = lpsz;
  227. CString strFileName = lpsz;
  228. // find char pos at next Delimiter
  229. while(*lpsz != chDelimiter && *lpsz != '\0')
  230. lpsz = _tcsinc(lpsz);
  231. if (!bExplorer && *lpsz == '\0')
  232. pos = NULL;
  233. else
  234. {
  235. if (!bExplorer)
  236. strFileName = strFileName.Left(lpsz - lpszFileName);
  237. lpsz = _tcsinc(lpsz);
  238. if (*lpsz == '\0') // if double terminated then done
  239. pos = NULL;
  240. else
  241. pos = (POSITION)lpsz;
  242. }
  243. // only add '\\' if it is needed
  244. if (!strPath.IsEmpty())
  245. {
  246. // check for last back-slash or forward slash (handles DBCS)
  247. LPCTSTR lpsz = _tcsrchr(strPath, '\\');
  248. if (lpsz == NULL)
  249. lpsz = _tcsrchr(strPath, '/');
  250. // if it is also the last character, then we don't need an extra
  251. if (lpsz != NULL &&
  252. (lpsz - (LPCTSTR)strPath) == strPath.GetLength()-1)
  253. {
  254. ASSERT(*lpsz == '\\' || *lpsz == '/');
  255. return strPath + strFileName;
  256. }
  257. }
  258. return strPath + '\\' + strFileName;
  259. }
  260. void CFileDialog::SetTemplate(LPCTSTR lpWin3ID, LPCTSTR lpWin4ID)
  261. {
  262. if (m_ofn.Flags & OFN_EXPLORER)
  263. m_ofn.lpTemplateName = lpWin4ID;
  264. else
  265. m_ofn.lpTemplateName = lpWin3ID;
  266. m_ofn.Flags |= OFN_ENABLETEMPLATE;
  267. }
  268. CString CFileDialog::GetFolderPath() const
  269. {
  270. ASSERT(::IsWindow(m_hWnd));
  271. ASSERT(m_ofn.Flags & OFN_EXPLORER);
  272. CString strResult;
  273. if (GetParent()->SendMessage(CDM_GETFOLDERPATH, (WPARAM)MAX_PATH, (LPARAM)strResult.GetBuffer(MAX_PATH)) < 0)
  274. strResult.Empty();
  275. else
  276. strResult.ReleaseBuffer();
  277. return strResult;
  278. }
  279. void CFileDialog::SetControlText(int nID, LPCSTR lpsz)
  280. {
  281. ASSERT(::IsWindow(m_hWnd));
  282. ASSERT(m_ofn.Flags & OFN_EXPLORER);
  283. GetParent()->SendMessage(CDM_SETCONTROLTEXT, (WPARAM)nID, (LPARAM)lpsz);
  284. }
  285. void CFileDialog::HideControl(int nID)
  286. {
  287. ASSERT(::IsWindow(m_hWnd));
  288. ASSERT(m_ofn.Flags & OFN_EXPLORER);
  289. GetParent()->SendMessage(CDM_HIDECONTROL, (WPARAM)nID, 0);
  290. }
  291. void CFileDialog::SetDefExt(LPCSTR lpsz)
  292. {
  293. ASSERT(::IsWindow(m_hWnd));
  294. ASSERT(m_ofn.Flags & OFN_EXPLORER);
  295. GetParent()->SendMessage(CDM_SETDEFEXT, 0, (LPARAM)lpsz);
  296. }
  297. UINT CFileDialog::OnShareViolation(LPCTSTR)
  298. {
  299. ASSERT_VALID(this);
  300. // Do not call Default() if you override
  301. return OFN_SHAREWARN; // default
  302. }
  303. BOOL CFileDialog::OnFileNameOK()
  304. {
  305. ASSERT_VALID(this);
  306. // Do not call Default() if you override
  307. return FALSE;
  308. }
  309. void CFileDialog::OnLBSelChangedNotify(UINT, UINT, UINT)
  310. {
  311. ASSERT_VALID(this);
  312. // Do not call Default() if you override
  313. // no default processing needed
  314. }
  315. void CFileDialog::OnInitDone()
  316. {
  317. ASSERT_VALID(this);
  318. GetParent()->CenterWindow();
  319. // Do not call Default() if you override
  320. // no default processing needed
  321. }
  322. void CFileDialog::OnFileNameChange()
  323. {
  324. ASSERT_VALID(this);
  325. // Do not call Default() if you override
  326. // no default processing needed
  327. }
  328. void CFileDialog::OnFolderChange()
  329. {
  330. ASSERT_VALID(this);
  331. // Do not call Default() if you override
  332. // no default processing needed
  333. }
  334. void CFileDialog::OnTypeChange()
  335. {
  336. ASSERT_VALID(this);
  337. // Do not call Default() if you override
  338. // no default processing needed
  339. }
  340. BOOL CFileDialog::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  341. {
  342. ASSERT(pResult != NULL);
  343. // allow message map to override
  344. if (CCommonDialog::OnNotify(wParam, lParam, pResult))
  345. return TRUE;
  346. OFNOTIFY* pNotify = (OFNOTIFY*)lParam;
  347. switch(pNotify->hdr.code)
  348. {
  349. case CDN_INITDONE:
  350. OnInitDone();
  351. return TRUE;
  352. case CDN_SELCHANGE:
  353. OnFileNameChange();
  354. return TRUE;
  355. case CDN_FOLDERCHANGE:
  356. OnFolderChange();
  357. return TRUE;
  358. case CDN_SHAREVIOLATION:
  359. *pResult = OnShareViolation(pNotify->pszFile);
  360. return TRUE;
  361. case CDN_HELP:
  362. if (!SendMessage(WM_COMMAND, ID_HELP))
  363. SendMessage(WM_COMMANDHELP, 0, 0);
  364. return TRUE;
  365. case CDN_FILEOK:
  366. *pResult = OnFileNameOK();
  367. return TRUE;
  368. case CDN_TYPECHANGE:
  369. OnTypeChange();
  370. return TRUE;
  371. }
  372. return FALSE; // not handled
  373. }
  374. ////////////////////////////////////////////////////////////////////////////
  375. // CFileDialog diagnostics
  376. #ifdef _DEBUG
  377. void CFileDialog::Dump(CDumpContext& dc) const
  378. {
  379. CDialog::Dump(dc);
  380. if (m_bOpenFileDialog)
  381. dc << "File open dialog";
  382. else
  383. dc << "File save dialog";
  384. dc << "\nm_ofn.hwndOwner = " << (UINT)m_ofn.hwndOwner;
  385. dc << "\nm_ofn.nFilterIndex = " << m_ofn.nFilterIndex;
  386. dc << "\nm_ofn.lpstrFile = " << m_ofn.lpstrFile;
  387. dc << "\nm_ofn.nMaxFile = " << m_ofn.nMaxFile;
  388. dc << "\nm_ofn.lpstrFileTitle = " << m_ofn.lpstrFileTitle;
  389. dc << "\nm_ofn.nMaxFileTitle = " << m_ofn.nMaxFileTitle;
  390. dc << "\nm_ofn.lpstrTitle = " << m_ofn.lpstrTitle;
  391. dc << "\nm_ofn.Flags = " << (LPVOID)m_ofn.Flags;
  392. dc << "\nm_ofn.lpstrDefExt = " << m_ofn.lpstrDefExt;
  393. dc << "\nm_ofn.nFileOffset = " << m_ofn.nFileOffset;
  394. dc << "\nm_ofn.nFileExtension = " << m_ofn.nFileExtension;
  395. dc << "\nm_ofn.lpstrFilter = ";
  396. LPCTSTR lpstrItem = m_ofn.lpstrFilter;
  397. LPTSTR lpszBreak = _T("|");
  398. while (lpstrItem != NULL && *lpstrItem != '\0')
  399. {
  400. dc << lpstrItem << lpszBreak;
  401. lpstrItem += lstrlen(lpstrItem) + 1;
  402. }
  403. if (lpstrItem != NULL)
  404. dc << lpszBreak;
  405. dc << "\nm_ofn.lpstrCustomFilter = ";
  406. lpstrItem = m_ofn.lpstrCustomFilter;
  407. while (lpstrItem != NULL && *lpstrItem != '\0')
  408. {
  409. dc << lpstrItem << lpszBreak;
  410. lpstrItem += lstrlen(lpstrItem) + 1;
  411. }
  412. if (lpstrItem != NULL)
  413. dc << lpszBreak;
  414. if (m_ofn.lpfnHook == (COMMDLGPROC)_AfxCommDlgProc)
  415. dc << "\nhook function set to standard MFC hook function";
  416. else
  417. dc << "\nhook function set to non-standard hook function";
  418. dc << "\n";
  419. }
  420. #endif //_DEBUG
  421. #ifdef AFX_INIT_SEG
  422. #pragma code_seg(AFX_INIT_SEG)
  423. #endif
  424. IMPLEMENT_DYNAMIC(CFileDialog, CDialog)
  425. ////////////////////////////////////////////////////////////////////////////