Click here to Skip to main content
15,886,689 members
Articles / Programming Languages / C++

ESS: Extremely Simple Serialization for C++

Rate me:
Please Sign up or sign in to vote.
4.94/5 (14 votes)
26 Nov 2012BSD15 min read 86.9K   1.7K   68  
An article on persistent C++ objects. Includes several console mode test apps and an MFC GUI demo.
/*

	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)

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
Architect
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions