|
VC初学者入门系列之二:消息循环
作者:jxhnuaa(铁凌)
适用读者:VC初学者并有C 基础。 逆风编程精品
VC初学者入门系列之一:窗口类的诞生
一、传统SDK程序的消息循环
在传统的SDK程序中,消息循环是很简单的,也许你不信,那我们就看看下面这段代码吧:
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("HelloWin") ;
WNDCLAS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.lpszClassName = szAppName ;
RegisterClass (&wndclass);
hwnd = CreateWindow( szAppName,……,NULL);
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
………
case WM_PAINT:
………
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
在WinMain 中 CreateWindow通过一个参数将创建的窗口和窗口类(见"窗口类的诞生"一文)联系起来,这样该窗口的所有消息都将发送到该窗口类的窗口函数WndProc,其后WndProc根据不同的消息给予不同的动作。
二、MFC期望的消息循环
在传统的SDK程序中消息循环是非常简单的,并且将窗口和窗口函数绑定在一起。而在MFC中就出现了问题,比如CDocument类,不是窗口,所以没有窗口类,但是我也想让它响应消息,怎办?问题不仅仅如此,我们再看看MFC的消息,就会发现更多问题。
MFC将消息分为三大类:1.标准消息,即除WM_COMMAND之外的任何WM_开头的消息,任何派生自CWnd的类都可以接受该消息,并按照继承关系接受(如从CScrollView到CView再到CWnd)。2.命令消息,即WM_COMMAND,任何派生自CCmdTarget的类,兼可接受该消息,接受顺序如下图所示,其中标号标注了接受消息的顺序,箭头代表调用顺序
:

图1 消息的拐弯流动
3.Control Notification,通知类消息,也以WM_COMMAND形式出现,由控件产生,通知其父窗口。
三、消息宏背后的秘密
知道了MFC消息流动的要求,那MFC是怎样实现的呢?当一个消息出现时,Application FrameWork怎么知道将该消息发送给哪个对象的呢?其实都是CCmdTarget类在作怪,所有能够接受消息的类都必须继承于CCmdTarget类,因为这些类都一个共同的特征:含有DECLARE_MESSAGE_MAP、BEGIN_MESSAGE_MAP、END_MESSAGE_MAP三个宏。啊!就这三个宏组织了一张庞大的消息映射网,也许你不信,那我们就看看这三个宏是怎样定义的:
#define DECLARE_MESSAGE_MAP()\
private:\
static const AFX_MSGMAP_ENTRY _messageEntries[];\
protected:
static AFX_DATA const AFX_MSGMAP messageMap;\
virtual const AFX_MSGMAP* GetMessageMap() const;\
#define BEGIN_MESSAGE_MAP(theClass, baseClass)\
const AFX_MSGMAP* theClass::GetMessageMap() const\
{return &theClass::messageMap;}\
AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \
{&baseClass::messageMap, &theClass::_messageEntries[0]};\
const AFX_MSGMAP_ENTRY theClass::_messageEntries[]=\
{\
#define END_MESSAGE_MAP()\
{0,0,0,0,AfxSig_end,(AFX_pMSG)0}\
};\
typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);
struct AFX_MSGMAP_ENTRY
{
UINT nMessage;
UINT nCode;
UINT nID;
UINT nLastID;
UINT nSig;
AFX_PMSG pfn;
};
struct AFX_MSGMAP
{
const AFX_MSGMAP* pBaseMap;
const AFX_MSGMAP_ENTRY* lpEntries;
};
本文章更多内容:1 - 2 - 3 - 4 - 下一页>> |