home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / dlgfile.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  13KB  |  497 lines

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