/*
JME modified from Microsoft MFC code.
*/
#include "stdafx.h"
#include "DocManagerEx.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
// MultiExt: needed for a bunch of MFC private constants and functions
#include "afxpriv.h"
BOOL AFXAPI AfxFullPath(LPTSTR lpszPathOut, LPCTSTR lpszFileIn);
BOOL AFXAPI AfxComparePath(LPCTSTR lpszPath1, LPCTSTR lpszPath2);
BOOL AFXAPI AfxResolveShortcut(CWnd* pWnd, LPCTSTR pszShortcutFile,
LPTSTR pszPath, int cchPath);
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
enum
{
e_szShellOpenFmt,
e_szShellPrintFmt,
e_szShellPrintToFmt,
e_szDefaultIconFmt,
e_szShellNewFmt,
e_szIconIndexFmt,
e_szCommand,
e_szOpenArg,
e_szPrintArg,
e_szPrintToArg,
e_szDDEArg,
e_szDDEExec,
e_szDDEOpen,
e_szDDEPrint,
e_szDDEPrintTo,
e_szShellNewValueName,
e_szShellNewValue,
e_szMax
};
static LPCTSTR GetString(unsigned int index)
{
static const TCHAR szShellOpenFmt[] = _T("%s\\shell\\open\\%s");
static const TCHAR szShellPrintFmt[] = _T("%s\\shell\\print\\%s");
static const TCHAR szShellPrintToFmt[] = _T("%s\\shell\\printto\\%s");
static const TCHAR szDefaultIconFmt[] = _T("%s\\DefaultIcon");
static const TCHAR szShellNewFmt[] = _T("%s\\ShellNew");
static const TCHAR szIconIndexFmt[] = _T(",%d");
static const TCHAR szCommand[] = _T("command");
static const TCHAR szOpenArg[] = _T(" \"%1\"");
static const TCHAR szPrintArg[] = _T(" /p \"%1\"");
static const TCHAR szPrintToArg[] = _T(" /pt \"%1\" \"%2\" \"%3\" \"%4\"");
static const TCHAR szDDEArg[] = _T(" /dde");
static const TCHAR szDDEExec[] = _T("ddeexec");
static const TCHAR szDDEOpen[] = _T("[open(\"%1\")]");
static const TCHAR szDDEPrint[] = _T("[print(\"%1\")]");
static const TCHAR szDDEPrintTo[] = _T("[printto(\"%1\",\"%2\",\"%3\",\"%4\")]");
static const TCHAR szShellNewValueName[] = _T("NullFile");
static const TCHAR szShellNewValue[] = _T("");
static const TCHAR* ppStrings[e_szMax] =
{
szShellOpenFmt,
szShellPrintFmt,
szShellPrintToFmt,
szDefaultIconFmt,
szShellNewFmt,
szIconIndexFmt,
szCommand,
szOpenArg,
szPrintArg,
szPrintToArg,
szDDEArg,
szDDEExec,
szDDEOpen,
szDDEPrint,
szDDEPrintTo,
szShellNewValueName,
szShellNewValue
};
return (ppStrings[index]);
}
// JME
CDocManagerEx::CDocManagerEx(LPCTSTR pszFilter)
{
if (pszFilter)
{
m_filter = pszFilter;
}
// get a default extension
CString strFilterExt;
if (AfxExtractSubString(strFilterExt,m_filter,0,(TCHAR)';'))
{
// this extracts *.xml
// from "XML Files (*.xml)|*.xml;|"
if (AfxExtractSubString(m_extension,strFilterExt,1,(TCHAR)'|'))
{
ASSERT(m_extension[0] == '*');
ASSERT(m_extension[1] == '.');
// delete the wildcard
m_extension.Delete(0,2);
}
}
}
CDocManagerEx::~CDocManagerEx()
{
}
// Document functions
void CDocManagerEx::RegisterShellFileTypes(BOOL bCompat)
{
const unsigned int DEFAULT_ICON_INDEX = 0;
ASSERT(!m_templateList.IsEmpty()); // must have some doc templates
CString strPathName, strTemp;
AfxGetModuleShortFileName(AfxGetInstanceHandle(), strPathName);
POSITION pos = m_templateList.GetHeadPosition();
for (int nTemplateIndex = 1; pos != NULL; nTemplateIndex++)
{
CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
CString strOpenCommandLine = strPathName;
CString strPrintCommandLine = strPathName;
CString strPrintToCommandLine = strPathName;
CString strDefaultIconCommandLine = strPathName;
if (bCompat)
{
CString strIconIndex;
HICON hIcon = ::ExtractIcon(AfxGetInstanceHandle(), strPathName, nTemplateIndex);
if (hIcon != NULL)
{
strIconIndex.Format(GetString(e_szIconIndexFmt), nTemplateIndex);
DestroyIcon(hIcon);
}
else
{
strIconIndex.Format(GetString(e_szIconIndexFmt), DEFAULT_ICON_INDEX);
}
strDefaultIconCommandLine += strIconIndex;
}
CString strMultiFilterExt, strFileTypeId, strFileTypeName;
if (pTemplate->GetDocString(strFileTypeId,
CDocTemplate::regFileTypeId) && !strFileTypeId.IsEmpty())
{
// if enough info to register it
if (!pTemplate->GetDocString(strFileTypeName,
CDocTemplate::regFileTypeName))
strFileTypeName = strFileTypeId; // use id name
ASSERT(strFileTypeId.Find(' ') == -1); // no spaces allowed
// first register the type ID of our server
if (!SetRegKey(strFileTypeId, strFileTypeName))
continue; // just skip it
if (bCompat)
{
// path\DefaultIcon = path,1
strTemp.Format(GetString(e_szDefaultIconFmt), (LPCTSTR)strFileTypeId);
if (!SetRegKey(strTemp, strDefaultIconCommandLine))
continue; // just skip it
}
// If MDI Application
if (!pTemplate->GetDocString(strTemp, CDocTemplate::windowTitle) ||
strTemp.IsEmpty())
{
// path\shell\open\ddeexec = [open("%1")]
strTemp.Format(GetString(e_szShellOpenFmt), (LPCTSTR)strFileTypeId,
GetString(e_szDDEExec));
if (!SetRegKey(strTemp, GetString(e_szDDEOpen)))
continue; // just skip it
if (bCompat)
{
// path\shell\print\ddeexec = [print("%1")]
strTemp.Format(GetString(e_szShellPrintFmt), (LPCTSTR)strFileTypeId,
GetString(e_szDDEExec));
if (!SetRegKey(strTemp, GetString(e_szShellPrintFmt)))
continue; // just skip it
// path\shell\printto\ddeexec = [printto("%1","%2","%3","%4")]
strTemp.Format(GetString(e_szShellPrintFmt), (LPCTSTR)strFileTypeId,
GetString(e_szDDEExec));
if (!SetRegKey(strTemp, GetString(e_szDDEPrintTo)))
continue; // just skip it
// path\shell\open\command = path /dde
// path\shell\print\command = path /dde
// path\shell\printto\command = path /dde
strOpenCommandLine += GetString(e_szDDEArg);
strPrintCommandLine += GetString(e_szDDEArg);
strPrintToCommandLine += GetString(e_szDDEArg);
}
else
{
strOpenCommandLine += GetString(e_szOpenArg);
}
}
else
{
// path\shell\open\command = path filename
// path\shell\print\command = path /p filename
// path\shell\printto\command = path /pt filename printer driver port
strOpenCommandLine += GetString(e_szOpenArg);
if (bCompat)
{
strPrintCommandLine += GetString(e_szPrintArg);
strPrintToCommandLine += GetString(e_szPrintToArg);
}
}
// path\shell\open\command = path filename
strTemp.Format(GetString(e_szShellOpenFmt), (LPCTSTR)strFileTypeId,
GetString(e_szCommand));
if (!SetRegKey(strTemp, strOpenCommandLine))
continue; // just skip it
if (bCompat)
{
// path\shell\print\command = path /p filename
strTemp.Format(GetString(e_szShellPrintFmt), (LPCTSTR)strFileTypeId,
GetString(e_szCommand));
if (!SetRegKey(strTemp, strPrintCommandLine))
continue; // just skip it
// path\shell\printto\command = path /pt filename printer driver port
strTemp.Format(GetString(e_szShellPrintFmt), (LPCTSTR)strFileTypeId,
GetString(e_szCommand));
if (!SetRegKey(strTemp, strPrintToCommandLine))
continue; // just skip it
}
pTemplate->GetDocString(strMultiFilterExt, CDocTemplate::filterExt);
// MultiExt: strMultiFilterExt is formatted as: ".ext1;.ext2;.ext3".
if (!strMultiFilterExt.IsEmpty())
{
CString strFilterExt;
// for all extensions in the filter
for (int i=0; AfxExtractSubString(strFilterExt, strMultiFilterExt, i, ';'); i++)
{
ASSERT(strFilterExt[0] == '.');
LONG lSize = _MAX_PATH * 2;
LONG lResult = ::RegQueryValue(HKEY_CLASSES_ROOT, strFilterExt,
strTemp.GetBuffer(lSize), &lSize);
strTemp.ReleaseBuffer();
if (lResult != ERROR_SUCCESS || strTemp.IsEmpty() ||
strTemp == strFileTypeId)
{
// no association for that suffix
if (!SetRegKey(strFilterExt, strFileTypeId))
continue;
if (bCompat)
{
strTemp.Format(GetString(e_szShellNewFmt), strFilterExt);
(void)SetRegKey(strTemp, GetString(e_szShellNewValue), GetString(e_szShellNewValueName));
}
}
} // for all extensions in the filter
} // if (!strMultiFilterExt.IsEmpty())
} // if enough info to register
} // for all templates in the template list
}
void CDocManagerEx::UnregisterShellFileTypes()
{
ASSERT(!m_templateList.IsEmpty()); // must have some doc templates
CString strPathName, strTemp;
AfxGetModuleShortFileName(AfxGetInstanceHandle(), strPathName);
POSITION pos = m_templateList.GetHeadPosition();
for (int nTemplateIndex = 1; pos != NULL; nTemplateIndex++)
{
CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
CString strMultiFilterExt, strFileTypeId, strFileTypeName;
if (pTemplate->GetDocString(strFileTypeId,
CDocTemplate::regFileTypeId) && !strFileTypeId.IsEmpty())
{
// if enough info to register it
if (!pTemplate->GetDocString(strFileTypeName,
CDocTemplate::regFileTypeName))
strFileTypeName = strFileTypeId; // use id name
ASSERT(strFileTypeId.Find(' ') == -1); // no spaces allowed
strTemp.Format(GetString(e_szDefaultIconFmt), (LPCTSTR)strFileTypeId);
DeleteRegKey(strTemp);
// If MDI Application
if (!pTemplate->GetDocString(strTemp, CDocTemplate::windowTitle) ||
strTemp.IsEmpty())
{
// path\shell\open\ddeexec = [open("%1")]
strTemp.Format(GetString(e_szShellOpenFmt), (LPCTSTR)strFileTypeId,
GetString(e_szDDEExec));
DeleteRegKey(strTemp);
// path\shell\print\ddeexec = [print("%1")]
strTemp.Format(GetString(e_szShellPrintFmt), (LPCTSTR)strFileTypeId,
GetString(e_szDDEExec));
DeleteRegKey(strTemp);
// path\shell\printto\ddeexec = [printto("%1","%2","%3","%4")]
strTemp.Format(GetString(e_szShellPrintFmt), (LPCTSTR)strFileTypeId,
GetString(e_szDDEExec));
DeleteRegKey(strTemp);
}
// path\shell\open\command = path filename
strTemp.Format(GetString(e_szShellOpenFmt), (LPCTSTR)strFileTypeId,
GetString(e_szCommand));
DeleteRegKey(strTemp);
// path\shell\print\command = path /p filename
strTemp.Format(GetString(e_szShellPrintFmt), (LPCTSTR)strFileTypeId,
GetString(e_szCommand));
DeleteRegKey(strTemp);
// path\shell\printto\command = path /pt filename printer driver port
strTemp.Format(GetString(e_szShellPrintFmt), (LPCTSTR)strFileTypeId,
GetString(e_szCommand));
DeleteRegKey(strTemp);
pTemplate->GetDocString(strMultiFilterExt, CDocTemplate::filterExt);
// MultiExt: strMultiFilterExt is formatted as: ".ext1;.ext2;.ext3".
if (!strMultiFilterExt.IsEmpty())
{
CString strFilterExt;
// for all extensions in the filter
for (int i=0; AfxExtractSubString(strFilterExt, strMultiFilterExt, i, ';'); i++)
{
ASSERT(strFilterExt[0] == '.');
LONG lSize = _MAX_PATH * 2;
LONG lResult = ::RegQueryValue(HKEY_CLASSES_ROOT, strFilterExt,
strTemp.GetBuffer(lSize), &lSize);
strTemp.ReleaseBuffer();
if (lResult != ERROR_SUCCESS || strTemp.IsEmpty() ||
strTemp == strFileTypeId)
{
strTemp.Format(GetString(e_szShellNewFmt), (LPCTSTR)strFilterExt);
DeleteRegKey(strTemp);
// no association for that suffix
DeleteRegKey(strFilterExt);
}
} // for all extensions in the filter
} // if (!strMultiFilterExt.IsEmpty())
} // if enough info to register
} // for all templates in the template list
}
// helper for standard commdlg dialogs
BOOL CDocManagerEx::DoPromptFileName( CString& fileName,
UINT /*nIDSTitle*/,
DWORD /*lFlags*/,
BOOL bOpenFileDialog,
CDocTemplate* /*pTemplate*/)
{
if (bOpenFileDialog)
{
CFileDialog dlg(TRUE,NULL,NULL,OFN_FILEMUSTEXIST|OFN_ENABLESIZING|OFN_EXPLORER,m_filter);
BOOL bResult = (dlg.DoModal() == IDOK ? TRUE : FALSE);
fileName = dlg.GetPathName();
return bResult;
}
else
{
CFileDialog dlg(FALSE,m_extension,NULL,OFN_OVERWRITEPROMPT|OFN_ENABLESIZING|OFN_EXPLORER,m_filter);
BOOL bResult = (dlg.DoModal() == IDOK ? TRUE : FALSE);
fileName = dlg.GetPathName();
// test for extension
int pos = fileName.ReverseFind('.');
if (pos < 0)
{
}
return bResult;
}
}
CDocument* CDocManagerEx::OpenDocumentFile(LPCTSTR lpszFileName)
{
// find the highest confidence
POSITION pos = m_templateList.GetHeadPosition();
CDocTemplate::Confidence bestMatch = CDocTemplate::noAttempt;
CDocTemplate* pBestTemplate = NULL;
CDocument* pOpenDocument = NULL;
TCHAR szPath[_MAX_PATH];
ASSERT(lstrlen(lpszFileName) < DM_ARRAY_SIZE(szPath));
TCHAR szTemp[_MAX_PATH];
if (lpszFileName[0] == '\"')
++lpszFileName;
lstrcpyn(szTemp, lpszFileName, _MAX_PATH);
LPTSTR lpszLast = _tcsrchr(szTemp, '\"');
if (lpszLast != NULL)
*lpszLast = 0;
AfxFullPath(szPath, szTemp);
TCHAR szLinkName[_MAX_PATH];
if (AfxResolveShortcut(AfxGetMainWnd(), szPath, szLinkName, _MAX_PATH))
lstrcpy(szPath, szLinkName);
while (pos != NULL)
{
CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
ASSERT_KINDOF(CDocTemplate, pTemplate);
CDocTemplate::Confidence match;
ASSERT(pOpenDocument == NULL);
// MultiExt: call our own MatchDocType() function
match = MatchDocType(pTemplate, szPath, pOpenDocument);
if (match > bestMatch)
{
bestMatch = match;
pBestTemplate = pTemplate;
}
if (match == CDocTemplate::yesAlreadyOpen)
break; // stop here
}
if (pOpenDocument != NULL)
{
POSITION pos = pOpenDocument->GetFirstViewPosition();
if (pos != NULL)
{
CView* pView = pOpenDocument->GetNextView(pos); // get first one
ASSERT_VALID(pView);
CFrameWnd* pFrame = pView->GetParentFrame();
if (pFrame != NULL)
pFrame->ActivateFrame();
else
TRACE0("Error: Can not find a frame for document to activate.\n");
CFrameWnd* pAppFrame;
if (pFrame != (pAppFrame = (CFrameWnd*)AfxGetApp()->m_pMainWnd))
{
ASSERT_KINDOF(CFrameWnd, pAppFrame);
pAppFrame->ActivateFrame();
}
}
else
{
TRACE0("Error: Can not find a view for document to activate.\n");
}
return pOpenDocument;
}
if (pBestTemplate == NULL)
{
AfxMessageBox(AFX_IDP_FAILED_TO_OPEN_DOC);
return NULL;
}
return pBestTemplate->OpenDocumentFile(szPath);
}
// MultiExt: our own MatchDocType() function
CDocTemplate::Confidence CDocManagerEx::MatchDocType(CDocTemplate *pTemplate, LPCTSTR lpszPathName,
CDocument*& rpDocMatch)
{
ASSERT(lpszPathName != NULL);
rpDocMatch = NULL;
// go through all documents
POSITION pos = pTemplate->GetFirstDocPosition();
while (pos != NULL)
{
CDocument* pDoc = pTemplate->GetNextDoc(pos);
if (AfxComparePath(pDoc->GetPathName(), lpszPathName))
{
// already open
rpDocMatch = pDoc;
return CDocTemplate::yesAlreadyOpen;
}
}
// MultiExt: deal w/ multiple extensions in the template filter
// see if it matches our default suffix
CString strMultiFilterExt;
if (pTemplate->GetDocString(strMultiFilterExt, CDocTemplate::filterExt) &&
!strMultiFilterExt.IsEmpty())
{
CString strFilterExt;
for (int i = 0; AfxExtractSubString(strFilterExt, strMultiFilterExt, i, (TCHAR)';'); i++)
{
// see if extension matches
ASSERT(strFilterExt[0] == '.');
LPCTSTR lpszDot = _tcsrchr(lpszPathName, '.');
if (lpszDot != NULL && lstrcmpi(lpszDot, strFilterExt) == 0)
return CDocTemplate::yesAttemptNative; // extension matches, looks like ours
}
}
// otherwise we will guess it may work
return CDocTemplate::yesAttemptForeign;
}
//IMPLEMENT_DYNAMIC(CDocManagerEx, CDocManager)