vc6之多文档程序执行流程

本文详细介绍了在VC6.0中使用MFCAppWizard创建多文档项目的操作步骤,并深入分析了初始化过程及执行流程,包括窗口对象的创建、初始化、消息处理等关键环节。
在vc6.0中
选择File/New
在projects标签页选择MFC Appwizard(exe)
在接下来的对话框中选择multiple document...
即可建立一多文档项目
每新建一个多文档的项目,wizard都会自动生成6个类,比如新建multid项目
自动生成的类是
CMultidApp---对应文件是multid.cpp和multid.h
CMainFrame---对应文件是MainFrm.cpp和MainFrm.h
CChildFrame---对应文件是ChildFrm.cpp和ChildFrm.h
CMultidDoc---对应文件是MultidDoc.cpp和MultidDoc.h
CMultidView---对应文件是MultidView.cpp和MultidView.h
CAboutDlg-----在multid.cpp中声明和实现。

其中
CMainFrame继承于CMDIFrameWnd-->CFrameWnd-->CWnd-->CCmdTarget
CChildFrame继承于CMDIChildWnd-->
CFrameWnd-->CWnd-->CCmdTarget

看一下执行流程--参照深入浅出mfc chapter6
首先有一个全局的对象theApp属于类CMultidApp,继承于CWinApp。全部变量在winmain函数执行之前就已经创建,类CWinApp有几个函数比较重要,在AFXWIN.H
class CWinApp : public CWinThread
{
    DECLARE_DYNAMIC(CWinApp)
public:	
    ...
    virtual BOOL InitApplication();
    virtual BOOL InitInstance();
    virtual int Run();
    ...
}
创建好theApp对象后,进入程序入口点_tWinMain,调用theApp的成员函数InitInstance,InitApplication,Run,其中虚函数InitInstance在multid.cpp中改写。可以看出程序的执行路径,和sdk中程序执行路径对应。
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,//入口点,appmodul.cppP
    LPTSTR lpCmdLine, int nCmdShow)
{
    // call shared/exported WinMain
    return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,//winmain.cpp
	LPTSTR lpCmdLine, int nCmdShow)
{
	ASSERT(hPrevInstance == NULL);

	int nReturnCode = -1;
	CWinThread* pThread = AfxGetThread();
	CWinApp* pApp = AfxGetApp();

	// AFX internal initialization
	if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
		goto InitFailure;

	// App global initializations (rare)
	if (pApp != NULL && !pApp->InitApplication())//调用theApp->InitApplication()
		goto InitFailure;

	// Perform specific initializations
	if (!pThread->InitInstance())//调用theApp->InitInstance()
	{
		if (pThread->m_pMainWnd != NULL)
		{
			TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
			pThread->m_pMainWnd->DestroyWindow();
		}
		nReturnCode = pThread->ExitInstance();
		goto InitFailure;
	}
	nReturnCode = pThread->Run();//调用theApp->Run()

InitFailure:
#ifdef _DEBUG
	// Check for missing AfxLockTempMap calls
	if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
	{
		TRACE1("Warning: Temp map lock count non-zero (%ld).\n",
			AfxGetModuleThreadState()->m_nTempMapLock);
	}
	AfxLockTempMaps();
	AfxUnlockTempMaps(-1);
#endif

	AfxWinTerm();
	return nReturnCode;
}

