Click here to Skip to main content
15,886,919 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Hi everybody, I want to create a MDI frame with doc/view in dll, when it is load by exe app, it show the mdi frame defined in dll with its' document and sub frame.

I have write some code, but it have a running error in CMDIChildWnd::Create() function, and it stop at this line:
C++
ASSERT_KINDOF(CMDIFrameWnd, pMDIFrame);


everyone can tell the reason?
Posted

C++
mfc90ud.dll!CMDIChildWnd::Create(const wchar_t * lpszClassName=0x00154c48, const wchar_t * lpszWindowName=0x00ec3838, unsigned long dwStyle=1087340544, const tagRECT & rect={...}, CMDIFrameWnd * pParentWnd=0x00ec3550, CCreateContext * pContext=0x0012fa14)  行547   C++
ExampleDLL.dll!CDLLChildFrame::Create(const wchar_t * lpszClassName=0x00154c48, const wchar_t * lpszWindowName=0x00ec3838, unsigned long dwStyle=1087340544, const tagRECT & rect={...}, CMDIFrameWnd * pParentWnd=0x00ec3550, CCreateContext * pContext=0x0012fa14)  行85   C++
mfc90ud.dll!CMDIChildWnd::LoadFrame(unsigned int nIDResource=129, unsigned long dwDefaultStyle=1087340544, CWnd * pParentWnd=0x00ec3550, CCreateContext * pContext=0x0012fa14)  行617 + 0x3b 字节  C++
ExampleDLL.dll!CDLLChildFrame::LoadFrame(unsigned int nIDResource=129, unsigned long dwDefaultStyle=13598720, CWnd * pParentWnd=0x00ec3550, CCreateContext * pContext=0x0012fa14)  行98 + 0x18 字节    C++
mfc90ud.dll!CDocTemplate::CreateNewFrame(CDocument * pDoc=0x00ec6198, CFrameWnd * pOther=0x00000000)  行277 + 0x22 字节    C++
mfc90ud.dll!CMultiDocTemplate::OpenDocumentFile(const wchar_t * lpszPathName=0x00000000, int bMakeVisible=1)  行121 + 0x13 字节    C++
ExampleDLL.dll!CMyMultiDocTemplate::OpenDocumentFile(const wchar_t * lpszPathName=0x00000000, int bMakeVisible=1)  行51 + 0x10 字节    C++
mfc90ud.dll!CDocManager::OnFileNew()  行848  C++
mfc90ud.dll!CWinApp::OnFileNew()  行22   C++
mfc90ud.dll!_AfxDispatchCmdMsg(CCmdTarget * pTarget=0x00428600, unsigned int nID=57600, int nCode=0, void (void)* pfn=0x004114f1, void * pExtra=0x00000000, unsigned int nSig=57, AFX_CMDHANDLERINFO * pHandlerInfo=0x00000000)  行82    C++
mfc90ud.dll!CCmdTarget::OnCmdMsg(unsigned int nID=57600, int nCode=0, void * pExtra=0x00000000, AFX_CMDHANDLERINFO * pHandlerInfo=0x00000000)  行381 + 0x27 字节   C++
mfc90ud.dll!CWinApp::ProcessShellCommand(CCommandLineInfo & rCmdInfo={...})  行24 + 0x20 字节  C++
DocViewFromDLL.exe!CDocViewFromDLLApp::InitInstance()  行116 + 0xc 字节    C++
mfc90ud.dll!AfxWinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, wchar_t * lpCmdLine=0x00020dee, int nCmdShow=1)  行37 + 0xd 字节    C++
DocViewFromDLL.exe!wWinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, wchar_t * lpCmdLine=0x00020dee, int nCmdShow=1)  行30    C++
DocViewFromDLL.exe!__tmainCRTStartup()  行574 + 0x35 字节  C
DocViewFromDLL.exe!wWinMainCRTStartup()  行399   C
kernel32.dll!7c817077()
 
Share this answer
 
v2
Now we could try to analyze the type of pMDIFrame... :)
 
Share this answer
 
This is the code export from dll:
C++
// global function exports so we can be loaded by DLL
extern "C" __declspec( dllexport ) CMyMultiDocTemplate* DLLDocTemplate()
{
    // create the CMyMultiDocTemplate object to pass to exe
    // we have to be using the local resources when we do this as
    // the CDocTemplate constructor calls LoadTemplate() before the
    // vtable for virtual functions is setup and calls the base
    // class implementation
    AFX_MANAGE_STATE(AfxGetStaticModuleState()) ;
    CMyMultiDocTemplate *pTemplate = NULL ;
    pTemplate = new CMyMultiDocTemplate(
        theApp.m_hInstance,         // the APP's resource instance
        IDR_DLLDOCUMENT,
        RUNTIME_CLASS(CDLLDocument),
        RUNTIME_CLASS(CDLLChildFrame), // custom MDI child frame
        RUNTIME_CLASS(CDLLDocumentView));
    return pTemplate ;
}
extern "C" __declspec( dllexport ) BOOL CreateDllFrame()
{
    if ( theApp.m_pMainWnd == NULL )
    {
        AFX_MANAGE_STATE(AfxGetStaticModuleState()) ;
        CDLLMainFrame* pMainFrame = new CDLLMainFrame;
        if (!pMainFrame->LoadFrame(IDR_DLLDOCUMENT))
            return FALSE;
        theApp.m_pMainWnd = pMainFrame;
        pMainFrame->ShowWindow( SW_SHOW );
        pMainFrame->UpdateWindow();
    }
    return TRUE;
}


dll have it's own DocTemplate and I have overwrite the two function:
C++
void CMyMultiDocTemplate::LoadTemplate()
{
	// call the base class member after switching the resource to the DLL, if this is a DLL document type
	HINSTANCE	hOld ;

	hOld = AfxGetResourceHandle() ;			// save
	AfxSetResourceHandle(m_hInst) ;			// set
	CMultiDocTemplate::LoadTemplate() ;		// now get from correct resources!
	AfxSetResourceHandle(hOld) ;			// restore
}

CDocument* CMyMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible)
{
	// switch to the correct resources and then resturn the document
	CDocument	*pDoc = NULL ;
	HINSTANCE	hOld ;

	hOld = AfxGetResourceHandle() ;			// save
	AfxSetResourceHandle(m_hInst) ;			// set
	//CreateDllFrame();
	pDoc = CMultiDocTemplate::OpenDocumentFile(lpszPathName, bMakeVisible) ;
	AfxSetResourceHandle(hOld) ;			// restore
	return pDoc ;
}

I AddDocTemplate() and CreateDllFrame() in exe app's InitInstance()
 
Share this answer
 
Please post the definition of CDLLMainFrame :)
 
Share this answer
 
//DLLMainFrm.h
class CDLLMainFrame : public CMDIFrameWnd
{
	DECLARE_DYNAMIC(CDLLMainFrame)
public:
	CDLLMainFrame();

// Attributes
public:

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CDLLMainFrame)
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
	//}}AFX_VIRTUAL

// Implementation
public:
	virtual ~CDLLMainFrame();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:  // control bar embedded members
	CStatusBar  m_wndStatusBar;
	CToolBar    m_wndToolBar;

// Generated message map functions
protected:
	//{{AFX_MSG(CDLLMainFrame)
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
		// NOTE - the ClassWizard will add and remove member functions here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};


//DLLMainFrm.cpp
/////////////////////////////////////////////////////////////////////////////
// CDLLMainFrame

IMPLEMENT_DYNAMIC(CDLLMainFrame, CMDIFrameWnd)

BEGIN_MESSAGE_MAP(CDLLMainFrame, CMDIFrameWnd)
	//{{AFX_MSG_MAP(CDLLMainFrame)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code !
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

static UINT indicators[] =
{
	ID_SEPARATOR,           // status line indicator
	ID_INDICATOR_CAPS,
	ID_INDICATOR_NUM,
	ID_INDICATOR_SCRL,
};

/////////////////////////////////////////////////////////////////////////////
// CDLLMainFrame construction/destruction

CDLLMainFrame::CDLLMainFrame()
{
	// TODO: add member initialization code here
	
}

CDLLMainFrame::~CDLLMainFrame()
{
}

int CDLLMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
		!m_wndToolBar.LoadToolBar(IDR_DLLFRAME))
	{
		TRACE0("Failed to create toolbar\n");
		return -1;      // fail to create
	}

	if (!m_wndStatusBar.Create(this) ||
		!m_wndStatusBar.SetIndicators(indicators,
		  sizeof(indicators)/sizeof(UINT)))
	{
		TRACE0("Failed to create status bar\n");
		return -1;      // fail to create
	}

	// TODO: Delete these three lines if you don't want the toolbar to
	//  be dockable
	m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
	EnableDocking(CBRS_ALIGN_ANY);
	DockControlBar(&m_wndToolBar);

	return 0;
}

BOOL CDLLMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	if( !CMDIFrameWnd::PreCreateWindow(cs) )
		return FALSE;
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return TRUE;
}
 
Share this answer
 
It seems to be OK :)

Now -
please obeserve the stack (post it) at the assertion stopping
and the type of pMDIFrame (just move your cursor there) :)
 
Share this answer
 
CDLLMainFrm is a class I copy from exe's CMainFrm.

When I created the main frame in exe, it work and the child frame defined in dll was showed correctly in this main frame, but when i created the main frame in dll, the problem came again.
 
Share this answer
 
please obeserve the stack (post it) at the assertion stopping
and the type of pMDIFrame (just move your cursor there)

I did, and I found the type of pMDIFrame was CWnd, and the value of hWnd and m_hWnd is different, I guess this may be the point.
 
Share this answer
 
OK, now we have the reason of the assertion :)

And the stack at the assertion,
could you post it, please ?
 
Share this answer
 
VB
mfc90ud.dll!CMDIChildWnd::GetMDIFrame()  行901   C++
mfc90ud.dll!CMDIChildWnd::OnSize(unsigned int nType=0, int cx=786, int cy=385)  行631 + 0x8 字节   C++
mfc90ud.dll!CWnd::OnWndMsg(unsigned int message=5, unsigned int wParam=0, long lParam=25232146, long * pResult=0x0012e5e4)  行2066   C++
mfc90ud.dll!CWnd::WindowProc(unsigned int message=5, unsigned int wParam=0, long lParam=25232146)  行1755 + 0x20 字节  C++
mfc90ud.dll!AfxCallWndProc(CWnd * pWnd=0x00ec62e0, HWND__ * hWnd=0x001408f6, unsigned int nMsg=5, unsigned int wParam=0, long lParam=25232146)  行240 + 0x1c 字节  C++
mfc90ud.dll!AfxWndProc(HWND__ * hWnd=0x001408f6, unsigned int nMsg=5, unsigned int wParam=0, long lParam=25232146)  行403    C++
mfc90ud.dll!AfxWndProcBase(HWND__ * hWnd=0x001408f6, unsigned int nMsg=5, unsigned int wParam=0, long lParam=25232146)  行441 + 0x15 字节  C++
user32.dll!7e418734()
user32.dll!7e418816()
user32.dll!7e42bf15()
user32.dll!7e430b05()
user32.dll!7e430a5f()
mfc90ud.dll!CMDIChildWnd::DefWindowProcW(unsigned int nMsg=71, unsigned int wParam=0, long lParam=1239836)  行429    C++
mfc90ud.dll!CWnd::WindowProc(unsigned int message=71, unsigned int wParam=0, long lParam=1239836)  行1756 + 0x1c 字节  C++
mfc90ud.dll!AfxCallWndProc(CWnd * pWnd=0x00ec62e0, HWND__ * hWnd=0x001408f6, unsigned int nMsg=71, unsigned int wParam=0, long lParam=1239836)  行240 + 0x1c 字节  C++
mfc90ud.dll!AfxWndProc(HWND__ * hWnd=0x001408f6, unsigned int nMsg=71, unsigned int wParam=0, long lParam=1239836)  行403    C++
mfc90ud.dll!AfxWndProcBase(HWND__ * hWnd=0x001408f6, unsigned int nMsg=71, unsigned int wParam=0, long lParam=1239836)  行441 + 0x15 字节  C++
user32.dll!7e418734()
user32.dll!7e42bdf1()
user32.dll!7e42bf90()
user32.dll!7e42be3b()
ntdll.dll!7c90e473()
user32.dll!7e4299ff()
mfc90ud.dll!_AfxModifyStyle(HWND__ * hWnd=0x92840f00, int nStyleOffset=-1191182606, unsigned long dwRemove=32768, unsigned long dwAdd=4277307625, unsigned int nFlags=2425393407)  行104 C++
008005f9()
 
