MFC程序框架剖析

来源:互联网 发布:mac画流程图软件 编辑:程序博客网 时间:2024/04/30 20:28

1:程序的“导火索”---theApp

CmyApp theApp;

在声明对象的同时,调用其构造函数。按C++的语法,首先要调用其基类Cwinapp的构造函数. 这个文件主要用于应用程序的一些初始化操作。

class CWinApp : public CWinThread

{

    DECLARE_DYNAMIC(CWinApp)

public:

// Constructor

    CWinApp(LPCTSTR lpszAppName = NULL); 

…………

}

 

CWinApp::CWinApp(LPCTSTR lpszAppName)

{

    if (lpszAppName != NULL)

       m_pszAppName = _tcsdup(lpszAppName);

    else

       m_pszAppName = NULL;

    // initialize CWinThread state

    AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();

    AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;

    ASSERT(AfxGetThread() == NULL);

    pThreadState->m_pCurrentWinThread = this;

    ASSERT(AfxGetThread() == this);

    m_hThread = ::GetCurrentThread();

    m_nThreadID = ::GetCurrentThreadId();

    // initialize CWinApp state

    ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please

    pModuleState->m_pCurrentWinApp = this;

    ASSERT(AfxGetApp() == this);

    // in non-running state until WinMain

    m_hInstance = NULL;

    m_hLangResourceDLL = NULL;

    m_pszHelpFilePath = NULL;

    m_pszProfileName = NULL;

    m_pszRegistryKey = NULL;

    m_pszExeName = NULL;

    m_pRecentFileList = NULL;

    m_pDocManager = NULL;

    m_atomApp = m_atomSystemTopic = NULL;

    m_lpCmdLine = NULL;

    m_pCmdInfo = NULL;

    // initialize wait cursor state

    m_nWaitCursorCount = 0;

    m_hcurWaitCursorRestore = NULL;

    // initialize current printer state

    m_hDevMode = NULL;

    m_hDevNames = NULL;

    m_nNumPreviewPages = 0;     // not specified (defaults to 1)

    // initialize DAO state

    m_lpfnDaoTerm = NULL;   // will be set if AfxDaoInit called

    // other initialization

    m_bHelpMode = FALSE;

    m_eHelpType = afxWinHelp;

    m_nSafetyPoolSize = 512;        // default size

}

2:theApp之后的隐藏代码,由他控制整个程序的流程。

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

    LPTSTR lpCmdLine, int nCmdShow)

{

    // call shared/exported WinMain

    return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

 

其中有宏定义:#define _tWinMain   wWinMain

 

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

    LPTSTR lpCmdLine, int nCmdShow)

{

    ASSERT(hPrevInstance == NULL);

    int nReturnCode = -1;

    CWinThread* pThread = AfxGetThread();// CWinApp是从CWinThread派生的,

    CWinApp* pApp = AfxGetApp();  //实质上就是pThread==pApp

    // AFX internal initialization

    if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))  //用于初始化

       goto InitFailure;

    // App global initializations (rare)

    if (pApp != NULL && !pApp->InitApplication())   //用于初始化

       goto InitFailure;

    // Perform specific initializations

    if (!pThread->InitInstance())   //注意多态性  virtual BOOL InitInstance();

                                   //又因为pThread==pApp,所以调用pApp-> InitInstance()

    {

       if (pThread->m_pMainWnd != NULL)

       {

           TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd/n");

           pThread->m_pMainWnd->DestroyWindow();

       }

       nReturnCode = pThread->ExitInstance();

       goto InitFailure;

    }

    nReturnCode = pThread->Run();  //控制消息循环

InitFailure:

#ifdef _DEBUG

    // Check for missing AfxLockTempMap calls

    if (AfxGetModuleThreadState()->m_nTempMapLock != 0)

    {

       TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld)./n",

           AfxGetModuleThreadState()->m_nTempMapLock);

    }

    AfxLockTempMaps();

    AfxUnlockTempMaps(-1);

