// 我在建立新文檔時一般經過pDocTemplate->OpenDocumentFile(NULL)的方式建立; // 下面貼出調用代碼 // AFX_IDP_FAILED_TO_CREATE_DOC就是「建立空文檔失敗」 // 當前遇到的狀況是在CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL); // 建立框架窗口時失敗,進行跟就去 CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible) { return OpenDocumentFile(lpszPathName, TRUE, bMakeVisible); } CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bAddToMRU, BOOL bMakeVisible) { CDocument* pDocument = CreateNewDocument(); if (pDocument == NULL) { TRACE(traceAppMsg, 0, "CDocTemplate::CreateNewDocument returned NULL.\n"); AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); return NULL; } ASSERT_VALID(pDocument); BOOL bAutoDelete = pDocument->m_bAutoDelete; pDocument->m_bAutoDelete = FALSE; // don't destroy if something goes wrong CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL); pDocument->m_bAutoDelete = bAutoDelete; if (pFrame == NULL) { AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); delete pDocument; // explicit delete on error return NULL; } ASSERT_VALID(pFrame); if (lpszPathName == NULL) { // create a new document - with default document name SetDefaultTitle(pDocument); // avoid creating temporary compound file when starting up invisible if (!bMakeVisible) pDocument->m_bEmbedded = TRUE; if (!pDocument->OnNewDocument()) { // user has be alerted to what failed in OnNewDocument TRACE(traceAppMsg, 0, "CDocument::OnNewDocument returned FALSE.\n"); pFrame->DestroyWindow(); return NULL; } // it worked, now bump untitled count m_nUntitledCount++; } else { // open an existing document CWaitCursor wait; if (!pDocument->OnOpenDocument(lpszPathName)) { // user has be alerted to what failed in OnOpenDocument TRACE(traceAppMsg, 0, "CDocument::OnOpenDocument returned FALSE.\n"); pFrame->DestroyWindow(); return NULL; } pDocument->SetPathName(lpszPathName, bAddToMRU); pDocument->OnDocumentEvent(CDocument::onAfterOpenDocument); } InitialUpdateFrame(pFrame, pDocument, bMakeVisible); return pDocument; } // 更進去以後發現,CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject(); // 進行建立框架窗口,繼續跟進去 CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther) { if (pDoc != NULL) ASSERT_VALID(pDoc); // create a frame wired to the specified document ASSERT(m_nIDResource != 0); // must have a resource ID to load from CCreateContext context; context.m_pCurrentFrame = pOther; context.m_pCurrentDoc = pDoc; context.m_pNewViewClass = m_pViewClass; context.m_pNewDocTemplate = this; if (m_pFrameClass == NULL) { TRACE(traceAppMsg, 0, "Error: you must override CDocTemplate::CreateNewFrame.\n"); ASSERT(FALSE); return NULL; } CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject(); if (pFrame == NULL) { TRACE(traceAppMsg, 0, "Warning: Dynamic create of frame %hs failed.\n", m_pFrameClass->m_lpszClassName); return NULL; } ASSERT_KINDOF(CFrameWnd, pFrame); if (context.m_pNewViewClass == NULL) TRACE(traceAppMsg, 0, "Warning: creating frame with no default view.\n"); // create new from resource if (!pFrame->LoadFrame(m_nIDResource, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, // default frame styles NULL, &context)) { TRACE(traceAppMsg, 0, "Warning: CDocTemplate couldn't create a frame.\n"); // frame will be deleted in PostNcDestroy cleanup return NULL; } // it worked ! return pFrame; } // 跟到這裏發現了緣由m_pfnCreateObject的值爲空 // DECLARE_DYNCREATE發現了這個宏 // 猜想跟建立子框架窗口的類時添加的宏有關 // 發現我本身建立子框架添加的宏是DECLARE_DYNAMIC // 將修改成DECLARE_DYNCREATE便可成功 // 在.cpp文件中修改IMPLEMENT_DYNCREATE宏 // 出現這樣的緣由是經過嚮導建立默認添加的是DECLARE_DYNAMIC宏 CObject* CRuntimeClass::CreateObject() { ENSURE(this); if (m_pfnCreateObject == NULL) { TRACE(traceAppMsg, 0, _T("Error: Trying to create object which is not ") _T("DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n"), m_lpszClassName); return NULL; } CObject* pObject = NULL; TRY { pObject = (*m_pfnCreateObject)(); } END_TRY return pObject; } // 下面給出這些宏定義的區別 #define DECLARE_DYNAMIC(class_name) \ public: \ static const CRuntimeClass class##class_name; \ virtual CRuntimeClass* GetRuntimeClass() const; \ #define _DECLARE_DYNAMIC(class_name) \ public: \ static CRuntimeClass class##class_name; \ virtual CRuntimeClass* GetRuntimeClass() const; \ #endif // not serializable, but dynamically constructable #define DECLARE_DYNCREATE(class_name) \ DECLARE_DYNAMIC(class_name) \ static CObject* PASCAL CreateObject(); #define _DECLARE_DYNCREATE(class_name) \ _DECLARE_DYNAMIC(class_name) \ static CObject* PASCAL CreateObject(); // 這只是我找到的緣由之一,調試了好久都沒找到緣由。 // 由於我發現問題的項目調試時沒法進到OpenDocumentFile中。 // 因此另建立了一個測試項目進行調試,才能夠跟就去。