home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / DOCMGR.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-03  |  26.5 KB  |  1,003 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 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.  
  13. #ifdef AFX_INIT_SEG
  14. #pragma code_seg(AFX_INIT_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #ifndef _MAC
  23. static const TCHAR szShellOpenFmt[] = _T("%s\\shell\\open\\%s");
  24. static const TCHAR szShellPrintFmt[] = _T("%s\\shell\\print\\%s");
  25. static const TCHAR szShellPrintToFmt[] = _T("%s\\shell\\printto\\%s");
  26. static const TCHAR szDefaultIconFmt[] = _T("%s\\DefaultIcon");
  27. static const TCHAR szShellNewFmt[] = _T("%s\\ShellNew");
  28.  
  29. #define DEFAULT_ICON_INDEX 0
  30.  
  31. static const TCHAR szIconIndexFmt[] = _T(",%d");
  32. static const TCHAR szCommand[] = _T("command");
  33. static const TCHAR szOpenArg[] = _T(" \"%1\"");
  34. static const TCHAR szPrintArg[] = _T(" /p \"%1\"");
  35. static const TCHAR szPrintToArg[] = _T(" /pt \"%1\" \"%2\" \"%3\" \"%4\"");
  36. static const TCHAR szDDEArg[] = _T(" /dde");
  37.  
  38. static const TCHAR szDDEExec[] = _T("ddeexec");
  39. static const TCHAR szDDEOpen[] = _T("[open(\"%1\")]");
  40. static const TCHAR szDDEPrint[] = _T("[print(\"%1\")]");
  41. static const TCHAR szDDEPrintTo[] = _T("[printto(\"%1\",\"%2\",\"%3\",\"%4\")]");
  42.  
  43. static const TCHAR szShellNewValueName[] = _T("NullFile");
  44. static const TCHAR szShellNewValue[] = _T("");
  45.  
  46. BOOL AFXAPI _AfxDeleteRegKey(LPCTSTR lpszKey)
  47. {
  48.     LPTSTR lpszKeyCopy = _tcsdup(lpszKey);
  49.     LPTSTR lpszLast = lpszKeyCopy + lstrlen(lpszKeyCopy);
  50.  
  51.     while (lpszLast != NULL)
  52.     {
  53.         *lpszLast-- = '\0';
  54.         HKEY hKey;
  55.         if (::RegOpenKey(HKEY_CLASSES_ROOT, lpszKeyCopy, &hKey) != ERROR_SUCCESS)
  56.             break;
  57.  
  58.         TCHAR szScrap[_MAX_PATH+1];
  59.         DWORD dwLen = _countof(szScrap);
  60.         BOOL bItExists = FALSE;
  61.  
  62.         if (::RegEnumKey(hKey, 0, szScrap, dwLen) == ERROR_SUCCESS)
  63.             bItExists = TRUE;
  64.         ::RegCloseKey(hKey);
  65.  
  66.         if (bItExists)
  67.             break;
  68.         ::RegDeleteKey(HKEY_CLASSES_ROOT, lpszKeyCopy);
  69.  
  70.         lpszLast = _tcsrchr(lpszKeyCopy, '\\');
  71.     }
  72.     free(lpszKeyCopy);
  73.     return TRUE;
  74. }
  75.  
  76. static BOOL AFXAPI SetRegKey(LPCTSTR lpszKey, LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL)
  77. {
  78.     if (lpszValueName == NULL)
  79.     {
  80.         if (::RegSetValue(HKEY_CLASSES_ROOT, lpszKey, REG_SZ,
  81.               lpszValue, lstrlen(lpszValue) * sizeof(TCHAR)) != ERROR_SUCCESS)
  82.         {
  83.             TRACE1("Warning: registration database update failed for key '%s'.\n",
  84.                 lpszKey);
  85.             return FALSE;
  86.         }
  87.         return TRUE;
  88.     }
  89.     else
  90.     {
  91.         HKEY hKey;
  92.  
  93.         if(::RegCreateKey(HKEY_CLASSES_ROOT, lpszKey, &hKey) == ERROR_SUCCESS)
  94.         {
  95.             LONG lResult = ::RegSetValueEx(hKey, lpszValueName, 0, REG_SZ,
  96.                 (CONST BYTE*)lpszValue, (lstrlen(lpszValue) + 1) * sizeof(TCHAR));
  97.  
  98.             if(::RegCloseKey(hKey) == ERROR_SUCCESS && lResult == ERROR_SUCCESS)
  99.                 return TRUE;
  100.         }
  101.         TRACE1("Warning: registration database update failed for key '%s'.\n", lpszKey);
  102.         return FALSE;
  103.     }
  104. }
  105. #endif
  106.  
  107. CDocManager::CDocManager()
  108. {
  109. }
  110.  
  111. #ifndef _MAC
  112.  
  113. void CDocManager::UnregisterShellFileTypes()
  114. {
  115.     ASSERT(!m_templateList.IsEmpty());  // must have some doc templates
  116.  
  117.     CString strPathName, strTemp;
  118.  
  119.     AfxGetModuleShortFileName(AfxGetInstanceHandle(), strPathName);
  120.  
  121.     POSITION pos = m_templateList.GetHeadPosition();
  122.     for (int nTemplateIndex = 1; pos != NULL; nTemplateIndex++)
  123.     {
  124.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  125.  
  126.         CString strFilterExt, strFileTypeId, strFileTypeName;
  127.         if (pTemplate->GetDocString(strFileTypeId,
  128.            CDocTemplate::regFileTypeId) && !strFileTypeId.IsEmpty())
  129.         {
  130.             // enough info to register it
  131.             if (!pTemplate->GetDocString(strFileTypeName,
  132.                CDocTemplate::regFileTypeName))
  133.                 strFileTypeName = strFileTypeId;    // use id name
  134.  
  135.             ASSERT(strFileTypeId.Find(' ') == -1);  // no spaces allowed
  136.  
  137.             strTemp.Format(szDefaultIconFmt, (LPCTSTR)strFileTypeId);
  138.             _AfxDeleteRegKey(strTemp);
  139.  
  140.             // If MDI Application
  141.             if (!pTemplate->GetDocString(strTemp, CDocTemplate::windowTitle) ||
  142.                 strTemp.IsEmpty())
  143.             {
  144.                 // path\shell\open\ddeexec = [open("%1")]
  145.                 strTemp.Format(szShellOpenFmt, (LPCTSTR)strFileTypeId,
  146.                     (LPCTSTR)szDDEExec);
  147.                 _AfxDeleteRegKey(strTemp);
  148.  
  149.                 // path\shell\print\ddeexec = [print("%1")]
  150.                 strTemp.Format(szShellPrintFmt, (LPCTSTR)strFileTypeId,
  151.                     (LPCTSTR)szDDEExec);
  152.                 _AfxDeleteRegKey(strTemp);
  153.  
  154.                 // path\shell\printto\ddeexec = [printto("%1","%2","%3","%4")]
  155.                 strTemp.Format(szShellPrintToFmt, (LPCTSTR)strFileTypeId,
  156.                     (LPCTSTR)szDDEExec);
  157.                 _AfxDeleteRegKey(strTemp);
  158.             }
  159.  
  160.             // path\shell\open\command = path filename
  161.             strTemp.Format(szShellOpenFmt, (LPCTSTR)strFileTypeId,
  162.                 (LPCTSTR)szCommand);
  163.             _AfxDeleteRegKey(strTemp);
  164.  
  165.             // path\shell\print\command = path /p filename
  166.             strTemp.Format(szShellPrintFmt, (LPCTSTR)strFileTypeId,
  167.                 (LPCTSTR)szCommand);
  168.             _AfxDeleteRegKey(strTemp);
  169.  
  170.             // path\shell\printto\command = path /pt filename printer driver port
  171.             strTemp.Format(szShellPrintToFmt, (LPCTSTR)strFileTypeId,
  172.                 (LPCTSTR)szCommand);
  173.             _AfxDeleteRegKey(strTemp);
  174.  
  175.             pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt);
  176.             if (!strFilterExt.IsEmpty())
  177.             {
  178.                 ASSERT(strFilterExt[0] == '.');
  179.  
  180.                 LONG lSize = _MAX_PATH * 2;
  181.                 LONG lResult = ::RegQueryValue(HKEY_CLASSES_ROOT, strFilterExt,
  182.                     strTemp.GetBuffer(lSize), &lSize);
  183.                 strTemp.ReleaseBuffer();
  184.  
  185.                 if (lResult != ERROR_SUCCESS || strTemp.IsEmpty() ||
  186.                     strTemp == strFileTypeId)
  187.                 {
  188.                     strTemp.Format(szShellNewFmt, (LPCTSTR)strFilterExt);
  189.                     _AfxDeleteRegKey(strTemp);
  190.  
  191.                     // no association for that suffix
  192.                     _AfxDeleteRegKey(strFilterExt);
  193.                 }
  194.             }
  195.         }
  196.     }
  197. }
  198.  
  199.  
  200. void CDocManager::RegisterShellFileTypes(BOOL bCompat)
  201. {
  202.     ASSERT(!m_templateList.IsEmpty());  // must have some doc templates
  203.  
  204.     CString strPathName, strTemp;
  205.  
  206.     AfxGetModuleShortFileName(AfxGetInstanceHandle(), strPathName);
  207.  
  208.     POSITION pos = m_templateList.GetHeadPosition();
  209.     for (int nTemplateIndex = 1; pos != NULL; nTemplateIndex++)
  210.     {
  211.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  212.  
  213.         CString strOpenCommandLine = strPathName;
  214.         CString strPrintCommandLine = strPathName;
  215.         CString strPrintToCommandLine = strPathName;
  216.         CString strDefaultIconCommandLine = strPathName;
  217.  
  218.         if (bCompat)
  219.         {
  220.             CString strIconIndex;
  221.             HICON hIcon = AfxDllExtractIcon(AfxGetInstanceHandle(), strPathName, nTemplateIndex);
  222.             if (hIcon != NULL)
  223.             {
  224.                 strIconIndex.Format(szIconIndexFmt, nTemplateIndex);
  225.                 DestroyIcon(hIcon);
  226.             }
  227.             else
  228.             {
  229.                 strIconIndex.Format(szIconIndexFmt, DEFAULT_ICON_INDEX);
  230.             }
  231.             strDefaultIconCommandLine += strIconIndex;
  232.         }
  233.  
  234.         CString strFilterExt, strFileTypeId, strFileTypeName;
  235.         if (pTemplate->GetDocString(strFileTypeId,
  236.            CDocTemplate::regFileTypeId) && !strFileTypeId.IsEmpty())
  237.         {
  238.             // enough info to register it
  239.             if (!pTemplate->GetDocString(strFileTypeName,
  240.                CDocTemplate::regFileTypeName))
  241.                 strFileTypeName = strFileTypeId;    // use id name
  242.  
  243.             ASSERT(strFileTypeId.Find(' ') == -1);  // no spaces allowed
  244.  
  245.             // first register the type ID of our server
  246.             if (!SetRegKey(strFileTypeId, strFileTypeName))
  247.                 continue;       // just skip it
  248.  
  249.             if (bCompat)
  250.             {
  251.                 // path\DefaultIcon = path,1
  252.                 strTemp.Format(szDefaultIconFmt, (LPCTSTR)strFileTypeId);
  253.                 if (!SetRegKey(strTemp, strDefaultIconCommandLine))
  254.                     continue;       // just skip it
  255.             }
  256.  
  257.             // If MDI Application
  258.             if (!pTemplate->GetDocString(strTemp, CDocTemplate::windowTitle) ||
  259.                 strTemp.IsEmpty())
  260.             {
  261.                 // path\shell\open\ddeexec = [open("%1")]
  262.                 strTemp.Format(szShellOpenFmt, (LPCTSTR)strFileTypeId,
  263.                     (LPCTSTR)szDDEExec);
  264.                 if (!SetRegKey(strTemp, szDDEOpen))
  265.                     continue;       // just skip it
  266.  
  267.                 if (bCompat)
  268.                 {
  269.                     // path\shell\print\ddeexec = [print("%1")]
  270.                     strTemp.Format(szShellPrintFmt, (LPCTSTR)strFileTypeId,
  271.                         (LPCTSTR)szDDEExec);
  272.                     if (!SetRegKey(strTemp, szDDEPrint))
  273.                         continue;       // just skip it
  274.  
  275.                     // path\shell\printto\ddeexec = [printto("%1","%2","%3","%4")]
  276.                     strTemp.Format(szShellPrintToFmt, (LPCTSTR)strFileTypeId,
  277.                         (LPCTSTR)szDDEExec);
  278.                     if (!SetRegKey(strTemp, szDDEPrintTo))
  279.                         continue;       // just skip it
  280.  
  281.                     // path\shell\open\command = path /dde
  282.                     // path\shell\print\command = path /dde
  283.                     // path\shell\printto\command = path /dde
  284.                     strOpenCommandLine += szDDEArg;
  285.                     strPrintCommandLine += szDDEArg;
  286.                     strPrintToCommandLine += szDDEArg;
  287.                 }
  288.                 else
  289.                 {
  290.                     strOpenCommandLine += szOpenArg;
  291.                 }
  292.             }
  293.             else
  294.             {
  295.                 // path\shell\open\command = path filename
  296.                 // path\shell\print\command = path /p filename
  297.                 // path\shell\printto\command = path /pt filename printer driver port
  298.                 strOpenCommandLine += szOpenArg;
  299.                 if (bCompat)
  300.                 {
  301.                     strPrintCommandLine += szPrintArg;
  302.                     strPrintToCommandLine += szPrintToArg;
  303.                 }
  304.             }
  305.  
  306.             // path\shell\open\command = path filename
  307.             strTemp.Format(szShellOpenFmt, (LPCTSTR)strFileTypeId,
  308.                 (LPCTSTR)szCommand);
  309.             if (!SetRegKey(strTemp, strOpenCommandLine))
  310.                 continue;       // just skip it
  311.  
  312.             if (bCompat)
  313.             {
  314.                 // path\shell\print\command = path /p filename
  315.                 strTemp.Format(szShellPrintFmt, (LPCTSTR)strFileTypeId,
  316.                     (LPCTSTR)szCommand);
  317.                 if (!SetRegKey(strTemp, strPrintCommandLine))
  318.                     continue;       // just skip it
  319.  
  320.                 // path\shell\printto\command = path /pt filename printer driver port
  321.                 strTemp.Format(szShellPrintToFmt, (LPCTSTR)strFileTypeId,
  322.                     (LPCTSTR)szCommand);
  323.                 if (!SetRegKey(strTemp, strPrintToCommandLine))
  324.                     continue;       // just skip it
  325.             }
  326.  
  327.             pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt);
  328.             if (!strFilterExt.IsEmpty())
  329.             {
  330.                 ASSERT(strFilterExt[0] == '.');
  331.  
  332.                 LONG lSize = _MAX_PATH * 2;
  333.                 LONG lResult = ::RegQueryValue(HKEY_CLASSES_ROOT, strFilterExt,
  334.                     strTemp.GetBuffer(lSize), &lSize);
  335.                 strTemp.ReleaseBuffer();
  336.  
  337.                 if (lResult != ERROR_SUCCESS || strTemp.IsEmpty() ||
  338.                     strTemp == strFileTypeId)
  339.                 {
  340.                     // no association for that suffix
  341.                     if (!SetRegKey(strFilterExt, strFileTypeId))
  342.                         continue;
  343.  
  344.                     if (bCompat)
  345.                     {
  346.                         strTemp.Format(szShellNewFmt, (LPCTSTR)strFilterExt);
  347.                         (void)SetRegKey(strTemp, szShellNewValue, szShellNewValueName);
  348.                     }
  349.                 }
  350.             }
  351.         }
  352.     }
  353. }
  354. #endif
  355.  
  356. #ifdef AFX_CORE3_SEG
  357. #pragma code_seg(AFX_CORE3_SEG)
  358. #endif
  359.  
  360. static void AppendFilterSuffix(CString& filter, OPENFILENAME& ofn,
  361.     CDocTemplate* pTemplate, CString* pstrDefaultExt)
  362. {
  363.     ASSERT_VALID(pTemplate);
  364.     ASSERT_KINDOF(CDocTemplate, pTemplate);
  365.  
  366.     CString strFilterExt, strFilterName;
  367.     if (pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt) &&
  368.      !strFilterExt.IsEmpty() &&
  369.      pTemplate->GetDocString(strFilterName, CDocTemplate::filterName) &&
  370.      !strFilterName.IsEmpty())
  371.     {
  372.         // a file based document template - add to filter list
  373. #ifndef _MAC
  374.         ASSERT(strFilterExt[0] == '.');
  375. #endif
  376.         if (pstrDefaultExt != NULL)
  377.         {
  378.             // set the default extension
  379. #ifndef _MAC
  380.             *pstrDefaultExt = ((LPCTSTR)strFilterExt) + 1;  // skip the '.'
  381. #else
  382.             *pstrDefaultExt = strFilterExt;
  383. #endif
  384.             ofn.lpstrDefExt = (LPTSTR)(LPCTSTR)(*pstrDefaultExt);
  385.             ofn.nFilterIndex = ofn.nMaxCustFilter + 1;  // 1 based number
  386.         }
  387.  
  388.         // add to filter
  389.         filter += strFilterName;
  390.         ASSERT(!filter.IsEmpty());  // must have a file type name
  391.         filter += (TCHAR)'\0';  // next string please
  392. #ifndef _MAC
  393.         filter += (TCHAR)'*';
  394. #endif
  395.         filter += strFilterExt;
  396.         filter += (TCHAR)'\0';  // next string please
  397.         ofn.nMaxCustFilter++;
  398.     }
  399. }
  400.  
  401. // Get the best document template for the named file
  402.  
  403. class CNewTypeDlg : public CDialog
  404. {
  405. protected:
  406.     CPtrList*   m_pList;        // actually a list of doc templates
  407. public:
  408.     CDocTemplate*   m_pSelectedTemplate;
  409.  
  410. public:
  411.     //{{AFX_DATA(CNewTypeDlg)
  412.     enum { IDD = AFX_IDD_NEWTYPEDLG };
  413.     //}}AFX_DATA
  414.     CNewTypeDlg(CPtrList* pList) : CDialog(CNewTypeDlg::IDD)
  415.     {
  416.         m_pList = pList;
  417.         m_pSelectedTemplate = NULL;
  418.     }
  419.     ~CNewTypeDlg() { }
  420.  
  421. protected:
  422.     BOOL OnInitDialog();
  423.     void OnOK();
  424.     //{{AFX_MSG(CNewTypeDlg)
  425.     //}}AFX_MSG
  426.     DECLARE_MESSAGE_MAP()
  427. };
  428.  
  429. BEGIN_MESSAGE_MAP(CNewTypeDlg, CDialog)
  430.     //{{AFX_MSG_MAP(CNewTypeDlg)
  431.     ON_LBN_DBLCLK(AFX_IDC_LISTBOX, OnOK)
  432.     //}}AFX_MSG_MAP
  433. END_MESSAGE_MAP()
  434.  
  435. BOOL CNewTypeDlg::OnInitDialog()
  436. {
  437.     CListBox* pListBox = (CListBox*)GetDlgItem(AFX_IDC_LISTBOX);
  438.     ASSERT(pListBox != NULL);
  439.  
  440.     // fill with document templates in list
  441.     pListBox->ResetContent();
  442.  
  443.     POSITION pos = m_pList->GetHeadPosition();
  444.     // add all the CDocTemplates in the list by name
  445.     while (pos != NULL)
  446.     {
  447.         CDocTemplate* pTemplate = (CDocTemplate*)m_pList->GetNext(pos);
  448.         ASSERT_KINDOF(CDocTemplate, pTemplate);
  449.  
  450.         CString strTypeName;
  451.         if (pTemplate->GetDocString(strTypeName, CDocTemplate::fileNewName) &&
  452.            !strTypeName.IsEmpty())
  453.         {
  454.             // add it to the listbox
  455.             int nIndex = pListBox->AddString(strTypeName);
  456.             if (nIndex == -1)
  457.             {
  458.                 EndDialog(-1);
  459.                 return FALSE;
  460.             }
  461.             pListBox->SetItemDataPtr(nIndex, pTemplate);
  462.         }
  463.     }
  464.  
  465.     int nTemplates = pListBox->GetCount();
  466.     if (nTemplates == 0)
  467.     {
  468.         TRACE0("Error: no document templates to select from!\n");
  469.         EndDialog(-1); // abort
  470.     }
  471.     else if (nTemplates == 1)
  472.     {
  473.         // get the first/only item
  474.         m_pSelectedTemplate = (CDocTemplate*)pListBox->GetItemDataPtr(0);
  475.         ASSERT_VALID(m_pSelectedTemplate);
  476.         ASSERT_KINDOF(CDocTemplate, m_pSelectedTemplate);
  477.         EndDialog(IDOK);    // done
  478.     }
  479.     else
  480.     {
  481.         // set selection to the first one (NOT SORTED)
  482.         pListBox->SetCurSel(0);
  483.     }
  484.  
  485.     return CDialog::OnInitDialog();
  486. }
  487.  
  488. void CNewTypeDlg::OnOK()
  489. {
  490.     CListBox* pListBox = (CListBox*)GetDlgItem(AFX_IDC_LISTBOX);
  491.     ASSERT(pListBox != NULL);
  492.     // if listbox has selection, set the selected template
  493.     int nIndex;
  494.     if ((nIndex = pListBox->GetCurSel()) == -1)
  495.     {
  496.         // no selection
  497.         m_pSelectedTemplate = NULL;
  498.     }
  499.     else
  500.     {
  501.         m_pSelectedTemplate = (CDocTemplate*)pListBox->GetItemDataPtr(nIndex);
  502.         ASSERT_VALID(m_pSelectedTemplate);
  503.         ASSERT_KINDOF(CDocTemplate, m_pSelectedTemplate);
  504.     }
  505.     CDialog::OnOK();
  506. }
  507.  
  508. /////////////////////////////////////////////////////////////////////////////
  509. // CDocManager
  510.  
  511. void CDocManager::AddDocTemplate(CDocTemplate* pTemplate)
  512. {
  513.     if (pTemplate == NULL)
  514.     {
  515.         if (pStaticList != NULL)
  516.         {
  517.             POSITION pos = pStaticList->GetHeadPosition();
  518.             while (pos != NULL)
  519.             {
  520.                 CDocTemplate* pTemplate =
  521.                     (CDocTemplate*)pStaticList->GetNext(pos);
  522.                 AddDocTemplate(pTemplate);
  523.             }
  524.             delete pStaticList;
  525.             pStaticList = NULL;
  526.         }
  527.         bStaticInit = FALSE;
  528.     }
  529.     else
  530.     {
  531.         ASSERT_VALID(pTemplate);
  532.         ASSERT(m_templateList.Find(pTemplate, NULL) == NULL);// must not be in list
  533.         pTemplate->LoadTemplate();
  534.         m_templateList.AddTail(pTemplate);
  535.     }
  536. }
  537.  
  538. POSITION CDocManager::GetFirstDocTemplatePosition() const
  539. {
  540.     return m_templateList.GetHeadPosition();
  541. }
  542.  
  543. CDocTemplate* CDocManager::GetNextDocTemplate(POSITION& pos) const
  544. {
  545.     return (CDocTemplate*)m_templateList.GetNext(pos);
  546. }
  547.  
  548. BOOL CDocManager::SaveAllModified()
  549. {
  550.     POSITION pos = m_templateList.GetHeadPosition();
  551.     while (pos != NULL)
  552.     {
  553.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  554.         ASSERT_KINDOF(CDocTemplate, pTemplate);
  555.         if (!pTemplate->SaveAllModified())
  556.             return FALSE;
  557.     }
  558.     return TRUE;
  559. }
  560.  
  561. void CDocManager::CloseAllDocuments(BOOL bEndSession)
  562. {
  563.     POSITION pos = m_templateList.GetHeadPosition();
  564.     while (pos != NULL)
  565.     {
  566.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  567.         ASSERT_KINDOF(CDocTemplate, pTemplate);
  568.         pTemplate->CloseAllDocuments(bEndSession);
  569.     }
  570. }
  571.  
  572. BOOL CDocManager::DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate)
  573. {
  574.     CFileDialog dlgFile(bOpenFileDialog);
  575.  
  576.     CString title;
  577.     VERIFY(title.LoadString(nIDSTitle));
  578.  
  579.     dlgFile.m_ofn.Flags |= lFlags;
  580.  
  581.     CString strFilter;
  582.     CString strDefault;
  583.     if (pTemplate != NULL)
  584.     {
  585.         ASSERT_VALID(pTemplate);
  586.         AppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate, &strDefault);
  587.     }
  588.     else
  589.     {
  590.         // do for all doc template
  591.         POSITION pos = m_templateList.GetHeadPosition();
  592.         BOOL bFirst = TRUE;
  593.         while (pos != NULL)
  594.         {
  595.             CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  596.             AppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate,
  597.                 bFirst ? &strDefault : NULL);
  598.             bFirst = FALSE;
  599.         }
  600.     }
  601.  
  602.     // append the "*.*" all files filter
  603.     CString allFilter;
  604.     VERIFY(allFilter.LoadString(AFX_IDS_ALLFILTER));
  605.     strFilter += allFilter;
  606.     strFilter += (TCHAR)'\0';   // next string please
  607. #ifndef _MAC
  608.     strFilter += _T("*.*");
  609. #else
  610.     strFilter += _T("****");
  611. #endif
  612.     strFilter += (TCHAR)'\0';   // last string
  613.     dlgFile.m_ofn.nMaxCustFilter++;
  614.  
  615.     dlgFile.m_ofn.lpstrFilter = strFilter;
  616. #ifndef _MAC
  617.     dlgFile.m_ofn.lpstrTitle = title;
  618. #else
  619.     dlgFile.m_ofn.lpstrPrompt = title;
  620. #endif
  621.     dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);
  622.  
  623.     BOOL bResult = dlgFile.DoModal() == IDOK ? TRUE : FALSE;
  624.     fileName.ReleaseBuffer();
  625.     return bResult;
  626. }
  627.  
  628. #ifndef _MAC
  629. BOOL CDocManager::OnDDECommand(LPTSTR lpszCommand)
  630. {
  631.     CString strCommand = lpszCommand;
  632.     CDocument* pDoc = NULL;
  633.  
  634.     // open format is "[open("%s")]" - no whitespace allowed, one per line
  635.     // print format is "[print("%s")]" - no whitespace allowed, one per line
  636.     // print to format is "[printto("%s","%s","%s","%s")]" - no whitespace allowed, one per line
  637.     CCommandLineInfo cmdInfo;
  638.     cmdInfo.m_nShellCommand = CCommandLineInfo::FileDDE;
  639.  
  640.     if (strCommand.Left(7) == _T("[open(\""))
  641.     {
  642.         cmdInfo.m_nShellCommand = CCommandLineInfo::FileOpen;
  643.         strCommand = strCommand.Right(strCommand.GetLength() - 7);
  644.     }
  645.     else if (strCommand.Left(8) == _T("[print(\""))
  646.     {
  647.         cmdInfo.m_nShellCommand = CCommandLineInfo::FilePrint;
  648.         strCommand = strCommand.Right(strCommand.GetLength() - 8);
  649.     }
  650.     else if (strCommand.Left(10) == _T("[printto(\""))
  651.     {
  652.         cmdInfo.m_nShellCommand = CCommandLineInfo::FilePrintTo;\
  653.         strCommand = strCommand.Right(strCommand.GetLength() - 10);
  654.     }
  655.     else
  656.         return FALSE; // not a command we handle
  657.  
  658.     int i = strCommand.Find('"');
  659.     if (i == -1)
  660.         return FALSE; // illegally terminated
  661.  
  662.     cmdInfo.m_strFileName = strCommand.Left(i);
  663.     strCommand = strCommand.Right(strCommand.GetLength() - i);
  664.  
  665.     CCommandLineInfo* pOldInfo = NULL;
  666.     BOOL bRetVal = TRUE;
  667.  
  668.     // If we were started up for DDE retrieve the Show state
  669.     if (AfxGetApp()->m_pCmdInfo != NULL)
  670.     {
  671.         AfxGetApp()->m_nCmdShow = (int)AfxGetApp()->m_pCmdInfo;
  672.         AfxGetApp()->m_pCmdInfo = &cmdInfo;
  673.     }
  674.     else
  675.         pOldInfo = AfxGetApp()->m_pCmdInfo;
  676.  
  677.     if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileOpen)
  678.     {
  679.         // show the application window
  680.         CWnd* pMainWnd = AfxGetApp()->m_pMainWnd;
  681.         int nCmdShow = AfxGetApp()->m_nCmdShow;
  682.         if (nCmdShow == -1 || nCmdShow == SW_SHOWNORMAL)
  683.         {
  684.             if (pMainWnd->IsIconic())
  685.                 nCmdShow = SW_RESTORE;
  686.             else
  687.                 nCmdShow = SW_SHOW;
  688.         }
  689.         pMainWnd->ShowWindow(nCmdShow);
  690.         if (nCmdShow != SW_MINIMIZE)
  691.             pMainWnd->SetForegroundWindow();
  692.  
  693.         // then open the document
  694.         AfxGetApp()->OpenDocumentFile(cmdInfo.m_strFileName);
  695.  
  696.         // user is now "in control" of the application
  697.         if (!AfxOleGetUserCtrl())
  698.             AfxOleSetUserCtrl(TRUE);
  699.  
  700.         // next time, show the window as default
  701.         AfxGetApp()->m_nCmdShow = -1;
  702.         goto RestoreAndReturn;
  703.     }
  704.  
  705.     if (cmdInfo.m_nShellCommand == CCommandLineInfo::FilePrintTo)
  706.     {
  707.         if (strCommand.Left(3) != _T("\",\""))
  708.         {
  709.             bRetVal = FALSE;
  710.             goto RestoreAndReturn;
  711.         }
  712.         else
  713.         {
  714.             strCommand = strCommand.Right(strCommand.GetLength() - 3);
  715.             i = strCommand.Find('"');
  716.             if (i == -1)
  717.             {
  718.                 bRetVal = FALSE;
  719.                 goto RestoreAndReturn;
  720.             }
  721.             else
  722.             {
  723.                 cmdInfo.m_strPrinterName = strCommand.Left(i);
  724.                 strCommand = strCommand.Right(strCommand.GetLength() - i);
  725.             }
  726.         }
  727.  
  728.         if (strCommand.Left(3) != _T("\",\""))
  729.         {
  730.             bRetVal = FALSE;
  731.             goto RestoreAndReturn;
  732.         }
  733.         else
  734.         {
  735.             strCommand = strCommand.Right(strCommand.GetLength() - 3);
  736.             i = strCommand.Find('"');
  737.             if (i == -1)
  738.             {
  739.                 bRetVal = FALSE;
  740.                 goto RestoreAndReturn;
  741.             }
  742.             else
  743.             {
  744.                 cmdInfo.m_strDriverName = strCommand.Left(i);
  745.                 strCommand = strCommand.Right(strCommand.GetLength() - i);
  746.             }
  747.         }
  748.  
  749.         if (strCommand.Left(3) != _T("\",\""))
  750.         {
  751.             bRetVal = FALSE;
  752.             goto RestoreAndReturn;
  753.         }
  754.         else
  755.         {
  756.             strCommand = strCommand.Right(strCommand.GetLength() - 3);
  757.             i = strCommand.Find('"');
  758.             if (i == -1)
  759.             {
  760.                 bRetVal = FALSE;
  761.                 goto RestoreAndReturn;
  762.             }
  763.             else
  764.             {
  765.                 cmdInfo.m_strPortName = strCommand.Left(i);
  766.                 strCommand = strCommand.Right(strCommand.GetLength() - i);
  767.             }
  768.         }
  769.     }
  770.  
  771.     pDoc = AfxGetApp()->OpenDocumentFile(cmdInfo.m_strFileName);
  772.     AfxGetApp()->m_pCmdInfo = &cmdInfo;
  773.     AfxGetApp()->m_pMainWnd->SendMessage(WM_COMMAND, ID_FILE_PRINT_DIRECT);
  774.     AfxGetApp()->m_pCmdInfo = NULL;
  775.     pDoc->OnCloseDocument();
  776.  
  777.      // if the app was only started to process this command then close
  778.      if (!AfxOleGetUserCtrl())
  779.         AfxGetApp()->m_pMainWnd->PostMessage(WM_CLOSE);
  780.  
  781. RestoreAndReturn:
  782.     AfxGetApp()->m_pCmdInfo = pOldInfo;
  783.     return bRetVal;
  784. }
  785. #endif
  786.  
  787. void CDocManager::OnFileNew()
  788. {
  789.     if (m_templateList.IsEmpty())
  790.     {
  791.         TRACE0("Error: no document templates registered with CWinApp.\n");
  792.         AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
  793.         return;
  794.     }
  795.  
  796.     CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();
  797.     if (m_templateList.GetCount() > 1)
  798.     {
  799.         // more than one document template to choose from
  800.         // bring up dialog prompting user
  801.         CNewTypeDlg dlg(&m_templateList);
  802.         int nID = dlg.DoModal();
  803.         if (nID == IDOK)
  804.             pTemplate = dlg.m_pSelectedTemplate;
  805. #ifndef _MAC
  806.         else
  807. #else
  808.         else if (nID != IDCANCEL || GetLastError() != ERROR_INTERACTION_NOT_ALLOWED)
  809. #endif
  810.             return;     // none - cancel operation
  811.     }
  812.  
  813.     ASSERT(pTemplate != NULL);
  814.     ASSERT_KINDOF(CDocTemplate, pTemplate);
  815.  
  816.     pTemplate->OpenDocumentFile(NULL);
  817.         // if returns NULL, the user has already been alerted
  818. }
  819.  
  820. void CDocManager::OnFileOpen()
  821. {
  822.     // prompt the user (with all document templates)
  823.     CString newName;
  824.     if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,
  825.       OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL))
  826.         return; // open cancelled
  827.  
  828.     AfxGetApp()->OpenDocumentFile(newName);
  829.         // if returns NULL, the user has already been alerted
  830. }
  831.  
  832. #ifdef _DEBUG
  833. void CDocManager::AssertValid() const
  834. {
  835.     CObject::AssertValid();
  836.  
  837.     POSITION pos = m_templateList.GetHeadPosition();
  838.     while (pos != NULL)
  839.     {
  840.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  841.         ASSERT_VALID(pTemplate);
  842.     }
  843. }
  844.  
  845. void CDocManager::Dump(CDumpContext& dc) const
  846. {
  847.     CObject::Dump(dc);
  848.  
  849.     if (dc.GetDepth() != 0)
  850.     {
  851.         dc << "\nm_templateList[] = {";
  852.         POSITION pos = m_templateList.GetHeadPosition();
  853.         while (pos != NULL)
  854.         {
  855.             CDocTemplate* pTemplate =
  856.                 (CDocTemplate*)m_templateList.GetNext(pos);
  857.             dc << "\ntemplate " << pTemplate;
  858.         }
  859.         dc << "}";
  860.     }
  861.  
  862.     dc << "\n";
  863. }
  864. #endif
  865.  
  866. #ifdef AFX_CORE2_SEG
  867. #pragma code_seg(AFX_CORE2_SEG)
  868. #endif
  869.  
  870. CDocument* CDocManager::OpenDocumentFile(LPCTSTR lpszFileName)
  871. {
  872.     // find the highest confidence
  873.     POSITION pos = m_templateList.GetHeadPosition();
  874.     CDocTemplate::Confidence bestMatch = CDocTemplate::noAttempt;
  875.     CDocTemplate* pBestTemplate = NULL;
  876.     CDocument* pOpenDocument = NULL;
  877.  
  878.     TCHAR szPath[_MAX_PATH];
  879.     ASSERT(lstrlen(lpszFileName) < _countof(szPath));
  880. #ifndef _MAC
  881.     TCHAR szTemp[_MAX_PATH];
  882.     if (lpszFileName[0] == '\"')
  883.         ++lpszFileName;
  884.     lstrcpyn(szTemp, lpszFileName, _MAX_PATH);
  885.     LPTSTR lpszLast = _tcsrchr(szTemp, '\"');
  886.     if (lpszLast != NULL)
  887.         *lpszLast = 0;
  888.     AfxFullPath(szPath, szTemp);
  889.     TCHAR szLinkName[_MAX_PATH];
  890.     if (AfxResolveShortcut(AfxGetMainWnd(), szPath, szLinkName, _MAX_PATH))
  891.         lstrcpy(szPath, szLinkName);
  892.  
  893. #else
  894.     lstrcpyn(szPath, lpszFileName, _MAX_PATH);
  895.     WIN32_FIND_DATA fileData;
  896.     HANDLE hFind = FindFirstFile(lpszFileName, &fileData);
  897.     if (hFind != INVALID_HANDLE_VALUE)
  898.         VERIFY(FindClose(hFind));
  899.     else
  900.         fileData.dwFileType = 0;    // won't match any type
  901. #endif
  902.  
  903.     while (pos != NULL)
  904.     {
  905.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  906.         ASSERT_KINDOF(CDocTemplate, pTemplate);
  907.  
  908.         CDocTemplate::Confidence match;
  909.         ASSERT(pOpenDocument == NULL);
  910. #ifndef _MAC
  911.         match = pTemplate->MatchDocType(szPath, pOpenDocument);
  912. #else
  913.         match = pTemplate->MatchDocType(szPath, fileData.dwFileType, pOpenDocument);
  914. #endif
  915.         if (match > bestMatch)
  916.         {
  917.             bestMatch = match;
  918.             pBestTemplate = pTemplate;
  919.         }
  920.         if (match == CDocTemplate::yesAlreadyOpen)
  921.             break;      // stop here
  922.     }
  923.  
  924.     if (pOpenDocument != NULL)
  925.     {
  926.         POSITION pos = pOpenDocument->GetFirstViewPosition();
  927.         if (pos != NULL)
  928.         {
  929.             CView* pView = pOpenDocument->GetNextView(pos); // get first one
  930.             ASSERT_VALID(pView);
  931.             CFrameWnd* pFrame = pView->GetParentFrame();
  932.             if (pFrame != NULL)
  933.                 pFrame->ActivateFrame();
  934.             else
  935.                 TRACE0("Error: Can not find a frame for document to activate.\n");
  936.             CFrameWnd* pAppFrame;
  937.             if (pFrame != (pAppFrame = (CFrameWnd*)AfxGetApp()->m_pMainWnd))
  938.             {
  939.                 ASSERT_KINDOF(CFrameWnd, pAppFrame);
  940.                 pAppFrame->ActivateFrame();
  941.             }
  942.         }
  943.         else
  944.         {
  945.             TRACE0("Error: Can not find a view for document to activate.\n");
  946.         }
  947.         return pOpenDocument;
  948.     }
  949.  
  950.     if (pBestTemplate == NULL)
  951.     {
  952.         AfxMessageBox(AFX_IDP_FAILED_TO_OPEN_DOC);
  953.         return NULL;
  954.     }
  955.  
  956.     return pBestTemplate->OpenDocumentFile(szPath);
  957. }
  958.  
  959. int CDocManager::GetOpenDocumentCount()
  960. {
  961.     int nOpen = 0;
  962.     POSITION pos = m_templateList.GetHeadPosition();
  963.     while (pos != NULL)
  964.     {
  965.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  966.         POSITION pos2 = pTemplate->GetFirstDocPosition();
  967.         while (pos2)
  968.         {
  969.             if (pTemplate->GetNextDoc(pos2) != NULL)
  970.                 nOpen++;
  971.         }
  972.     }
  973.     return nOpen;
  974. }
  975.  
  976. #ifdef AFX_TERM_SEG
  977. #pragma code_seg(AFX_TERM_SEG)
  978. #endif
  979.  
  980. CDocManager::~CDocManager()
  981. {
  982.     // for cleanup - delete all document templates
  983.     POSITION pos = m_templateList.GetHeadPosition();
  984.     while (pos != NULL)
  985.     {
  986.         POSITION posTemplate = pos;
  987.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  988.         if (pTemplate->m_bAutoDelete)
  989.         {
  990.             m_templateList.RemoveAt(posTemplate);
  991.             delete (CDocTemplate*)pTemplate;
  992.         }
  993.     }
  994. }
  995.  
  996. #ifdef AFX_INIT_SEG
  997. #pragma code_seg(AFX_INIT_SEG)
  998. #endif
  999.  
  1000. IMPLEMENT_DYNAMIC(CDocManager, CObject)
  1001.  
  1002. /////////////////////////////////////////////////////////////////////////////
  1003.