MFC默认的文档/视图的操作方式,是操作文件的。当我的文档是数据库等非文本文件时,麻烦了问题出现了。需要重写CwinApp::OnFileOpen()等函数。
谁有现成的代码,提供一下,多谢了!

解决方案 »

  1.   

    在 ClassWizard 里面,MessageMap选项,选 APP类,选ID_FILE_OPEN,增加消息响应.就行了.
    这样,再次按打开时,就不会执行默认的打开对话框,而是你自己的函数了.
      

  2.   

    哦,情况我没说清楚,是这样:
    wizard生产的代码:
    ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)CWinApp::OnFileOpen 代码:
    void CWinApp::OnFileOpen()
    {
    ENSURE(m_pDocManager != NULL);
    m_pDocManager->OnFileOpen();
    }m_pDocManager->OnFileOpen(); 代码:void CDocManager::OnFileOpen()
    {
    // prompt the user (with all document templates)
    CString newName;
    if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,
      OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL))
    return; // open cancelled AfxGetApp()->OpenDocumentFile(newName);
    // if returns NULL, the user has already been alerted
    }AfxGetApp()->OpenDocumentFile(newName); 代码:CDocument* CWinApp::OpenDocumentFile(LPCTSTR lpszFileName)
    {
    ENSURE_VALID(m_pDocManager);
    return m_pDocManager->OpenDocumentFile(lpszFileName);
    }return m_pDocManager->OpenDocumentFile(lpszFileName); 代码:CDocument* CDocManager::OpenDocumentFile(LPCTSTR lpszFileName)
    {
    if (lpszFileName == NULL)
    {
    AfxThrowInvalidArgException();
    }
    // 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) < _countof(szPath));
    TCHAR szTemp[_MAX_PATH];
    if (lpszFileName[0] == '\"')
    ++lpszFileName;
    Checked::tcsncpy_s(szTemp, _countof(szTemp), lpszFileName, _TRUNCATE);
    LPTSTR lpszLast = _tcsrchr(szTemp, '\"');
    if (lpszLast != NULL)
    *lpszLast = 0;

    if( AfxFullPath(szPath, szTemp) == FALSE )
    {
    ASSERT(FALSE);
    return NULL; // We won't open the file. MFC requires paths with
                 // length < _MAX_PATH
    } TCHAR szLinkName[_MAX_PATH];
    if (AfxResolveShortcut(AfxGetMainWnd(), szPath, szLinkName, _MAX_PATH))
    Checked::tcscpy_s(szPath, _countof(szPath), szLinkName); while (pos != NULL)
    {
    CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
    ASSERT_KINDOF(CDocTemplate, pTemplate); CDocTemplate::Confidence match;
    ASSERT(pOpenDocument == NULL);
    match = pTemplate->MatchDocType(szPath, pOpenDocument);
    if (match > bestMatch)
    {
    bestMatch = match;
    pBestTemplate = pTemplate;
    }
    if (match == CDocTemplate::yesAlreadyOpen)
    break;      // stop here
    } if (pOpenDocument != NULL)
    {
    POSITION posOpenDoc = pOpenDocument->GetFirstViewPosition();
    if (posOpenDoc != NULL)
    {
    CView* pView = pOpenDocument->GetNextView(posOpenDoc); // get first one
    ASSERT_VALID(pView);
    CFrameWnd* pFrame = pView->GetParentFrame(); if (pFrame == NULL)
    TRACE(traceAppMsg, 0, "Error: Can not find a frame for document to activate.\n");
    else
    {
    pFrame->ActivateFrame(); if (pFrame->GetParent() != NULL)
    {
    CFrameWnd* pAppFrame;
    if (pFrame != (pAppFrame = (CFrameWnd*)AfxGetApp()->m_pMainWnd))
    {
    ASSERT_KINDOF(CFrameWnd, pAppFrame);
    pAppFrame->ActivateFrame();
    }
    }
    }
    }
    else
    TRACE(traceAppMsg, 0, "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);
    }pBestTemplate->OpenDocumentFile(szPath); 代码这里就先不列出里....
    在这一系列的调用中,完成了基于对文件文档的对打开的管理,比如:同一个文件文档不会打开2次。而我现在的代码,仅仅:   
    ON_COMMAND(ID_FILE_OPEN, &CMyApp::OnFileOpen)void CMyApp::OnFileOpen()
    {
        // TODO: 在此添加命令处理程序代码
    }谁有现成的这个函数的实现,不是基于文件的,是基于数据库的应用的,就是说一个文档就是一个数据库的记录。给我一份,我好省省力。提前谢了。
      

  3.   

    楼主,研究过了一下你的代码.
    跟我之前看过的书里写的是一样的,是孙鑫的VC++深入详解,第13章文档与串行化.
    你贴出来的代码,也是跟 DOCMGR.CPP 里的源代码一样的.他主要是在 match = pTemplate->MatchDocType(szPath, pOpenDocument);这一句这里
    如果这个是已经打开了的文档,第二个参数会返回文档的指针,否则第二个参数返回空值.下面再用 if (pOpenDocument != NULL) 来看是否要做打开操作.我试了一下,把 DOCMGR.CPP 的内容,放到自己的 void CSDIDEMOApp::OnFileOpen() 里运行是可以的.
    楼主,你提供一下你的数据库读写的代码.我们帮你放到OnFileOpen里面试试吧.
      

  4.   

    在 ClassWizard 里面,MessageMap选项,选 APP类,选ID_FILE_OPEN,增加消息响应.就行了.
    这样,再次按打开时,就不会执行默认的打开对话框,而是你自己的函数了.
      

  5.   

    呵呵,最后还是自己写代码解决了。
    我其实是想避开CDocManager类中的OnFileOpen的实现,MFC的实现中使用打开文件的对话框,并且把文件名前加上了绝对路径。其实这对于非文件的应用都是必须去掉的。真不知道,MFC的开发小组是怎么想的,怎么就不肯加上一个对处理非文件的DocManager类呢,唉,毕竟,现实中大部分应用都是都是基于非文件数据的,谁又能开发几个excel或word呢?
    好了,不抱怨了,下面把我新写的CMyDocManager文件源码贴出来,共享一下,我仅重写了我需要的2个函数,谁要用可以接着重新其他的,并请同行指正!文件:MyDocManager.h#pragma once
    // CMyDocManagerclass CMyDocManager : public CDocManager
    {
    DECLARE_DYNAMIC(CMyDocManager)public:
    CMyDocManager();
    virtual ~CMyDocManager();    virtual void OnFileOpen();
        virtual CDocument* OpenDocumentFile(LPCTSTR lpszFileName); // open named file};文件:MyDocManager.cpp// MyDocManager.cpp : 实现文件
    //#include "stdafx.h"
    #include "MyDocManager.h"
    #include <afxwin.h>
    // CMyDocManagerIMPLEMENT_DYNAMIC(CMyDocManager, CDocManager)CMyDocManager::CMyDocManager()
    {
        CDocManager();
    }CMyDocManager::~CMyDocManager()
    {
    }void CMyDocManager::OnFileOpen()
    {
        // prompt the user (with all document templates)
        CString newName;
        //if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,
        //    OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL))
        //    return; // open cancelled
        //在这里把打开文件对话框的代码去掉了,需要填上自己的取得文件名的代码
      
        AfxGetApp()->OpenDocumentFile(newName);
        // if returns NULL, the user has already been alerted
    }CDocument* CMyDocManager::OpenDocumentFile( LPCTSTR lpszFileName )
    {    if (lpszFileName == NULL)
        {
            AfxThrowInvalidArgException();
        }
        // 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) < _countof(szPath));
        TCHAR szTemp[_MAX_PATH];
        if (lpszFileName[0] == '\"')
            ++lpszFileName;
        Checked::tcsncpy_s(szTemp, _countof(szTemp), lpszFileName, _TRUNCATE);
        LPTSTR lpszLast = _tcsrchr(szTemp, '\"');
        if (lpszLast != NULL)
            *lpszLast = 0;    
        //我增加的代码
        Checked::tcsncpy_s(szPath, _countof(szPath), szTemp, _TRUNCATE);    // 加入文件路径的,无用
        //if( AfxFullPath(szPath, szTemp) == FALSE )
        //{
        //    ASSERT(FALSE);
        //    return NULL; // We won't open the file. MFC requires paths with
        //    // length < _MAX_PATH
        //}    // 文件快捷方式的处理,也无用
        //TCHAR szLinkName[_MAX_PATH];
        //if (AfxResolveShortcut(AfxGetMainWnd(), szPath, szLinkName, _MAX_PATH))
        //    Checked::tcscpy_s(szPath, _countof(szPath), szLinkName);    while (pos != NULL)
        {
            CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
            ASSERT_KINDOF(CDocTemplate, pTemplate);        CDocTemplate::Confidence match;
            ASSERT(pOpenDocument == NULL);
            match = pTemplate->MatchDocType(szPath, pOpenDocument);
            if (match > bestMatch)
            {
                bestMatch = match;
                pBestTemplate = pTemplate;
            }
            if (match == CDocTemplate::yesAlreadyOpen)
                break; // stop here
        }    if (pOpenDocument != NULL)
        {
            POSITION posOpenDoc = pOpenDocument->GetFirstViewPosition();
            if (posOpenDoc != NULL)
            {
                CView* pView = pOpenDocument->GetNextView(posOpenDoc); // get first one
                ASSERT_VALID(pView);
                CFrameWnd* pFrame = pView->GetParentFrame();            if (pFrame == NULL)
                    TRACE(traceAppMsg, 0, "Error: Can not find a frame for document to activate.\n");
                else
                {
                    pFrame->ActivateFrame();                if (pFrame->GetParent() != NULL)
                    {
                        CFrameWnd* pAppFrame;
                        if (pFrame != (pAppFrame = (CFrameWnd*)AfxGetApp()->m_pMainWnd))
                        {
                            ASSERT_KINDOF(CFrameWnd, pAppFrame);
                            pAppFrame->ActivateFrame();
                        }
                    }
                }
            }
            else
                TRACE(traceAppMsg, 0, "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);
    }使用时候要注意:
    1 替换CWinApp 的包含的CDocManager类对象
    在 CMyApp::InitInstance()函数中,添加代码    //用把CDocManager类的对象替换为自己的CMyDocManager类的对象
        if (m_pDocManager) delete m_pDocManager;
        m_pDocManager = new CMyDocManager();注意,这代码一定要填写在下面代码的前面: CMultiDocTemplate* pDocTemplate;
    pDocTemplate = new CMultiDocTemplate(IDR_ValuerUITYPE,
    RUNTIME_CLASS(CCompanyDoc),
    RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
    RUNTIME_CLASS(CCompanyView));2 重写CMyDocument中的OnOpenDocument函数。
       因为MFC开发人员在CDocument在的默认OnOpenDocument实现是打开一个文件,现在需要把它改写成你自己需要的了。3 重写CMyDocument中的SetPathName等函数。
    只用改写了SetPathName函数才能让MFC框架正确判断一个文档是否打开了。因为在
    在CMyDocManger类中的:
    match = pTemplate->MatchDocType(szPath, pOpenDocument);
    就是依靠CDocument中的m_strPathName做的判断。
    最好在在SetPathName函数中重新调用一次SetTitle,把文档标题设置成自己需要的。下面是我的SetPathName的实现:void CCompanyDoc::SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU)
    {
        //CDocument::SetPathName(lpszPathName, bAddToMRU);
        m_strPathName = lpszPathName;
        SetTitle(lpszPathName); //临时用用,正式使用时候在修改
    }
    好了,就这么多。经过如此增补,MFC的文档/视图模式(其实就是MVC模式),可以支持任何抽象类型的文件了,呵呵。