#endif

    AfxWinTerm();

    return nReturnCode;

}

由上面的程序可以看到几个很重要的函数

1AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))

       goto InitFailure;

 (2) pApp->InitApplication())

 (3) pThread->InitInstance()

 (4) pThread->Run()

其中12 也是完成程序的一些初始化工作,4 主要是为了处理消息,3呢,很关键,我们运行时看到的窗口就是从这里产生。下面一一介绍

3:程序自动产生的InitInstance()函数

以下是自动生成的InitInstance()源程序:

BOOL CmyApp::InitInstance()

    {

    // 如果一个运行在 Windows XP 上的应用程序清单指定要

    // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,

    //则需要 InitCommonControls()。否则,将无法创建窗口。

    InitCommonControls();

    CWinApp::InitInstance();

    // 初始化 OLE

    if (!AfxOleInit())

    {

       AfxMessageBox(IDP_OLE_INIT_FAILED);

       return FALSE;

    }

    AfxEnableControlContainer();

    // 标准初始化

    // 如果未使用这些功能并希望减小

    // 最终可执行文件的大小,则应移除下列

    // 不需要的特定初始化例程

    // 更改用于存储设置的注册表项

    // TODO: 应适当修改该字符串,

    // 例如修改为公司或组织名

    SetRegistryKey(_T("应用程序向导生成的本地应用程序"));

    LoadStdProfileSettings(4);  // 加载标准 INI 文件选项(包括 MRU)

    // 注册应用程序的文档模板。文档模板

    // 将用作文档、框架窗口和视图之间的连接

    CMultiDocTemplate* pDocTemplate;

    pDocTemplate = new CMultiDocTemplate(IDR_myTYPE,

       RUNTIME_CLASS(CmyDoc),

       RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架

       RUNTIME_CLASS(CmyView));

    if (!pDocTemplate)

       return FALSE;

    AddDocTemplate(pDocTemplate);

    // 创建主 MDI 框架窗口

    CMainFrame* pMainFrame = new CMainFrame;

    if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))

       return FALSE;

    m_pMainWnd = pMainFrame;

    // 仅当具有后缀时才调用 DragAcceptFiles

    //  MDI 应用程序中,这应在设置 m_pMainWnd 之后立即发生

    // 分析标准外壳命令、DDE、打开文件操作的命令行

    CCommandLineInfo cmdInfo;

    ParseCommandLine(cmdInfo);

    // 调度在命令行中指定的命令。如果

    // /RegServer/Register/Unregserver /Unregister 启动应用程序,则返回 FALSE

    if (!ProcessShellCommand(cmdInfo))   //引发窗口注册

       return FALSE;

    // 主窗口已初始化,因此显示它并对其进行更新

    pMainFrame->ShowWindow(m_nCmdShow);

    pMainFrame->UpdateWindow();

    return TRUE;

}

 

其中,注册窗口用到了一下函数,比较长,如下:

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)

