程序代码:
class CMyApp : public CWinApp
{public:
virtual BOOL InitInstance();
};
class CMainWindow : public CWnd
{
public:
CMainWindow();
protected:
char m_szText[1024]; // 客户区文本缓冲区
RECT m_rcInfo; // 文本所在方框的大小
protected:
virtual void PostNcDestroy();
afx_msg BOOL OnCreate(LPCREATESTRUCT);
afx_msg void OnPaint();
afx_msg void OnTimer(UINT nIDEvent);
DECLARE_MESSAGE_MAP()
};
CMyApp theApp;
程序流程:
首先全局对象theApp的初始化话,其会调用CMyApp的基类CWinApp的构造函数,构造函数代码如下:
CWinApp::CWinApp()
{
// 初始化CWinThread状态
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
ASSERT(AfxGetThread() == NULL);
pThreadState->m_pCurrentWinThread = this;
ASSERT(AfxGetThread() == this);
m_hThread = ::GetCurrentThread();
m_nThreadID = ::GetCurrentThreadId();
// 初始化CWinApp状态
ASSERT(pModuleState->m_pCurrentWinApp == NULL);
pModuleState->m_pCurrentWinApp = this;
ASSERT(AfxGetApp() == this);
// 直到进入WinMain函数之后再设置为运行状态
m_hInstance = NULL;
}
在构造函数中会new AFX_MODULE_STATE和AFX_MODULE_THREAD_STATE这两个结构体,并将其存放到线程本地存储中,这两个结构体中保存着一些模块和线程状态相关的信息,这不需要深究,和框架核心无多大关系,接着设置一些相关的成员变量,构造函数完了之后进入WinMain().
WinMain()代码如下:
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL);
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// 类库框架内部的初始化
if(!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// 应用程序的全局初始化
if(pApp != NULL && !pApp->InitApplication())
goto InitFailure;
// 主线程的初始化
if(!pThread->InitInstance())
{
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
// 开始与用户交互
nReturnCode = pThread->Run();
InitFailure:
return nReturnCode;
}
首先是AfxWinInit()这个主要是保存从winmian传来的参数,然后InitApplication()这个负责应用程序的初始化,这个是虚函数派生类可以重写以实现自己需要的功能,然后是InitInstance(),这个也是虚函数,CMyApp重写了这个函数,在这个函数中实现创建主窗口,在CMainWindow这个类的构造函数中首先是AfxRegisterWndClass注册窗口类,并返回一个AFX:xx:xx这种类型的类名,然后通过CreateEx这个函数创建窗口,在这个函数中首先会通过安装一个安装一个WH_CBT钩子,这个钩子的回调函数会在创建窗口时调用,当创建窗口时,系统会调用这个钩子的钩子函数,在钩子函数中首先将挂钩的CMainWindow类对象和窗口句柄添加到映射中,然后修改窗口函数为AfxWndProc,然后才开始创建窗口,接着卸掉钩子,因为钩子的工作已经完了。这样当消息来时,将会调用这个AfxWndProc窗口函数,而在这个窗口函数中首选通过窗口句柄找到对应的窗口类对象,然后在调用AfxCallWndProc,在其中调用窗口类对象中的WndProc。
BOOL CMyApp::InitInstance()
{
m_pMainWnd = new CMainWindow;
::ShowWindow(*m_pMainWnd, m_nCmdShow);
::UpdateWindow(*m_pMainWnd);
return TRUE;
}
CMainWindow::CMainWindow()
{
m_szText[0] = '\0';
LPCTSTR lpszClassName = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW,
::LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_3DFACE+1), AfxGetApp()->LoadIcon(IDI_MAIN));
CreateEx(WS_EX_CLIENTEDGE, lpszClassName,
"内存使用监视器", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 300, 230, NULL, NULL);
}
完成了第一步之后,现在开始了消息映射的创建,消息映射主要是首先消息到成员函数的映射,也就是当一个特定的消息来之后会自动调用相应的窗口类对象中的相应成员函数,至于关于其他的一些成员则是起到判别成员函数的参数返回值,从而好将消息的参数wparam和lparam转换为成员函数的参数,另外还有一个指向基类的消息映射指针,这个主要是当派生类没有处理相应的消息时,基类可以做出一些默认的处理。当消息来临是,首先通过窗口句柄找到相应的窗口类对象,然后判断是否是wm_command消息以及wm_notify消息,如果不是则直接在此对象中的消息映射条目中查找相应的消息,如果没有找到则会向基类的消息映射条目中查找,找到之后则调用消息映射条目中的函数,如果没找到则返回,调用默认的DefWndProc,进行默认的处理。至此框架完成。
此为消息映射结构
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // 窗口消息
UINT nCode; // 控制代码或WM_NOTIFY通知码
UINT nID; // 控件ID,如果为窗口消息其值为0
UINT nLastID; // 一定范围的命令的最后一个命令或控件ID,用于支持组消息映射
UINT nSig; // 指定了消息处理函数的类型
AFX_PMSG pfn; // 消息处理函数
};
// 消息映射表
struct AFX_MSGMAP
{
const AFX_MSGMAP* pBaseMap; // 其基类的消息映射表的地址
const AFX_MSGMAP_ENTRY* pEntries; // 消息映射项的指针
};