coderLucas

Miracles happen every day.

MFC程序运行流程

->进入入口函数_tWinMain()

程序首先进入文件AppModul.cpp,找到_tWinMain()函数运行,调用其中的AfxWinMain()函数。

由于为了支持UNICODE,C运行库对WinMain其实区分了UNICODE版和ANSI版.对UNICODE版的程序,C运行库将调用wWinMain,而对于ANSI版的应用,则调用WinMain.

文件tchar.h定义:

1
2
3
4
5
6
7
8
9
10
11
12
...
#ifdef  _UNICODE
...
#define _tmain      wmain
#define _tWinMain   wWinMain
...
 
#else   /* ndef _UNICODE */
...
#define _tmain      main
#define _tWinMain   WinMain
...

MFC的代码设计时是自动支持UNICODE的,所以,MFC的WinMain在APPMODUL.CPP被定义为_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow),无论用户#define _UNICODE与否,MFC的WinMain都会被调用.

1
2
3
4
5
6
7
8
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    _In_ LPTSTR lpCmdLine, int nCmdShow)
#pragma warning(suppress: 4985)
{
    // call shared/exported WinMain
    return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}

hInstance:表示该程序当前运行的实例句柄,它是一个数值。当程序在Windows下运行时,它唯一标识运行中的实例。

hPrevInstance:父窗口句柄。这个参数在Win32下已经不起作用了。

lpCmpLine:指定传递给应用程序的命令行参数。

nCmdShow:指定程序窗口如何显示,例如最大化、最小化、隐藏等。

 

->进入AfxWinMain()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    _In_ LPTSTR lpCmdLine, int nCmdShow)
{
    ASSERT(hPrevInstance == NULL);
 
    int nReturnCode = -1;
    CWinThread* pThread = AfxGetThread();//返回指向theApp的指针
    CWinApp* pApp = AfxGetApp();//返回指向theApp的指针
 
    // AFX internal initialization
    if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))//<strong>初始化应用程序内部环境,设置MFC</strong>
        goto InitFailure;
 
    // App global initializations (rare)
    if (pApp != NULL && !pApp->InitApplication())//<strong>初始化应用程序内部环境,设置MFC</strong>
        goto InitFailure;
 
    // Perform specific initializations
    if (!<strong>pThread->InitInstance</strong>())//<strong>完成应用程序相关工作:设计窗口类、注册窗口类、创建窗口类、显示窗口类、更新窗口类</strong>
    {
        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();//<strong>进入消息循环,处理系统消息。</strong>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<strong>//Run()调用PumpMessage函数,通过调用GetMessage、TranslateMessage、DispatchMessage等建立了消息循环并投递消息。</strong>
 
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;
}

->pThread->InitInstance()

这是个虚函数,pThread指向的是theApp,调用的是子类C***App类中的InitInstance函数。

KuaiPaiClient项目中的该函数为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
BOOL CKuaiPanClientApp::InitInstance()
{
    // InitCommonControlsEx() is required on Windows XP if an application
    // manifest specifies use of ComCtl32.dll version 6 or later to enable
    // visual styles.  Otherwise, any window creation will fail.
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    // Set this to include all the common control classes you want to use
    // in your application.
    InitCtrls.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&InitCtrls);
 
    CWinAppEx::InitInstance();
 
 
    // Initialize OLE libraries
    if (!AfxOleInit())
    {
        AfxMessageBox(IDP_OLE_INIT_FAILED);
        return FALSE;
    }
 
    AfxEnableControlContainer();
 
    EnableTaskbarInteraction(FALSE);
 
    // AfxInitRichEdit2() is required to use RichEdit control   
    // AfxInitRichEdit2();
 
    // 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
    // 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(4);  // Load standard INI file options (including MRU)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
    InitContextMenuManager();
 
    InitKeyboardManager();
 
    InitTooltipManager();
    CMFCToolTipInfo ttParams;
    ttParams.m_bVislManagerTheme = TRUE;
    theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
        RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);
 
    // Register the application's document templates.  Document templates
    //  serve as the connection between documents, frame windows and views
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CKuaiPanClientDoc),
        RUNTIME_CLASS(CMainFrame),       // main SDI frame window
        RUNTIME_CLASS(CKuaiPanClientView));
    if (!pDocTemplate)
        return FALSE;
    AddDocTemplate(pDocTemplate);//<strong>将Doc类、CMainFrame和CView三个类用文档模板关联到一起,装载到当前应用程序的全局对象theApp中。</strong>
 
    // Parse command line for standard shell commands, DDE, file open
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo);
 
    // Dispatch commands specified on the command line.  Will return FALSE if
    // app was launched with /RegServer, /Register, /Unregserver or /Unregister.
    if (!<strong>ProcessShellCommand</strong>(cmdInfo))//<strong>主要完成:设计窗口类、注册窗口类、创建窗口类</strong>
        return FALSE;
 
    // The one and only window has been initialized, so show and update it
    m_pMainWnd->ShowWindow(SW_SHOW);//显示窗口
    m_pMainWnd->UpdateWindow();//更新框架窗口
    // call DragAcceptFiles only if there's a suffix
    //  In an SDI app, this should occur after ProcessShellCommand
    return TRUE;
}
1
  
1
  