{

    // mask off all classes that are already registered

    AFX_MODULE_STATE* pModuleState = AfxGetModuleState();

    fToRegister &= ~pModuleState->m_fRegisteredClasses;

    if (fToRegister == 0)

       return TRUE;

    LONG fRegisteredClasses = 0;

    // common initialization

    WNDCLASS wndcls;

    memset(&wndcls, 0, sizeof(WNDCLASS));   // start with NULL defaults

    wndcls.lpfnWndProc = DefWindowProc;    //窗口处理函数

    wndcls.hInstance = AfxGetInstanceHandle();

    wndcls.hCursor = afxData.hcurArrow;

 

    INITCOMMONCONTROLSEX init;

    init.dwSize = sizeof(init);

 

    // work to register classes as specified by fToRegister, populate fRegisteredClasses as we go

    if (fToRegister & AFX_WND_REG)

    {

       // Child windows - no brush, no icon, safest default class styles

       wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

       wndcls.lpszClassName = _afxWnd;

       if (AfxRegisterClass(&wndcls))

           fRegisteredClasses |= AFX_WND_REG;

    }

    if (fToRegister & AFX_WNDOLECONTROL_REG)

    {

       // OLE Control windows - use parent DC for speed

       wndcls.style |= CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

       wndcls.lpszClassName = _afxWndOleControl;

       if (AfxRegisterClass(&wndcls))

           fRegisteredClasses |= AFX_WNDOLECONTROL_REG;

    }

    if (fToRegister & AFX_WNDCONTROLBAR_REG)

    {

       // Control bar windows

       wndcls.style = 0;   // control bars don't handle double click

       wndcls.lpszClassName = _afxWndControlBar;

       wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);

       if (AfxRegisterClass(&wndcls))

           fRegisteredClasses |= AFX_WNDCONTROLBAR_REG;

    }

    if (fToRegister & AFX_WNDMDIFRAME_REG)

    {

       // MDI Frame window (also used for splitter window)

       wndcls.style = CS_DBLCLKS;

       wndcls.hbrBackground = NULL;

       if (_AfxRegisterWithIcon(&wndcls, _afxWndMDIFrame, AFX_IDI_STD_MDIFRAME))

           fRegisteredClasses |= AFX_WNDMDIFRAME_REG;

    }

    if (fToRegister & AFX_WNDFRAMEORVIEW_REG)

    {

       // SDI Frame or MDI Child windows or views - normal colors

       wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

       wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

       if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME))

           fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG;

    }

    if (fToRegister & AFX_WNDCOMMCTLS_REG)

    {

       // this flag is compatible with the old InitCommonControls() API

       init.dwICC = ICC_WIN95_CLASSES;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WIN95CTLS_MASK);

       fToRegister &= ~AFX_WIN95CTLS_MASK;

    }

    if (fToRegister & AFX_WNDCOMMCTL_UPDOWN_REG)

    {

       init.dwICC = ICC_UPDOWN_CLASS;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_UPDOWN_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_TREEVIEW_REG)

    {

       init.dwICC = ICC_TREEVIEW_CLASSES;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_TREEVIEW_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_TAB_REG)

    {

       init.dwICC = ICC_TAB_CLASSES;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_TAB_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_PROGRESS_REG)

    {

       init.dwICC = ICC_PROGRESS_CLASS;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_PROGRESS_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_LISTVIEW_REG)

    {

       init.dwICC = ICC_LISTVIEW_CLASSES;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_LISTVIEW_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_HOTKEY_REG)

    {

       init.dwICC = ICC_HOTKEY_CLASS;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_HOTKEY_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_BAR_REG)

    {

       init.dwICC = ICC_BAR_CLASSES;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_BAR_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_ANIMATE_REG)

    {

       init.dwICC = ICC_ANIMATE_CLASS;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ANIMATE_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_INTERNET_REG)

    {

       init.dwICC = ICC_INTERNET_CLASSES;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_INTERNET_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_COOL_REG)

    {

       init.dwICC = ICC_COOL_CLASSES;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_COOL_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_USEREX_REG)

    {

       init.dwICC = ICC_USEREX_CLASSES;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_USEREX_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_DATE_REG)

    {

       init.dwICC = ICC_DATE_CLASSES;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_DATE_REG);

    }

    if (fToRegister & AFX_WNDCOMMCTL_LINK_REG)

    {

       init.dwICC = ICC_LINK_CLASS;

       fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_LINK_REG);

    }

 

 

    // save new state of registered controls

    pModuleState->m_fRegisteredClasses |= fRegisteredClasses;

 

    // special case for all common controls registered, turn on AFX_WNDCOMMCTLS_REG

    if ((pModuleState->m_fRegisteredClasses & AFX_WIN95CTLS_MASK) == AFX_WIN95CTLS_MASK)

    {

       pModuleState->m_fRegisteredClasses |= AFX_WNDCOMMCTLS_REG;

       fRegisteredClasses |= AFX_WNDCOMMCTLS_REG;

    }

 

    // must have registered at least as mamy classes as requested

    return (fToRegister & fRegisteredClasses) == fToRegister;

}

 