跟踪theApp->InitInstance()
在multid.cpp改写的InitInstance函数,创建并显示窗口,源码如下
BOOL CMultidApp::InitInstance()
{
	AfxEnableControlContainer();

	// Standard initialization
	// If you are not using these features and wish to reduce the size
	//  of your final executable, you should remove from the following
	//  the specific initialization routines you do not need.

#ifdef _AFXDLL
	Enable3dControls();			// Call this when using MFC in a shared DLL
#else
	Enable3dControlsStatic();	// Call this when linking to MFC statically
#endif

	// Change the registry key under which our settings are stored.
	// TODO: You should modify this string to be something appropriate
	// such as the name of your company or organization.
	SetRegistryKey(_T("Local AppWizard-Generated Applications"));

	LoadStdProfileSettings();  // Load standard INI file options (including MRU)

	// Register the application's document templates.  Document templates
	//  serve as the connection between documents, frame windows and views.

	CMultiDocTemplate* pDocTemplate;
	pDocTemplate = new CMultiDocTemplate(
		IDR_MULTIDTYPE,
		RUNTIME_CLASS(CMultidDoc),
		RUNTIME_CLASS(CChildFrame), // custom MDI child frame
		RUNTIME_CLASS(CMultidView));
	AddDocTemplate(pDocTemplate);

	// create main MDI Frame window
	CMainFrame* pMainFrame = new CMainFrame;//创建窗口对象CMainFrame
	if (!pMainFrame->LoadFrame(IDR_MAINFRAME))//为对象加载资源,在sdk中是用CreateWindow创建的窗口
		return FALSE;
	m_pMainWnd = pMainFrame;

	// Parse command line for standard shell commands, DDE, file open
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);

	// Dispatch commands specified on the command line
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;

	// The main window has been initialized, so show and update it.
	pMainFrame->ShowWindow(m_nCmdShow);//显示窗口
	pMainFrame->UpdateWindow();//更新窗口

	return TRUE;
}
窗口已经创建,下面就是怎么获取窗口消息?
跟踪theApp->Run();在CMultidApp类没有改写基类的Run()成员函数,则调用到基类CWinApp的Run,在调用到CWinThread::Run();
// Main running routine until application exits
int CWinApp::Run()//appcore.cpp
{
	if (m_pMainWnd == NULL && AfxOleGetUserCtrl())
	{
		// Not launched /Embedding or /Automation, but has no main window!
		TRACE0("Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application.\n");
		AfxPostQuitMessage(0);
	}
	return CWinThread::Run();
}


int CWinThread::Run()//thrdCore.cpp
{
    ASSERT_VALID(this);

    // for tracking the idle time state
    BOOL bIdle = TRUE;
    LONG lIdleCount = 0;

    // acquire and dispatch messages until a WM_QUIT message is received.
    for (;;)
    {
        // phase1: check to see if we can do idle work
        while (bIdle &&
            !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
        {
            // call OnIdle while in bIdle state
            if (!OnIdle(lIdleCount++))
                bIdle = FALSE; // assume "no idle" state
        }

        // phase2: pump messages while available
        do
        {
            // pump message, but quit on WM_QUIT
            if (!PumpMessage())//在同1cpp
                return ExitInstance();

            // reset "no idle" state after pumping "normal" message
            if (IsIdleMessage(&m_msgCur))
            {
                bIdle = TRUE;
                lIdleCount = 0;
            }

        } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
    }

    ASSERT(FALSE);  // not reachable
}



BOOL CWinThread::PumpMessage()
{
    ASSERT_VALID(this);

    if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
    {
#ifdef _DEBUG
        if (afxTraceFlags & traceAppMsg)
            TRACE0("CWinThread::PumpMessage - Received WM_QUIT.\n");
        m_nDisablePumpCount++; // application must die
            // Note: prevents calling message loop things in 'ExitInstance'
            // will never be decremented
#endif
        return FALSE;
    }

#ifdef _DEBUG
    if (m_nDisablePumpCount != 0)
    {
        TRACE0("Error: CWinThread::PumpMessage called when not permitted.\n");
        ASSERT(FALSE);
    }
#endif

#ifdef _DEBUG
    if (afxTraceFlags & traceAppMsg)
        _AfxTraceMsg(_T("PumpMessage"), &m_msgCur);
#endif

    // process this message

    if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
    {
        ::TranslateMessage(&m_msgCur);//翻译消息
        ::DispatchMessage(&m_msgCur);//分发消息
    }
    return TRUE;
}

消息已经获取,也可看到同sdk中消息获取原理一模一样,接下来就是将获取到的消息给了什么函数去处理?当然是窗口函数。
在创建窗口CMainFrame的时候,指定了窗口处理函数。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值