->ProcessShellCommand()调用了LoadFrame()注册并创建窗口

1
ProcessShellCommand()——>OnCmdMsg()——>AfxDispatchCmdMsg()——>pfn_Command()——>OnFileNew()——>OpenDocumentFile()——>CreateNewFrame()——>LoadFrame()
1
多次调用PreCreateWindow、CreateEx、AfxEndDeferRegisterClass 注册工具栏、状态栏等.
1
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)
{
    BOOL bResult = TRUE;
    switch (rCmdInfo.m_nShellCommand)
    {
    case CCommandLineInfo::RestartByRestartManager:
        // Re-register with the restart manager using the restart identifier from the command line
        RegisterWithRestartManager(SupportsApplicationRecovery(), rCmdInfo.m_strRestartIdentifier);
 
        // Call RestartIntance, which should reopen any previously opened document(s) and
        // optionally load the autosaved versions after querying the user about loading.
        if (RestartInstance())
            break;
        // If RestartInstance returns FALSE, then fall through to FileNew case, so
        // a new document is created--otherwise the main frame will not be created.
 
    case CCommandLineInfo::FileNew:
        if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))
            <strong>OnFileNew</strong>();
        if (m_pMainWnd == NULL)
            bResult = FALSE;
        break;
 
    // If we've been asked to open a file, call OpenDocumentFile()
    case CCommandLineInfo::FileOpen:
        if (!OpenDocumentFile(rCmdInfo.m_strFileName))
            bResult = FALSE;
        break;
 
    // If the user wanted to print, hide our main window and
    // fire a message to ourselves to start the printing
    case CCommandLineInfo::FilePrintTo:
    case CCommandLineInfo::FilePrint:
        m_nCmdShow = SW_HIDE;
        ASSERT(m_pCmdInfo == NULL);
        if(OpenDocumentFile(rCmdInfo.m_strFileName))
        {
            m_pCmdInfo = &rCmdInfo;
            ENSURE_VALID(m_pMainWnd);
            m_pMainWnd->SendMessage(WM_COMMAND, ID_FILE_PRINT_DIRECT);
            m_pCmdInfo = NULL;
        }
        bResult = FALSE;
        break;
 
    // If we're doing DDE print or print to, start up without a new document and hide ourselves
    case CCommandLineInfo::FileDDENoShow:
        m_pCmdInfo = (CCommandLineInfo*)(UINT_PTR)m_nCmdShow;
        m_nCmdShow = SW_HIDE;
        break;
 
    // If we're doing DDE open, start up without a new document, but don't hide ourselves -- this causes the
    // icon in the Windows 7 taskbar to start in the wrong position and slide into the right position.
    case CCommandLineInfo::FileDDE:
        break;
 
    // If we've been asked to register, exit without showing UI.
    // Registration was already done in InitInstance().
    case CCommandLineInfo::AppRegister:
        {
            Register();           
            bResult = FALSE;    // that's all we do
 
            // If nobody is using it already, we can use it.
            // We'll flag that we're unregistering and not save our state
            // on the way out. This new object gets deleted by the
            // app object destructor.
 
            if (m_pCmdInfo == NULL)
            {
                m_pCmdInfo = new CCommandLineInfo;
                m_pCmdInfo->m_nShellCommand = CCommandLineInfo::AppUnregister;
            }
            break;
        }
 
    // If we've been asked to unregister, unregister and then terminate
    case CCommandLineInfo::AppUnregister:
        {
            BOOL bUnregistered = Unregister();
 
            if (!rCmdInfo.m_bRunEmbedded)
            {
                if (bUnregistered)
                    AfxMessageBox(AFX_IDP_UNREG_DONE);
                else
                    AfxMessageBox(AFX_IDP_UNREG_FAILURE);
            }
            bResult = FALSE;    // that's all we do
 
            // If nobody is using it already, we can use it.
            // We'll flag that we're unregistering and not save our state
            // on the way out. This new object gets deleted by the
            // app object destructor.
 
            if (m_pCmdInfo == NULL)
            {
                m_pCmdInfo = new CCommandLineInfo;
                m_pCmdInfo->m_nShellCommand = CCommandLineInfo::AppUnregister;
            }
        }
        break;
    }
    return bResult;
}

->CreateEx()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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)
{
    ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) ||
        AfxIsValidAtom(lpszClassName));
    ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));
     
    // 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 (!<strong>PreCreateWindow</strong>(cs))//<strong>此处调用的PreCreateWindow,事实上调用的是C***App的成员函数,虚函数,可以在C***App中重写,这样可以在窗口被创建前通过结构体CREATESTRUCT更改窗口风格等
    {
        PostNcDestroy();</strong>
        return FALSE;
    }
 
    AfxHookWindowCreate(this);
    HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,//<strong>开始创建窗口</strong>
            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;
}

->AfxEndDeferRegisterClass()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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;//<strong>使窗口类的窗口过程为系统的默认窗口过程。</strong>
    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 (<strong>AfxRegisterClass</strong>(&wndcls))//<strong>注册窗口</strong>
            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);
    }
    if (fToRegister & AFX_WNDCOMMCTL_PAGER_REG)
    {
        init.dwICC = ICC_PAGESCROLLER_CLASS;
        fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_PAGER_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;
}
posted @   lucas hsueh  阅读(1063)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示