1.在MFC的源代码中查找入口函数WinMain().
X:/Program Files/Microsoft Visual Studio/VC98/MFC/SRC
APPMODUL.CPP文件中
------------------------------------------------------------------------
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{ //Breakpoint1
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
-------------------------------------------------------------------------
TCHAR.H
------------------------------------------------------------------------
#define _tWinMain WinMain
------------------------------------------------------------------------
Test.cpp
------------------------------------------------------------------------
CTestApp::CTestApp()
{ //Breakpoint2
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
------------------------------------------------------------------------
RUNNING: Breakpoint2->Breakpoint1
首先进入CTestApp的构造函数,然后才到达_tWinMain()函数
Test.cpp
--------------------------------------------------------------------------
CTestApp theApp; //全局对象 //Breakpoint3
--------------------------------------------------------------------------
RUNNING: Breakpoint3->Breakpoint2->Breakpoint1
2.在MFC程序中,通过产生一个应用程序类的对象来表示应用程序本身
在X:/Program Files/Microsoft Visual Studio/VC98/MFC/SRC搜索WinApp
得到:
APPCORE.CPP
--------------------------------------------------------------------------
CWinApp::CWinApp(LPCTSTR lpszAppName) //CWinApp的构造函数
{
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; //this指针指向CTestApp对象(theApp)
//根据继承性的原理(使用程序测试)
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_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_nSafetyPoolSize = 512; // default size
}
--------------------------------------------------------------------------------
CWinApp的构造函数带有参数LPCTSTR lpszAppName,而CTestApp的构造函数不带有任何参数.
在AFXWIN.H文件中
-----------------------------------------------------------------------------
class CWinApp : public CWinThread
{
DECLARE_DYNAMIC(CWinApp)
public:
// Constructor
CWinApp(LPCTSTR lpszAppName = NULL); //CWinApp的构造函数有缺省的参数
..............................
}
------------------------------------------------------------------------------
3. 回到_tWinMain(...)函数
查找AfxWinMain()函数,Afx表示应用程序框架类函数,相当于全局函数
-------------------------------------------------------------------------------
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL);
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread(); //线程的指针,也是指向子类
CWinApp* pApp = AfxGetApp(); //获得指针,这里pApp指向派生类的指针(theApp)
// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication())//pApp->InitApplication()MFC内部
//管理的函数
goto InitFailure;
// Perform specific initializations
if (!pThread->InitInstance()) //pThread->InitInstance() //Breakpoint4
//在AFXWIN.H中
//virtual BOOL InitInstance();
//InitInstance是一个虚函数
//此时调用的InitInstance函数是
//CTestApp::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();//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;
}
------------------------------------------------------------------------------------
4.在CTestApp的InitInstance()函数设置断点
------------------------------------------------------------------------------------
BOOL CTestApp::InitInstance()
{ //Breakpoint5
AfxEnableControlContainer();
.............
}
-------------------------------------------------------------------------------------
RUNNING:<1> 定义全局对象 CTestApp theApp; (Breakpoint3)
<2> 构造全局对象 CTestApp::CTestApp()(Breakpoint2)
<3> 构造基类对象
<4> 进入_tWinMain函数 (Breakpoint1)
<5> 到达AfxWinMain函数
if (!pThread->InitInstance()) (Breakpoint4)
<6> 到达CTestApp::InitInstance() (Breakpoint5)
5.注册窗口类
AfxEndDeferRegisterClass函数
WINCORE.CPP中 (注册窗口类应该在PreCreateWindow中调用)
由于是单文档应用程序的原因,事先调用AfxEndDeferRegisterClass函数注册窗口
-------------------------------------------------------------------------------------
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
{ // Breakpoint6
// 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;
........................
wndcls.lpfnWndProc = DefWindowProc;
}
-------------------------------------------------------------------------------------
BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)
{
WNDCLASS wndcls;
if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,
&wndcls)) //判断窗口是否注册
{
// class already registered
return TRUE;
}
if (!::RegisterClass(lpWndClass)) //调用RegisterClass,API函数
{
TRACE1("Can't register window class named %s/n",
lpWndClass->lpszClassName);
return FALSE;
}
.................................................
}
-------------------------------------------------------------------------------------
<7> 注册窗口类
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister) (Breakpoint6)
6.产生窗口
CMainFrm.CPP
-------------------------------------------------------------------------------------
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{ (Breakpoint7)
if( !CFrameWnd::PreCreateWindow(cs) ) //函数调用
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return TRUE;
}
-------------------------------------------------------------------------------------
<8>BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) (Breakpoint7)
WINFRM.CPP
-------------------------------------------------------------------------------------
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{ (Breakpoint8)
if (cs.lpszClass == NULL)
{
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
//AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)判断当前的窗口类有没有
//注册,没有就注册
cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background
}
if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4)
cs.style |= FWS_PREFIXTITLE;
if (afxData.bWin4)
cs.dwExStyle |= WS_EX_CLIENTEDGE;
return TRUE;
}
-------------------------------------------------------------------------------------
AFXIMPL.h
-------------------------------------------------------------------------------------
#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)
-------------------------------------------------------------------------------------
<9> BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) (Breakpoint8)
WINCORE.cpp
-------------------------------------------------------------------------------------
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)
{ (Breakpoint9)
// allow modification of several common create parameters
CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
..............................
if (!PreCreateWindow(cs)) //PreCreateWindow是一个虚函数
{
PostNcDestroy();
return FALSE;
}
...............................
}
-------------------------------------------------------------------------------------
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect, CWnd* pParentWnd, UINT nID,
LPVOID lpParam /* = NULL */) //调用上面的CreateEx函数
{ (Breakpoint10)
return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)nID, lpParam);
}
-------------------------------------------------------------------------------------
WINFRM.CPP
-------------------------------------------------------------------------------------
BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
LPCTSTR lpszMenuName,
DWORD dwExStyle,
CCreateContext* pContext)
{ (Breakpoint11)
..........................
if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext)) //调用上面的
{ //CreateEx函数
TRACE0("Warning: failed to create CFrameWnd./n");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}
....................................................
}
-----------------------------------------------------------------------------------
7.显示更新窗口
Test.CPP
-----------------------------------------------------------------------------------
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow(); //m_pMainWnd指向框架窗口对象的指针
-----------------------------------------------------------------------------------
8.消息循环
THRDCORE.CPP
-----------------------------------------------------------------------------------
int CWinThread::Run()
{
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())
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;
}
----------------------------------------------------------------------------------
9.窗口过程 (在AfxEndDeferRegisterClass函数中设置)
wndcls.lpfnWndProc = DefWindowProc; //缺省的窗口过程
10.在MFC如何整合CMainFrm类,CTestView类,CTestDoc类?
在
BOOL CTestApp::InitInstance()中:
------------------------------------------------------------------------------------
CSingleDocTemplate* pDocTemplate; //定义一个单文档的类模板
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestDoc), //通过单文档的模板组合在一起
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CTestView));
AddDocTemplate(pDocTemplate); //增加到文档模板中
-------------------------------------------------------------------------------------
11.窗口与C++类的关系
窗口销毁,C++的对象不一定销毁,窗口与C++窗口类的关系只不过是窗口类保存了窗口的句柄.
12.CButton
m_btn.Create("维新",WS_CHILD | WS_VISIBLE | BS_AUTO3STATE,
CRect(0,0,100,100),/*GetParent(),*/this,123);
CButton的窗口风格 WS_CHILD | WS_VISIBLE | BS_AUTO3STATE
CTestView的父窗口是CMainFrm,在CTestView里面使用GetParent()函数,得到CMainFrm对象的
指针.