他是在PreCreateWindow中调用的注册,

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)

{

    if (cs.lpszClass == NULL)

    {

       VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

       cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background

    }

    if (cs.style & FWS_ADDTOTITLE)

       cs.style |= FWS_PREFIXTITLE;

    cs.dwExStyle |= WS_EX_CLIENTEDGE;

    return TRUE;

}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

    if( !CFrameWnd::PreCreateWindow(cs) )

       return FALSE;

    // TODO: Modify the Window class or styles here by modifying

    //  the CREATESTRUCT cs

    return TRUE;

}

BOOL CView::PreCreateWindow(CREATESTRUCT & cs)

{

    ASSERT(cs.style & WS_CHILD);

    if (cs.lpszClass == NULL)

    {

       VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

       cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background

    }

    if (cs.style & WS_BORDER)

    {

       cs.dwExStyle |= WS_EX_CLIENTEDGE;

       cs.style &= ~WS_BORDER;

    }

    return TRUE;

}

BOOL CTestView::PreCreateWindow(CREATESTRUCT& cs)

{

    // TODO: Modify the Window class or styles here by modifying

    //  the CREATESTRUCT cs

    return CView::PreCreateWindow(cs);

}

有几点要说明

1m_pMainWnd,头文件里并没有这个变量呀? 噢,这个在基类里定义的public 类型的变量,所以,他是通过继承得到的。

(2) 你注意过吗,当我们一点运行,会默认出来一个视图窗口,这是谁调用的呢?哦,就是下面这几行,它调用了opendocument() 函数。

CCommandLineInfo cmdInfo;

    ParseCommandLine(cmdInfo);

    if (!ProcessShellCommand(cmdInfo))

       return FALSE

3)这个函数有个关键的地方

CMultiDocTemplate* pDocTemplate;

    pDocTemplate = new CMultiDocTemplate(IDR_myTYPE,

       RUNTIME_CLASS(CmyDoc),

       RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架

       RUNTIME_CLASS(CmyView));

    if (!pDocTemplate)

       return FALSE;

    AddDocTemplate(pDocTemplate);

通过它,把视图,窗口和文档结合起来。

4:主窗口CMainFrame的创建

(1)通过CMainFrame* pMainFrame = new CMainFrame;

 我们得到的是不断调用的基类

CMainFrame::CMainFrame()

{

    // TODO: 在此添加成员初始化代码

}

CMDIFrameWnd::CMDIFrameWnd()

{

    m_hWndMDIClient = NULL;

}

CFrameWnd::CFrameWnd()

{

    ASSERT(m_hWnd == NULL);

    m_nWindow = -1;                 // unknown window ID

    m_bAutoMenuEnable = TRUE;       // auto enable on by default

    m_lpfnCloseProc = NULL;

    m_hMenuDefault = NULL;

    m_hAccelTable = NULL;

    m_nIDHelp = 0;

    m_nIDTracking = 0;

    m_nIDLastMessage = 0;

    m_pViewActive = NULL;

    m_cModalStack = 0;              // initialize modality support

    m_phWndDisable = NULL;

    m_pNotifyHook = NULL;

    m_hMenuAlt = NULL;

    m_nIdleFlags = 0;               // no idle work at start

    m_rectBorder.SetRectEmpty();

    m_bHelpMode = HELP_INACTIVE;    // not in Shift+F1 help mode

    m_dwPromptContext = 0;

    m_pNextFrameWnd = NULL;         // not in list yet

 

    m_bInRecalcLayout = FALSE;

    m_pFloatingFrameClass = NULL;

    m_nShowDelay = -1;              // no delay pending

    AddFrameWnd();

}

(2)pMainFrame->LoadFrame(IDR_MAINFRAME)所引发的一系列

 