Share this answer
 
v2
- pMDIFrame 0x003adff0 {CWnd hWnd=0x0009085a} CMDIFrameWnd *
+ [CWnd] {CWnd hWnd=0x0009085a} CWnd
+ CFrameWnd {CFrameWnd hWnd=0x0009085a} CFrameWnd
- classCMDIFrameWnd {"CMDIFrameWnd"} const CRuntimeClass
+ m_lpszClassName 0x789e6054 "CMDIFrameWnd" const char *
m_nObjectSize 236 int
m_wSchema 65535 unsigned int
m_pfnCreateObject 0x78a58890 CMDIFrameWnd::CreateObject(void) CObject * (void)*
m_pfnGetBaseClass 0x78a589d0 CMDIChildWnd::_GetBaseClass(void) CRuntimeClass * (void)*
+ m_pNextClass 0x00000000 {???} CRuntimeClass *
+ m_pClassInit 0x00000000 const AFX_CLASSINIT *
+ m_hWndMDIClient 0xcdcdcdcd {unused=??? } HWND__ *
+ this 0x00ec62e0 {CDLLChildFrame hWnd=0x00080874} CMDIChildWnd * const
 
Share this answer
 
Please set a breakpoint in the same file of the assertion at:
BOOL CMDIChildWnd::Create(LPCTSTR lpszClassName,
	LPCTSTR lpszWindowName, DWORD dwStyle,
	const RECT& rect, CMDIFrameWnd* pParentWnd,
	CCreateContext* pContext)
{ // set breakpoint here...

...then start the debugger and take a stop for your DLL child creation:
is the pParentWnd of the valid type there ? :)
 
Share this answer
 
The "bug" has been found :-D :

please overwrite the:
CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
	                                      BOOL bMakeVisible)

to pass your parent pointer (and not NULL) to CreateNewFrame(.., !!!) inside :)
 
Share this answer
 
Thank you! :)

I overwrited CDLLChildFrame::Create() like that:

C++
CDLLChildFrame::Create(LPCTSTR lpszClassName,	LPCTSTR lpszWindowName, DWORD dwStyle,	const RECT& rect, CMDIFrameWnd* pParentWnd,	CCreateContext* pContext)
{
    if(pParentWnd==NULL)
    {
        pParentWnd =  (CMDIFrameWnd*)theApp.m_pMainWnd;
    }
    CMDIChildWnd::Create(lpszClassName,	lpszWindowName, dwStyle,rect, pParentWnd,pContext);
}


and it pop the message:"failed to create empty document"

and when I put this code in the CDLLChildFrame::LoadFrame() when overwrited it, it got the problem I said in my question.
 
Share this answer
 
I found the solution.

The reason may be I call too much

C++
AFX_MANAGE_STATE(AfxGetStaticModuleState()) ;
\


I replace AFX_MANAGE_STATE(AfxGetStaticModuleState()) ; by these code:

C++
HINSTANCE   hOld ;
hOld = AfxGetResourceHandle() ;         // save
AfxSetResourceHandle(m_hInst) ;         // set
//Here I create the frame
AfxSetResourceHandle(hOld) ;            // restore


and the bug had disappeared, but I don't know why, so welcome any explanations for it
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900