home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / docmgr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-16  |  27.0 KB  |  999 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.  
  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. AFX_STATIC_DATA const TCHAR _afxShellOpenFmt[] = _T("%s\\shell\\open\\%s");
  23. AFX_STATIC_DATA const TCHAR _afxShellPrintFmt[] = _T("%s\\shell\\print\\%s");
  24. AFX_STATIC_DATA const TCHAR _afxShellPrintToFmt[] = _T("%s\\shell\\printto\\%s");
  25. AFX_STATIC_DATA const TCHAR _afxDefaultIconFmt[] = _T("%s\\DefaultIcon");
  26. AFX_STATIC_DATA const TCHAR _afxShellNewFmt[] = _T("%s\\ShellNew");
  27.  
  28. #define DEFAULT_ICON_INDEX 0
  29.  
  30. AFX_STATIC_DATA const TCHAR _afxIconIndexFmt[] = _T(",%d");
  31. AFX_STATIC_DATA const TCHAR _afxCommand[] = _T("command");
  32. AFX_STATIC_DATA const TCHAR _afxOpenArg[] = _T(" \"%1\"");
  33. AFX_STATIC_DATA const TCHAR _afxPrintArg[] = _T(" /p \"%1\"");
  34. AFX_STATIC_DATA const TCHAR _afxPrintToArg[] = _T(" /pt \"%1\" \"%2\" \"%3\" \"%4\"");
  35. AFX_STATIC_DATA const TCHAR _afxDDEArg[] = _T(" /dde");
  36.  
  37. AFX_STATIC_DATA const TCHAR _afxDDEExec[] = _T("ddeexec");
  38. AFX_STATIC_DATA const TCHAR _afxDDEOpen[] = _T("[open(\"%1\")]");
  39. AFX_STATIC_DATA const TCHAR _afxDDEPrint[] = _T("[print(\"%1\")]");
  40. AFX_STATIC_DATA const TCHAR _afxDDEPrintTo[] = _T("[printto(\"%1\",\"%2\",\"%3\",\"%4\")]");
  41.  
  42. AFX_STATIC_DATA const TCHAR _afxShellNewValueName[] = _T("NullFile");
  43. AFX_STATIC_DATA const TCHAR _afxShellNewValue[] = _T("");
  44.  
  45. // recursively remove a registry key if and only if it has no subkeys
  46.  
  47. BOOL AFXAPI _AfxDeleteRegKey(LPCTSTR lpszKey)
  48. {
  49.     // copy the string
  50.     LPTSTR lpszKeyCopy = _tcsdup(lpszKey);
  51.     LPTSTR lpszLast = lpszKeyCopy + lstrlen(lpszKeyCopy);
  52.  
  53.     // work until the end of the string
  54.     while (lpszLast != NULL)
  55.     {
  56.         *lpszLast = '\0';
  57.         lpszLast = _tcsdec(lpszKeyCopy, lpszLast);
  58.  
  59.         // try to open that key
  60.         HKEY hKey;
  61.         if (::RegOpenKey(HKEY_CLASSES_ROOT, lpszKeyCopy, &hKey) != ERROR_SUCCESS)
  62.             break;
  63.  
  64.         // enumerate the keys underneath
  65.         TCHAR szScrap[_MAX_PATH+1];
  66.         DWORD dwLen = _countof(szScrap);
  67.         BOOL bItExists = FALSE;
  68.  
  69.         if (::RegEnumKey(hKey, 0, szScrap, dwLen) == ERROR_SUCCESS)
  70.             bItExists = TRUE;
  71.         ::RegCloseKey(hKey);
  72.  
  73.         // found one?  quit looping
  74.         if (bItExists)
  75.             break;
  76.  
  77.         // otherwise, delete and find the previous backwhack
  78.         ::RegDeleteKey(HKEY_CLASSES_ROOT, lpszKeyCopy);
  79.         lpszLast = _tcsrchr(lpszKeyCopy, '\\');
  80.     }
  81.  
  82.     // release the string and return
  83.     free(lpszKeyCopy);
  84.     return TRUE;
  85. }
  86.  
  87. AFX_STATIC BOOL AFXAPI
  88. _AfxSetRegKey(LPCTSTR lpszKey, LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL)
  89. {
  90.     if (lpszValueName == NULL)
  91.     {
  92.         if (::RegSetValue(HKEY_CLASSES_ROOT, lpszKey, REG_SZ,
  93.               lpszValue, lstrlen(lpszValue) * sizeof(TCHAR)) != ERROR_SUCCESS)
  94.         {
  95.             TRACE1("Warning: registration database update failed for key '%s'.\n",
  96.                 lpszKey);
  97.             return FALSE;
  98.         }
  99.         return TRUE;
  100.     }
  101.     else
  102.     {
  103.         HKEY hKey;
  104.  
  105.         if(::RegCreateKey(HKEY_CLASSES_ROOT, lpszKey, &hKey) == ERROR_SUCCESS)
  106.         {
  107.             LONG lResult = ::RegSetValueEx(hKey, lpszValueName, 0, REG_SZ,
  108.                 (CONST BYTE*)lpszValue, (lstrlen(lpszValue) + 1) * sizeof(TCHAR));
  109.  
  110.             if(::RegCloseKey(hKey) == ERROR_SUCCESS && lResult == ERROR_SUCCESS)
  111.                 return TRUE;
  112.         }
  113.         TRACE1("Warning: registration database update failed for key '%s'.\n", lpszKey);
  114.         return FALSE;
  115.     }
  116. }
  117.  
  118. CDocManager::CDocManager()
  119. {
  120. }
  121.  
  122. void CDocManager::UnregisterShellFileTypes()
  123. {
  124.     ASSERT(!m_templateList.IsEmpty());  // must have some doc templates
  125.  
  126.     CString strPathName, strTemp;
  127.  
  128.     AfxGetModuleShortFileName(AfxGetInstanceHandle(), strPathName);
  129.  
  130.     POSITION pos = m_templateList.GetHeadPosition();
  131.     for (int nTemplateIndex = 1; pos != NULL; nTemplateIndex++)
  132.     {
  133.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  134.  
  135.         CString strFilterExt, strFileTypeId, strFileTypeName;
  136.         if (pTemplate->GetDocString(strFileTypeId,
  137.            CDocTemplate::regFileTypeId) && !strFileTypeId.IsEmpty())
  138.         {
  139.             // enough info to register it
  140.             if (!pTemplate->GetDocString(strFileTypeName,
  141.                CDocTemplate::regFileTypeName))
  142.                 strFileTypeName = strFileTypeId;    // use id name
  143.  
  144.             ASSERT(strFileTypeId.Find(' ') == -1);  // no spaces allowed
  145.  
  146.             strTemp.Format(_afxDefaultIconFmt, (LPCTSTR)strFileTypeId);
  147.             _AfxDeleteRegKey(strTemp);
  148.  
  149.             // If MDI Application
  150.             if (!pTemplate->GetDocString(strTemp, CDocTemplate::windowTitle) ||
  151.                 strTemp.IsEmpty())
  152.             {
  153.                 // path\shell\open\ddeexec = [open("%1")]
  154.                 strTemp.Format(_afxShellOpenFmt, (LPCTSTR)strFileTypeId,
  155.                     (LPCTSTR)_afxDDEExec);
  156.                 _AfxDeleteRegKey(strTemp);
  157.  
  158.                 // path\shell\print\ddeexec = [print("%1")]
  159.                 strTemp.Format(_afxShellPrintFmt, (LPCTSTR)strFileTypeId,
  160.                     (LPCTSTR)_afxDDEExec);
  161.                 _AfxDeleteRegKey(strTemp);
  162.  
  163.                 // path\shell\printto\ddeexec = [printto("%1","%2","%3","%4")]
  164.                 strTemp.Format(_afxShellPrintToFmt, (LPCTSTR)strFileTypeId,
  165.                     (LPCTSTR)_afxDDEExec);
  166.                 _AfxDeleteRegKey(strTemp);
  167.             }
  168.  
  169.             // path\shell\open\command = path filename
  170.             strTemp.Format(_afxShellOpenFmt, (LPCTSTR)strFileTypeId,
  171.                 (LPCTSTR)_afxCommand);
  172.             _AfxDeleteRegKey(strTemp);
  173.  
  174.             // path\shell\print\command = path /p filename
  175.             strTemp.Format(_afxShellPrintFmt, (LPCTSTR)strFileTypeId,
  176.                 (LPCTSTR)_afxCommand);
  177.             _AfxDeleteRegKey(strTemp);
  178.  
  179.             // path\shell\printto\command = path /pt filename printer driver port
  180.             strTemp.Format(_afxShellPrintToFmt, (LPCTSTR)strFileTypeId,
  181.                 (LPCTSTR)_afxCommand);
  182.             _AfxDeleteRegKey(strTemp);
  183.  
  184.             pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt);
  185.             if (!strFilterExt.IsEmpty())
  186.             {
  187.                 ASSERT(strFilterExt[0] == '.');
  188.  
  189.                 LONG lSize = _MAX_PATH * 2;
  190.                 LONG lResult = ::RegQueryValue(HKEY_CLASSES_ROOT, strFilterExt,
  191.                     strTemp.GetBuffer(lSize), &lSize);
  192.                 strTemp.ReleaseBuffer();
  193.  
  194.                 if (lResult != ERROR_SUCCESS || strTemp.IsEmpty() ||
  195.                     strTemp == strFileTypeId)
  196.                 {
  197.                     strTemp.Format(_afxShellNewFmt, (LPCTSTR)strFilterExt);
  198.                     _AfxDeleteRegKey(strTemp);
  199.  
  200.                     // no association for that suffix
  201.                     _AfxDeleteRegKey(strFilterExt);
  202.                 }
  203.             }
  204.         }
  205.     }
  206. }
  207.  
  208.  
  209. void CDocManager::RegisterShellFileTypes(BOOL bCompat)
  210. {
  211.     ASSERT(!m_templateList.IsEmpty());  // must have some doc templates
  212.  
  213.     CString strPathName, strTemp;
  214.  
  215.     AfxGetModuleShortFileName(AfxGetInstanceHandle(), strPathName);
  216.  
  217.     POSITION pos = m_templateList.GetHeadPosition();
  218.     for (int nTemplateIndex = 1; pos != NULL; nTemplateIndex++)
  219.     {
  220.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  221.  
  222.         CString strOpenCommandLine = strPathName;
  223.         CString strPrintCommandLine = strPathName;
  224.         CString strPrintToCommandLine = strPathName;
  225.         CString strDefaultIconCommandLine = strPathName;
  226.  
  227.         if (bCompat)
  228.         {
  229.             CString strIconIndex;
  230.             HICON hIcon = ::ExtractIcon(AfxGetInstanceHandle(), strPathName, nTemplateIndex);
  231.             if (hIcon != NULL)
  232.             {
  233.                 strIconIndex.Format(_afxIconIndexFmt, nTemplateIndex);
  234.                 DestroyIcon(hIcon);
  235.             }
  236.             else
  237.             {
  238.                 strIconIndex.Format(_afxIconIndexFmt, DEFAULT_ICON_INDEX);
  239.             }
  240.             strDefaultIconCommandLine += strIconIndex;
  241.         }
  242.  
  243.         CString strFilterExt, strFileTypeId, strFileTypeName;
  244.         if (pTemplate->GetDocString(strFileTypeId,
  245.            CDocTemplate::regFileTypeId) && !strFileTypeId.IsEmpty())
  246.         {
  247.             // enough info to register it
  248.             if (!pTemplate->GetDocString(strFileTypeName,
  249.                CDocTemplate::regFileTypeName))
  250.                 strFileTypeName = strFileTypeId;    // use id name
  251.  
  252.             ASSERT(strFileTypeId.Find(' ') == -1);  // no spaces allowed
  253.  
  254.             // first register the type ID of our server
  255.             if (!_AfxSetRegKey(strFileTypeId, strFileTypeName))
  256.                 continue;       // just skip it
  257.  
  258.             if (bCompat)
  259.             {
  260.                 // path\DefaultIcon = path,1
  261.                 strTemp.Format(_afxDefaultIconFmt, (LPCTSTR)strFileTypeId);
  262.                 if (!_AfxSetRegKey(strTemp, strDefaultIconCommandLine))
  263.                     continue;       // just skip it
  264.             }
  265.  
  266.             // If MDI Application
  267.             if (!pTemplate->GetDocString(strTemp, CDocTemplate::windowTitle) ||
  268.                 strTemp.IsEmpty())
  269.             {
  270.                 // path\shell\open\ddeexec = [open("%1")]
  271.                 strTemp.Format(_afxShellOpenFmt, (LPCTSTR)strFileTypeId,
  272.                     (LPCTSTR)_afxDDEExec);
  273.                 if (!_AfxSetRegKey(strTemp, _afxDDEOpen))
  274.                     continue;       // just skip it
  275.  
  276.                 if (bCompat)
  277.                 {
  278.                     // path\shell\print\ddeexec = [print("%1")]
  279.                     strTemp.Format(_afxShellPrintFmt, (LPCTSTR)strFileTypeId,
  280.                         (LPCTSTR)_afxDDEExec);
  281.                     if (!_AfxSetRegKey(strTemp, _afxDDEPrint))
  282.                         continue;       // just skip it
  283.  
  284.                     // path\shell\printto\ddeexec = [printto("%1","%2","%3","%4")]
  285.                     strTemp.Format(_afxShellPrintToFmt, (LPCTSTR)strFileTypeId,
  286.                         (LPCTSTR)_afxDDEExec);
  287.                     if (!_AfxSetRegKey(strTemp, _afxDDEPrintTo))
  288.                         continue;       // just skip it
  289.  
  290.                     // path\shell\open\command = path /dde
  291.                     // path\shell\print\command = path /dde
  292.                     // path\shell\printto\command = path /dde
  293.                     strOpenCommandLine += _afxDDEArg;
  294.                     strPrintCommandLine += _afxDDEArg;
  295.                     strPrintToCommandLine += _afxDDEArg;
  296.                 }
  297.                 else
  298.                 {
  299.                     strOpenCommandLine += _afxOpenArg;
  300.                 }
  301.             }
  302.             else
  303.             {
  304.                 // path\shell\open\command = path filename
  305.                 // path\shell\print\command = path /p filename
  306.                 // path\shell\printto\command = path /pt filename printer driver port
  307.                 strOpenCommandLine += _afxOpenArg;
  308.                 if (bCompat)
  309.                 {
  310.                     strPrintCommandLine += _afxPrintArg;
  311.                     strPrintToCommandLine += _afxPrintToArg;
  312.                 }
  313.             }
  314.  
  315.             // path\shell\open\command = path filename
  316.             strTemp.Format(_afxShellOpenFmt, (LPCTSTR)strFileTypeId,
  317.                 (LPCTSTR)_afxCommand);
  318.             if (!_AfxSetRegKey(strTemp, strOpenCommandLine))
  319.                 continue;       // just skip it
  320.  
  321.             if (bCompat)
  322.             {
  323.                 // path\shell\print\command = path /p filename
  324.                 strTemp.Format(_afxShellPrintFmt, (LPCTSTR)strFileTypeId,
  325.                     (LPCTSTR)_afxCommand);
  326.                 if (!_AfxSetRegKey(strTemp, strPrintCommandLine))
  327.                     continue;       // just skip it
  328.  
  329.                 // path\shell\printto\command = path /pt filename printer driver port
  330.                 strTemp.Format(_afxShellPrintToFmt, (LPCTSTR)strFileTypeId,
  331.                     (LPCTSTR)_afxCommand);
  332.                 if (!_AfxSetRegKey(strTemp, strPrintToCommandLine))
  333.                     continue;       // just skip it
  334.             }
  335.  
  336.             pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt);
  337.             if (!strFilterExt.IsEmpty())
  338.             {
  339.                 ASSERT(strFilterExt[0] == '.');
  340.  
  341.                 LONG lSize = _MAX_PATH * 2;
  342.                 LONG lResult = ::RegQueryValue(HKEY_CLASSES_ROOT, strFilterExt,
  343.                     strTemp.GetBuffer(lSize), &lSize);
  344.                 strTemp.ReleaseBuffer();
  345.  
  346.                 if (lResult != ERROR_SUCCESS || strTemp.IsEmpty() ||
  347.                     strTemp == strFileTypeId)
  348.                 {
  349.                     // no association for that suffix
  350.                     if (!_AfxSetRegKey(strFilterExt, strFileTypeId))
  351.                         continue;
  352.  
  353.                     if (bCompat)
  354.                     {
  355.                         strTemp.Format(_afxShellNewFmt, (LPCTSTR)strFilterExt);
  356.                         (void)_AfxSetRegKey(strTemp, _afxShellNewValue, _afxShellNewValueName);
  357.                     }
  358.                 }
  359.             }
  360.         }
  361.     }
  362. }
  363.  
  364. #ifdef AFX_CORE3_SEG
  365. #pragma code_seg(AFX_CORE3_SEG)
  366. #endif
  367.  
  368. AFX_STATIC void AFXAPI _AfxAppendFilterSuffix(CString& filter, OPENFILENAME& ofn,
  369.     CDocTemplate* pTemplate, CString* pstrDefaultExt)
  370. {
  371.     ASSERT_VALID(pTemplate);
  372.     ASSERT_KINDOF(CDocTemplate, pTemplate);
  373.  
  374.     CString strFilterExt, strFilterName;
  375.     if (pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt) &&
  376.      !strFilterExt.IsEmpty() &&
  377.      pTemplate->GetDocString(strFilterName, CDocTemplate::filterName) &&
  378.      !strFilterName.IsEmpty())
  379.     {
  380.         // a file based document template - add to filter list
  381.         ASSERT(strFilterExt[0] == '.');
  382.         if (pstrDefaultExt != NULL)
  383.         {
  384.             // set the default extension
  385.             *pstrDefaultExt = ((LPCTSTR)strFilterExt) + 1;  // skip the '.'
  386.             ofn.lpstrDefExt = (LPTSTR)(LPCTSTR)(*pstrDefaultExt);
  387.             ofn.nFilterIndex = ofn.nMaxCustFilter + 1;  // 1 based number
  388.         }
  389.  
  390.         // add to filter
  391.         filter += strFilterName;
  392.         ASSERT(!filter.IsEmpty());  // must have a file type name
  393.         filter += (TCHAR)'\0';  // next string please
  394.         filter += (TCHAR)'*';
  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.         _AfxAppendFilterSuffix(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.             _AfxAppendFilterSuffix(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.     strFilter += _T("*.*");
  608.     strFilter += (TCHAR)'\0';   // last string
  609.     dlgFile.m_ofn.nMaxCustFilter++;
  610.  
  611.     dlgFile.m_ofn.lpstrFilter = strFilter;
  612.     dlgFile.m_ofn.lpstrTitle = title;
  613.     dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);
  614.  
  615.     int nResult = dlgFile.DoModal();
  616.     fileName.ReleaseBuffer();
  617.     return nResult == IDOK;
  618. }
  619.  
  620. int CDocManager::GetDocumentCount()
  621. {
  622.     // count all documents
  623.     int nCount = 0;
  624.     POSITION pos = m_templateList.GetHeadPosition();
  625.     while (pos != NULL)
  626.     {
  627.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  628.         POSITION pos2 = pTemplate->GetFirstDocPosition();
  629.         while (pos2 != NULL)
  630.         {
  631.             pTemplate->GetNextDoc(pos2);
  632.             ++nCount;
  633.         }
  634.     }
  635.     return nCount;
  636. }
  637.  
  638. BOOL CDocManager::OnDDECommand(LPTSTR lpszCommand)
  639. {
  640.     CString strCommand = lpszCommand;
  641.     CDocument* pDoc = NULL;
  642.  
  643.     // open format is "[open("%s")]" - no whitespace allowed, one per line
  644.     // print format is "[print("%s")]" - no whitespace allowed, one per line
  645.     // print to format is "[printto("%s","%s","%s","%s")]" - no whitespace allowed, one per line
  646.     CCommandLineInfo cmdInfo;
  647.     cmdInfo.m_nShellCommand = CCommandLineInfo::FileDDE;
  648.  
  649.     if (strCommand.Left(7) == _T("[open(\""))
  650.     {
  651.         cmdInfo.m_nShellCommand = CCommandLineInfo::FileOpen;
  652.         strCommand = strCommand.Right(strCommand.GetLength() - 7);
  653.     }
  654.     else if (strCommand.Left(8) == _T("[print(\""))
  655.     {
  656.         cmdInfo.m_nShellCommand = CCommandLineInfo::FilePrint;
  657.         strCommand = strCommand.Right(strCommand.GetLength() - 8);
  658.     }
  659.     else if (strCommand.Left(10) == _T("[printto(\""))
  660.     {
  661.         cmdInfo.m_nShellCommand = CCommandLineInfo::FilePrintTo;\
  662.         strCommand = strCommand.Right(strCommand.GetLength() - 10);
  663.     }
  664.     else
  665.         return FALSE; // not a command we handle
  666.  
  667.     int i = strCommand.Find('"');
  668.     if (i == -1)
  669.         return FALSE; // illegally terminated
  670.  
  671.     cmdInfo.m_strFileName = strCommand.Left(i);
  672.     strCommand = strCommand.Right(strCommand.GetLength() - i);
  673.  
  674.     CCommandLineInfo* pOldInfo = NULL;
  675.     BOOL bRetVal = TRUE;
  676.  
  677.     // If we were started up for DDE retrieve the Show state
  678.     if (AfxGetApp()->m_pCmdInfo != NULL)
  679.     {
  680.         AfxGetApp()->m_nCmdShow = (int)AfxGetApp()->m_pCmdInfo;
  681.         AfxGetApp()->m_pCmdInfo = &cmdInfo;
  682.     }
  683.     else
  684.         pOldInfo = AfxGetApp()->m_pCmdInfo;
  685.  
  686.     if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileOpen)
  687.     {
  688.         // show the application window
  689.         CWnd* pMainWnd = AfxGetApp()->m_pMainWnd;
  690.         int nCmdShow = AfxGetApp()->m_nCmdShow;
  691.         if (nCmdShow == -1 || nCmdShow == SW_SHOWNORMAL)
  692.         {
  693.             if (pMainWnd->IsIconic())
  694.                 nCmdShow = SW_RESTORE;
  695.             else
  696.                 nCmdShow = SW_SHOW;
  697.         }
  698.         pMainWnd->ShowWindow(nCmdShow);
  699.         if (nCmdShow != SW_MINIMIZE)
  700.             pMainWnd->SetForegroundWindow();
  701.  
  702.         // then open the document
  703.         AfxGetApp()->OpenDocumentFile(cmdInfo.m_strFileName);
  704.  
  705.         // user is now "in control" of the application
  706.         if (!AfxOleGetUserCtrl())
  707.             AfxOleSetUserCtrl(TRUE);
  708.  
  709.         // next time, show the window as default
  710.         AfxGetApp()->m_nCmdShow = -1;
  711.         goto RestoreAndReturn;
  712.     }
  713.  
  714.     if (cmdInfo.m_nShellCommand == CCommandLineInfo::FilePrintTo)
  715.     {
  716.         if (strCommand.Left(3) != _T("\",\""))
  717.         {
  718.             bRetVal = FALSE;
  719.             goto RestoreAndReturn;
  720.         }
  721.         else
  722.         {
  723.             strCommand = strCommand.Right(strCommand.GetLength() - 3);
  724.             i = strCommand.Find('"');
  725.             if (i == -1)
  726.             {
  727.                 bRetVal = FALSE;
  728.                 goto RestoreAndReturn;
  729.             }
  730.             else
  731.             {
  732.                 cmdInfo.m_strPrinterName = strCommand.Left(i);
  733.                 strCommand = strCommand.Right(strCommand.GetLength() - i);
  734.             }
  735.         }
  736.  
  737.         if (strCommand.Left(3) != _T("\",\""))
  738.         {
  739.             bRetVal = FALSE;
  740.             goto RestoreAndReturn;
  741.         }
  742.         else
  743.         {
  744.             strCommand = strCommand.Right(strCommand.GetLength() - 3);
  745.             i = strCommand.Find('"');
  746.             if (i == -1)
  747.             {
  748.                 bRetVal = FALSE;
  749.                 goto RestoreAndReturn;
  750.             }
  751.             else
  752.             {
  753.                 cmdInfo.m_strDriverName = strCommand.Left(i);
  754.                 strCommand = strCommand.Right(strCommand.GetLength() - i);
  755.             }
  756.         }
  757.  
  758.         if (strCommand.Left(3) != _T("\",\""))
  759.         {
  760.             bRetVal = FALSE;
  761.             goto RestoreAndReturn;
  762.         }
  763.         else
  764.         {
  765.             strCommand = strCommand.Right(strCommand.GetLength() - 3);
  766.             i = strCommand.Find('"');
  767.             if (i == -1)
  768.             {
  769.                 bRetVal = FALSE;
  770.                 goto RestoreAndReturn;
  771.             }
  772.             else
  773.             {
  774.                 cmdInfo.m_strPortName = strCommand.Left(i);
  775.                 strCommand = strCommand.Right(strCommand.GetLength() - i);
  776.             }
  777.         }
  778.     }
  779.  
  780.     // get document count before opening it
  781.     int nOldCount; nOldCount = GetDocumentCount();
  782.  
  783.     // open the document, then print it.
  784.     pDoc = AfxGetApp()->OpenDocumentFile(cmdInfo.m_strFileName);
  785.     AfxGetApp()->m_pCmdInfo = &cmdInfo;
  786.     AfxGetApp()->m_pMainWnd->SendMessage(WM_COMMAND, ID_FILE_PRINT_DIRECT);
  787.     AfxGetApp()->m_pCmdInfo = NULL;
  788.  
  789.     // close the document if it wasn't open previously (based on doc count)
  790.     if (GetDocumentCount() > nOldCount)
  791.         pDoc->OnCloseDocument();
  792.  
  793.      // if the app was only started to process this command then close
  794.      if (!AfxOleGetUserCtrl())
  795.         AfxGetApp()->m_pMainWnd->PostMessage(WM_CLOSE);
  796.  
  797. RestoreAndReturn:
  798.     AfxGetApp()->m_pCmdInfo = pOldInfo;
  799.     return bRetVal;
  800. }
  801.  
  802. void CDocManager::OnFileNew()
  803. {
  804.     if (m_templateList.IsEmpty())
  805.     {
  806.         TRACE0("Error: no document templates registered with CWinApp.\n");
  807.         AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
  808.         return;
  809.     }
  810.  
  811.     CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();
  812.     if (m_templateList.GetCount() > 1)
  813.     {
  814.         // more than one document template to choose from
  815.         // bring up dialog prompting user
  816.         CNewTypeDlg dlg(&m_templateList);
  817.         int nID = dlg.DoModal();
  818.         if (nID == IDOK)
  819.             pTemplate = dlg.m_pSelectedTemplate;
  820.         else
  821.             return;     // none - cancel operation
  822.     }
  823.  
  824.     ASSERT(pTemplate != NULL);
  825.     ASSERT_KINDOF(CDocTemplate, pTemplate);
  826.  
  827.     pTemplate->OpenDocumentFile(NULL);
  828.         // if returns NULL, the user has already been alerted
  829. }
  830.  
  831. void CDocManager::OnFileOpen()
  832. {
  833.     // prompt the user (with all document templates)
  834.     CString newName;
  835.     if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,
  836.       OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL))
  837.         return; // open cancelled
  838.  
  839.     AfxGetApp()->OpenDocumentFile(newName);
  840.         // if returns NULL, the user has already been alerted
  841. }
  842.  
  843. #ifdef _DEBUG
  844. void CDocManager::AssertValid() const
  845. {
  846.     CObject::AssertValid();
  847.  
  848.     POSITION pos = m_templateList.GetHeadPosition();
  849.     while (pos != NULL)
  850.     {
  851.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  852.         ASSERT_VALID(pTemplate);
  853.     }
  854. }
  855.  
  856. void CDocManager::Dump(CDumpContext& dc) const
  857. {
  858.     CObject::Dump(dc);
  859.  
  860.     if (dc.GetDepth() != 0)
  861.     {
  862.         dc << "\nm_templateList[] = {";
  863.         POSITION pos = m_templateList.GetHeadPosition();
  864.         while (pos != NULL)
  865.         {
  866.             CDocTemplate* pTemplate =
  867.                 (CDocTemplate*)m_templateList.GetNext(pos);
  868.             dc << "\ntemplate " << pTemplate;
  869.         }
  870.         dc << "}";
  871.     }
  872.  
  873.     dc << "\n";
  874. }
  875. #endif
  876.  
  877. #ifdef AFX_CORE2_SEG
  878. #pragma code_seg(AFX_CORE2_SEG)
  879. #endif
  880.  
  881. CDocument* CDocManager::OpenDocumentFile(LPCTSTR lpszFileName)
  882. {
  883.     // find the highest confidence
  884.     POSITION pos = m_templateList.GetHeadPosition();
  885.     CDocTemplate::Confidence bestMatch = CDocTemplate::noAttempt;
  886.     CDocTemplate* pBestTemplate = NULL;
  887.     CDocument* pOpenDocument = NULL;
  888.  
  889.     TCHAR szPath[_MAX_PATH];
  890.     ASSERT(lstrlen(lpszFileName) < _countof(szPath));
  891.     TCHAR szTemp[_MAX_PATH];
  892.     if (lpszFileName[0] == '\"')
  893.         ++lpszFileName;
  894.     lstrcpyn(szTemp, lpszFileName, _MAX_PATH);
  895.     LPTSTR lpszLast = _tcsrchr(szTemp, '\"');
  896.     if (lpszLast != NULL)
  897.         *lpszLast = 0;
  898.     AfxFullPath(szPath, szTemp);
  899.     TCHAR szLinkName[_MAX_PATH];
  900.     if (AfxResolveShortcut(AfxGetMainWnd(), szPath, szLinkName, _MAX_PATH))
  901.         lstrcpy(szPath, szLinkName);
  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.         match = pTemplate->MatchDocType(szPath, pOpenDocument);
  911.         if (match > bestMatch)
  912.         {
  913.             bestMatch = match;
  914.             pBestTemplate = pTemplate;
  915.         }
  916.         if (match == CDocTemplate::yesAlreadyOpen)
  917.             break;      // stop here
  918.     }
  919.  
  920.     if (pOpenDocument != NULL)
  921.     {
  922.         POSITION pos = pOpenDocument->GetFirstViewPosition();
  923.         if (pos != NULL)
  924.         {
  925.             CView* pView = pOpenDocument->GetNextView(pos); // get first one
  926.             ASSERT_VALID(pView);
  927.             CFrameWnd* pFrame = pView->GetParentFrame();
  928.             if (pFrame != NULL)
  929.                 pFrame->ActivateFrame();
  930.             else
  931.                 TRACE0("Error: Can not find a frame for document to activate.\n");
  932.             CFrameWnd* pAppFrame;
  933.             if (pFrame != (pAppFrame = (CFrameWnd*)AfxGetApp()->m_pMainWnd))
  934.             {
  935.                 ASSERT_KINDOF(CFrameWnd, pAppFrame);
  936.                 pAppFrame->ActivateFrame();
  937.             }
  938.         }
  939.         else
  940.         {
  941.             TRACE0("Error: Can not find a view for document to activate.\n");
  942.         }
  943.         return pOpenDocument;
  944.     }
  945.  
  946.     if (pBestTemplate == NULL)
  947.     {
  948.         AfxMessageBox(AFX_IDP_FAILED_TO_OPEN_DOC);
  949.         return NULL;
  950.     }
  951.  
  952.     return pBestTemplate->OpenDocumentFile(szPath);
  953. }
  954.  
  955. int CDocManager::GetOpenDocumentCount()
  956. {
  957.     int nOpen = 0;
  958.     POSITION pos = m_templateList.GetHeadPosition();
  959.     while (pos != NULL)
  960.     {
  961.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  962.         POSITION pos2 = pTemplate->GetFirstDocPosition();
  963.         while (pos2)
  964.         {
  965.             if (pTemplate->GetNextDoc(pos2) != NULL)
  966.                 nOpen++;
  967.         }
  968.     }
  969.     return nOpen;
  970. }
  971.  
  972. #ifdef AFX_TERM_SEG
  973. #pragma code_seg(AFX_TERM_SEG)
  974. #endif
  975.  
  976. CDocManager::~CDocManager()
  977. {
  978.     // for cleanup - delete all document templates
  979.     POSITION pos = m_templateList.GetHeadPosition();
  980.     while (pos != NULL)
  981.     {
  982.         POSITION posTemplate = pos;
  983.         CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
  984.         if (pTemplate->m_bAutoDelete)
  985.         {
  986.             m_templateList.RemoveAt(posTemplate);
  987.             delete (CDocTemplate*)pTemplate;
  988.         }
  989.     }
  990. }
  991.  
  992. #ifdef AFX_INIT_SEG
  993. #pragma code_seg(AFX_INIT_SEG)
  994. #endif
  995.  
  996. IMPLEMENT_DYNAMIC(CDocManager, CObject)
  997.  
  998. /////////////////////////////////////////////////////////////////////////////
  999.