BOOL CMDIFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,

    CWnd* pParentWnd, CCreateContext* pContext)

{

    if (!CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle,

      pParentWnd, pContext))

       return FALSE;

 

    // save menu to use when no active MDI child window is present

    ASSERT(m_hWnd != NULL);

    m_hMenuDefault = ::GetMenu(m_hWnd);

    if (m_hMenuDefault == NULL)

       TRACE(traceAppMsg, 0, "Warning: CMDIFrameWnd without a default menu./n");

    return TRUE;

}

BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,

    CWnd* pParentWnd, CCreateContext* pContext)

{

    // only do this once

    ASSERT_VALID_IDR(nIDResource);

    ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);

    m_nIDHelp = nIDResource;    // ID for help context (+HID_BASE_RESOURCE)

    CString strFullString;

    if (strFullString.LoadString(nIDResource))

       AfxExtractSubString(m_strTitle, strFullString, 0);    // first sub-string

    VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

    // attempt to create the window

    LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);

    CString strTitle = m_strTitle;

    if (!Create(lpszClass, strTitle, dwDefaultStyle, rectDefault,

     pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))

    {

       return FALSE;   // will self destruct on failure normally

    }

    // save the default menu handle

    ASSERT(m_hWnd != NULL);

    m_hMenuDefault = ::GetMenu(m_hWnd);

    // load accelerator resource

    LoadAccelTable(MAKEINTRESOURCE(nIDResource));

    if (pContext == NULL)   // send initial update

       SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);

    return TRUE;

}

BOOL CFrameWnd::Create(LPCTSTR lpszClassName,

    LPCTSTR lpszWindowName,

    DWORD dwStyle,

    const RECT& rect,

    CWnd* pParentWnd,

    LPCTSTR lpszMenuName,

    DWORD dwExStyle,

    CCreateContext* pContext)

{

    HMENU hMenu = NULL;

    if (lpszMenuName != NULL)

    {

       // load in a menu that will get destroyed when window gets destroyed

       HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);

       if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)

       {

           TRACE(traceAppMsg, 0, "Warning: failed to load menu for CFrameWnd./n");

           PostNcDestroy();            // perhaps delete the C++ object

           return FALSE;

       }

    }

 

    m_strTitle = lpszWindowName;    // save title for later

 

    if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,

      rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,

      pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))

    {

       TRACE(traceAppMsg, 0, "Warning: failed to create CFrameWnd./n");

       if (hMenu != NULL)

           DestroyMenu(hMenu);

       return FALSE;

    }

 

    return TRUE;

}

 

因为CFrameWnd没有重新写CreateEX,所以是调用的基类的CreateEx的函数:

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

    LPCTSTR lpszWindowName, DWORD dwStyle,

    int x, int y, int nWidth, int nHeight,

    HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

{

    // allow modification of several common create parameters

    CREATESTRUCT cs;

    cs.dwExStyle = dwExStyle;

    cs.lpszClass = lpszClassName;

    cs.lpszName = lpszWindowName;

    cs.style = dwStyle;

    cs.x = x;

    cs.y = y;

    cs.cx = nWidth;

    cs.cy = nHeight;

    cs.hwndParent = hWndParent;

    cs.hMenu = nIDorHMenu;

    cs.hInstance = AfxGetInstanceHandle();

    cs.lpCreateParams = lpParam;

 

    if (!PreCreateWindow(cs))

    {

       PostNcDestroy();

       return FALSE;

    }

    AfxHookWindowCreate(this);

    HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,

           cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,

           cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);

 

#ifdef _DEBUG

    if (hWnd == NULL)

    {

       TRACE(traceAppMsg, 0, "Warning: Window creation failed: GetLastError returns 0x%8.8X/n",

           GetLastError());

    }

#endif

 

    if (!AfxUnhookWindowCreate())

       PostNcDestroy();        // cleanup if CreateWindowEx fails too soon

 

    if (hWnd == NULL)

       return FALSE;

    ASSERT(hWnd == m_hWnd); // should have been set in send msg hook

    return TRUE;

}

 

可以看到,::CreateWindowEx是一个全局的函数,在其中触发WM_CREATE消息,进而调用我们自己定义的CMainFrame::OnCreate()

int CMainFrame::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_MAINFRAME))

    {

       TRACE0("未能创建工具栏/n");

       return -1;      // 未能创建

    }

    if (!m_wndStatusBar.Create(this) ||   

       !m_wndStatusBar.SetIndicators(indicators,

       sizeof(indicators)/sizeof(UINT)))

    {

       TRACE0("未能创建状态栏/n");

       return -1;      // 未能创建

    }

     //TODO: 如果不需要工具栏可停靠,则删除这三行

    m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

    EnableDocking(CBRS_ALIGN_ANY);

    DockControlBar(&m_wndToolBar);

 

    return 0;

}

5:运行后为什么能产生CMainFarme,文档 ,视图以及视图外包围的farme呢?

你注意过吗,当我们一点运行,会默认出来一个视图窗口,这是谁调用的呢?哦,就是下面这几行,它调用void CWinApp::OnFileNew()函数.

CCommandLineInfo cmdInfo;

    ParseCommandLine(cmdInfo);

    if (!ProcessShellCommand(cmdInfo))

       return FALSE

你可以自己跟踪以下。这里有个小技巧,你可以在BOOL CmyDoc::OnNewDocument()处设立断点,然后“跳出”,最后你会达到起始点!ProcessShellCommand(cmdInfo)

void CWinApp::OnFileNew()

{

    if (m_pDocManager != NULL)

       m_pDocManager->OnFileNew();    //接着调用下面的函数

}

 

void CDocManager::OnFileNew()

{

    if (m_templateList.IsEmpty())

    {

       TRACE(traceAppMsg, 0, "Error: no document templates registered with CWinApp./n");

       AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);

       return;

    }

    CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();

    if (m_templateList.GetCount() > 1)

    {

       // more than one document template to choose from

       // bring up dialog prompting user

       CNewTypeDlg dlg(&m_templateList);

       INT_PTR nID = dlg.DoModal();

       if (nID == IDOK)

           pTemplate = dlg.m_pSelectedTemplate;

       else

           return;     // none - cancel operation

    }

    ASSERT(pTemplate != NULL);

    ASSERT_KINDOF(CDocTemplate, pTemplate);

    pTemplate->OpenDocumentFile(NULL);  //接着调用下面的函数

       // if returns NULL, the user has already been alerted

}

 

CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,

   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);

    }

 

    InitialUpdateFrame(pFrame, pDocument, bMakeVisible);

    return pDocument;

}

 

我需要对上述函数进行进一步说明

(1)CreateNewDocument()产生文档

CDocument* CDocTemplate::CreateNewDocument()

{

    // default implementation constructs one from CRuntimeClass

    if (m_pDocClass == NULL)

    {

       TRACE(traceAppMsg, 0, "Error: you must override CDocTemplate::CreateNewDocument./n");

       ASSERT(FALSE);

       return NULL;

    }

    CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();

    if (pDocument == NULL)

    {

       TRACE(traceAppMsg, 0, "Warning: Dynamic create of document type %hs failed./n",

           m_pDocClass->m_lpszClassName);

       return NULL;

    }

    ASSERT_KINDOF(CDocument, pDocument);

    AddDocument(pDocument);

    return pDocument;

}

(2)CreateNewFrame(pDocument, NULL),产生框架和视图

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, 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;

}

在此函数中,不仅Frame被动态创建出来,其对应的窗口也以LoadFrame产生出来。其中参数context帮助产生了视图。别管怎么产生了,我跟踪不到,反正就是这个时候把框架和视图一起产生了出来。此时激发了WN_CREATE消息,从而引发CFrameWnd::OnCreate函数。我分别把相应的函数写在下面

CFrameWnd::OnCreate------CFrameWnd::OnCreateHelper------CFrameWnd:OnCreateClient-----CFrameWnd::CreateView*/

 

int CFrameWnd::OnCreate(LPCREATESTRUCT lpcs)

{

    CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;

    return OnCreateHelper(lpcs, pContext);

}

 

int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext)

{

    if (CWnd::OnCreate(lpcs) == -1)

       return -1;

    // create special children first

    if (!OnCreateClient(lpcs, pContext))

    {

       TRACE(traceAppMsg, 0, "Failed to create client pane/view for frame./n");

       return -1;

    }

    // post message for initial message string

    PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);

    // make sure the child windows have been properly sized

    RecalcLayout();

    return 0;   // create ok

}

BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext)

{

    // default create client will create a view if asked for it

    if (pContext != NULL && pContext->m_pNewViewClass != NULL)

    {

       if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL)

           return FALSE;

    }

    return TRUE;

}

CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)

{

    ASSERT(m_hWnd != NULL);

    ASSERT(::IsWindow(m_hWnd));

    ASSERT(pContext != NULL);

    ASSERT(pContext->m_pNewViewClass != NULL);

    // Note: can be a CWnd with PostNcDestroy self cleanup

    CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();

    if (pView == NULL)

    {

       TRACE(traceAppMsg, 0, "Warning: Dynamic create of view type %hs failed./n",

           pContext->m_pNewViewClass->m_lpszClassName);

       return NULL;

    }

    ASSERT_KINDOF(CWnd, pView);

    // views are always created with a border!

    if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,

       CRect(0,0,0,0), this, nID, pContext))

    {

       TRACE(traceAppMsg, 0, "Warning: could not create view for frame./n");

       return NULL;        // can't continue without a view

    }

    if (pView->GetExStyle() & WS_EX_CLIENTEDGE)

    {

       // remove the 3d style from the frame, since the view is

       //  providing it.

       // make sure to recalc the non-client area

       ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);

    }

    return pView;

}

6:窗口的现实和刷新(激发paint事件)

pMainFrame->ShowWindow(m_nCmdShow);

    pMainFrame->UpdateWindow();

7:pThread->Run()

/*thrdcore.cpp文件*/

// main running routine until thread exits

int CWinThread::Run()

{

    ASSERT_VALID(this);

    _AFX_THREAD_STATE* pState = AfxGetThreadState();

 

    // 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(&(pState->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())

              return ExitInstance();

 

           // reset "no idle" state after pumping "normal" message

           //if (IsIdleMessage(&m_msgCur))

           if (IsIdleMessage(&(pState->m_msgCur)))

           {

              bIdle = TRUE;

              lIdleCount = 0;

           }

 

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

    }

}

BOOL CWinThread::PumpMessage()

{

  return AfxInternalPumpMessage();

}

BOOL AFXAPI AfxInternalPumpMessage()

{

    _AFX_THREAD_STATE *pState = AfxGetThreadState();

 

    if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))

    {

#ifdef _DEBUG

       TRACE(traceAppMsg, 1, "CWinThread::PumpMessage - Received WM_QUIT./n");

           pState->m_nDisablePumpCount++; // application must die

#endif

       // Note: prevents calling message loop things in 'ExitInstance'

       // will never be decremented

       return FALSE;

    }

 

#ifdef _DEBUG

  if (pState->m_nDisablePumpCount != 0)

    {

      TRACE(traceAppMsg, 0, "Error: CWinThread::PumpMessage called when not permitted./n");

      ASSERT(FALSE);

    }

#endif

 

#ifdef _DEBUG

    _AfxTraceMsg(_T("PumpMessage"), &(pState->m_msgCur));

#endif

 

  // process this message

 

    if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))

    {

      ::TranslateMessage(&(pState->m_msgCur));

      ::DispatchMessage(&(pState->m_msgCur));

    }

  return TRUE;

}
原创粉丝点击