当前位置:文档之家› 消息映射的实现

消息映射的实现

消息映射的实现
消息映射的实现

消息映射的实现

1.Windows消息概述

Windows 应用程序的输入由Windows系统以消息的形式发送给应用程序的窗口。这些窗口通过窗口过程来接收和处理消息,然后把控制返还给Windows。

1.消息的分类

1.队列消息和非队列消息

从消息的发送途径上看,消息分两种:队列消息和非队列消息。队列消息送到系统消息队列,然后到线程消息队

列;非队列消息直接送给目的窗口过程。

这里,对消息队列阐述如下:

Windows 维护一个系统消息队列(System message queue),每个GUI线程有一个线程消息队列(Thread message queue)。

鼠 标、键盘事件由鼠标或键盘驱动程序转换成输入消息并把消息放进系统消息队列,例如WM_MOUSEMOVE、WM_LBUTTONUP、WM_KEYDOWN、WM_CHAR等等。Windows每次从系统消息队列移走一个消息,确定它是送给哪个窗口的和这个窗口是由哪个线程创建的,然后,把它放进窗口创建线程的线程消息队列。线程消息队列接收送给该线程所创建窗口的消息。线程从消息队列取出消息,通过Windows把它送给适当的窗口过程来处理。

除了键盘、鼠标消息以外,队列消息还有 WM_PAINT、WM_TIMER和WM_QUIT。

这些队列消息以外的绝大多数消息是非队列消息。

2.系统消息和应用程序消息

从消息的来源来看,可以分为:系统定义的消息和应用程序定义的消息。

系统消息ID的范围是从0到WM_USER-1,或0X80000到0XBFFFF;应用程序消息从WM_USER(0X0400)到0X7FFF,或0XC000到

0XFFFF;WM_USER到0X7FFF范围的消息由应用程序自己使用;0XC000到0XFFFF范围的消息用来和其他应用程序通信,为了ID 的唯一性,使用::RegisterWindowMessage来得到该范围的消息ID。

1.消息结构和消息处理

1.消息的结构

为了从消息队列获取消息信息,需要使用MSG结构。例如,::GetMessage函数(从消息队列得到消息并从队列中移走)和::PeekMessage函数(从消息队列得到消息但是可以不移走)都使用了该结构来保存获得的消息信息。

MSG 结构的定义如下:

typedef struct tagMSG { // msg

HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM lParam;

DWORD time;

POINT pt;

} MSG;

该结构包括了六个成员,用来描述消息的有关属性:

接收消息的窗口句柄、消息标识( ID)、第一个消息参数、第二个消息参数、消息产生的时间、消息产生时鼠标的位置。

2.应用程序通过窗口过程来处理消息

如前所述,每个“窗口类”都要登记一个如下形式的窗口过程:

LRESULT CALLBACK MainWndProc (

HWND hwnd,// 窗口句柄

UINT msg,// 消息标识

WPARAM wParam,// 消息参数1

LPARAM lParam// 消息参数2

)

应用程序通过窗口过程来处理消息:非队列消息由 Windows直接送给目的窗口的窗口过程,队列消息由::DispatchMessage等派发给目的窗口的窗口过程。窗口过程被调用时,接受四个参数:

a window handle (窗口句柄);

a message identifier (消息标识);

two 32-bit values called message parameters (两个32位的消息参数);

需要的话,窗口过程用 ::GetMessageTime获取消息产生的时间,用::GetMessagePos获取消息产生时鼠标光标所在的位置。

在窗口过程里,用 switch/case分支处理语句来识别和处理消息。

3.应用程序通过消息循环来获得对消息的处理

每个GDI应用程序在主窗口创建之后,都会进入消息循环,接受用户输入、解释和处理消息。

消息循环的结构如下:

while (GetMessage(&msg, (HWND) NULL, 0, 0)) {// 从消息队列得到消息

if (hwndDlgModeless == (HWND) NULL ||

!IsDialogMessage(hwndDlgModeless, &msg) &&

!TranslateAccelerator(hwndMain, haccel, &msg)) {

TranslateMessage(&msg);

DispatchMessage(&msg); // 发送消息

}

}

消息循环从消息队列中得到消息,如果不是快捷键消息或者对话框消息,就进行消息转换和派发,让目的窗口的窗口过程来处理。

当得到消息 WM_QUIT,或者::GetMessage出错时,退出消息循环。

4.MFC消息处理

使用MFC框架编程时,消息发送和处理的本质也如上所述。但是,有一点需要强调的是,所有的MFC窗口都使用同一窗口过程,程序员不必去设计和实现自己的窗口过程,而是通过MFC提供的一套消息映射机制来处理消息。因此,MFC简化了程序员编程时处理消息的复杂性。

所谓消息映射,简单地讲,就是让程序员指定要某个MFC类(有消息处理能力的类)处理某个消息。MFC提供了工具ClassWizard来帮助实现消息映射,在处理消息的类中添加一些有关消息映射的内容和处理消息的成员函数。程序员将完成消息处理函数,实现所希望的消息处理能力。

如果派生类要覆盖基类的消息处理函数,就用ClassWizard在派生类中添加一个消息映射条目,用同样的原型定义一个函数,然后实现该函数。这个函数覆盖派生类的任何基类的同名处理函数。

下面几节将分析MFC的消息机制的实现原理和消息处理的过程。为此,首先要分析ClassWizard实现消息映射的内幕,然后讨论MFC的窗口过程,分析MFC窗口过程是如何实现消息处理的。

1.消息映射的定义和实现

1.MFC处理的三类消息

根据处理函数和处理过程的不同, MFC主要处理三类消息:

●Windows 消息,前缀以“WM_”打头,WM_COMMAND例外。Windows消息直接送给MFC窗口过程处理,窗口过程调用对应

的消息处理函数。一般,由窗口对象来处理这类消息,也就是说,这类消息处理函数一般是MFC窗口类的成员函数。

●控制通知消息,是控制子窗口送给父窗口的 WM_COMMAND通知消息。窗口过程调用对应的消息处理函数。一般,由窗

口对象来处理这类消息,也就是说,这类消息处理函数一般是MFC窗口类的成员函数。

需要指出的是,Win32使用新的WM_NOFITY来处理复杂的通知消息。WM_COMMAND类型的通知消息仅仅能传递一个控制窗口句柄(lparam)、控制窗ID和通知代码(wparam)。WM_NOTIFY能传递任意复杂的信息。

●命令消息,这是来自菜单、工具条按钮、加速键等用户接口对象的WM_COMMAND通知消息,属于应用程序自己定义的

消息。通过消息映射机制,MFC框架把命令按一定的路径分发给多种类型的对象(具备消息处理能力)处理,如文档、窗口、应用程序、文档模板等对象。能处理消息映射的类必须从CCmdTarget类派生。

在讨论了消息的分类之后,应该是讨论各类消息如何处理的时候了。但是,要知道怎么处理消息,首先要知道如何映射消息。

1.MFC消息映射的实现方法

MFC 使用ClassWizard帮助实现消息映射,它在源码中添加一些消息映射的内容,并声明和实现消息

处理函数。现在来分析这些被添加的内容。

在类的定义(头文件)里,它增加了消息处理函数声明,并添加一行声明消息映射的宏

DECLARE_MESSAGE_MAP。

在类的实现(实现文件)里,实现消息处理函数,并使用 IMPLEMENT_MESSAGE_MAP宏实现消息映射。

一般情况下,这些声明和实现是由MFC的ClassWizard自动来维护的。看一个例子:

在 AppWizard产生的应用程序类的源码中,应用程序类的定义(头文件)包含了类似如下的代码:

//{{AFX_MSG(CTttApp)

afx_msg void OnAppAbout();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

应用程序类的实现文件中包含了类似如下的代码:

BEGIN_MESSAGE_MAP(CTApp, CWinApp)

//{{AFX_MSG_MAP(CTttApp)

ON_COMMAND(ID_APP_ABOUT, OnAppAbout)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

头文件里是消息映射和消息处理函数的声明,实现文件里是消息映射的实现和消息处理函数的实现。

它表示让应用程序对象处理命令消息 ID_APP_ABOUT,消息处理函数是OnAppAbout。

为什么这样做之后就完成了一个消息映射?这些声明和实现到底作了些什么呢?接着,将讨论这些问

题。

2.在声明与实现的内部

1.DECLARE_MESSAGE_MAP宏:

首先,看DECLARE_MESSAGE_MAP宏的内容:

#ifdef _AFXDLL

#define DECLARE_MESSAGE_MAP() \

private: \

static const AFX_MSGMAP_ENTRY _messageEntries[]; \

protected: \

static AFX_DATA const AFX_MSGMAP messageMap; \

static const AFX_MSGMAP* PASCAL _GetBaseMessageMap(); \

virtual const AFX_MSGMAP* GetMessageMap() const; \

#else

#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; \

#endif

DECLARE_MESSAGE_MAP 定义了两个版本,分别用于静态或者动态链接到MFC DLL的情形。

2.BEGIN_MESSAE_MAP宏

然后,看BEGIN_MESSAE_MAP宏的内容:

#ifdef _AFXDLL

#define BEGIN_MESSAGE_MAP(theClass, baseClass) \

const AFX_MSGMAP* PASCAL theClass::_GetBaseMessageMap() \

{ return &baseClass::messageMap; } \

const AFX_MSGMAP* theClass::GetMessageMap() const \

{ return &theClass::messageMap; } \

AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \

{ &theClass::_GetBaseMessageMap, &theClass::_messageEntries[0] }; \

const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \

{ \

#else

#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[] = \

{ \

#endif

#define END_MESSAGE_MAP() \

{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \

}; \

对应地, BEGIN_MESSAGE_MAP定义了两个版本,分别用于静态或者动态链接到MFC DLL的情形。END_MESSAGE_MAP相对简单,就只有一种定义。

3.ON_COMMAND宏

最后,看ON_COMMAND宏的内容:

#define ON_COMMAND(id, memberFxn) \

{\

WM_COMMAND,\

CN_COMMAND,\

(WORD)id,\

(WORD)id,\

AfxSig_vv,\

(AFX_PMSG)memberFxn\

};

1.消息映射声明的解释

在清楚了有关宏的定义之后,现在来分析它们的作用和功能。

消息映射声明的实质是给所在类添加几个静态成员变量和静态或虚拟函数,当然它们是与消息映射相关的变量和函数。

1.成员变量

有两个成员变量被添加,第一个是 _messageEntries,第二个是messageMap。

第一个成员变量的声明:

AFX_MSGMAP_ENTRY _messageEntries[]

这是一个 AFX_MSGMAP_ENTRY类型的数组变量,是一个静态成员变量,用来容纳类的消息映射条目。一个消息映射条目可以用AFX_MSGMAP_ENTRY结构来描述。

AFX_MSGMAP_ENTRY 结构的定义如下:

struct AFX_MSGMAP_ENTRY

{

//Windows 消息ID

UINT nMessage;

// 控制消息的通知码

UINT nCode;

//Windows Control 的ID

UINT nID;

// 如果是一定范围的消息被映射,则nLastID指定其范围

UINT nLastID;

UINT nSig;// 消息的动作标识

// 响应消息时应执行的函数(routine to call (or special value))

AFX_PMSG pfn;

};

从上述结构可以看出,每条映射有两部分的内容:第一部分是关于消息 ID的,包括前四个域;第二部分是关于消息对应的执行函数,包括后两个域。

在上述结构的六个域中,pfn是一个指向CCmdTarger成员函数的指针。函数指针的类型定义如下:

typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);

当使用一条或者多条消息映射条目初始化消息映射数组时,各种不同类型的消息函数都被转换成这样的类型:不接收参数,也不返回参数的类型。因为所有可以有消息映射的类都是从 CCmdTarge派生的,所以可以实现这样的转换。

nSig 是一个标识变量,用来标识不同原型的消息处理函数,每一个不同原型的消息处理函数对应一个不同的nSig。在消息分发时,MFC内部根据nSig把消息派发给对应的成员函数处理,实际上,就是根据nSig的值把pfn还原成相应类型的消息处理函数并执行它。

●第二个成员变量的声明

AFX_MSGMAP messageMap;

这是一个 AFX_MSGMAP类型的静态成员变量,从其类型名称和变量名称可以猜出,它是一个包含了消息映射信息的变量。的确,它把消息映射的信息(消息映射数组)和相关函数打包在一起,也就是说,得到了一个消息处理类的该变量,就得到了它全部的消息映射数据和功能。AFX_MSGMAP结构的定义如下:

struct AFX_MSGMAP

{

// 得到基类的消息映射入口地址的数据或者函数

#ifdef _AFXDLL

//pfnGetBaseMap 指向_GetBaseMessageMap函数

const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();

#else

//pBaseMap 保存基类消息映射入口_messageEntries的地址

const AFX_MSGMAP* pBaseMap;

#endif

//lpEntries 保存消息映射入口_messageEntries的地址

const AFX_MSGMAP_ENTRY* lpEntries;

};

从上面的定义可以看出,通过 messageMap可以得到类的消息映射数组_messageEntries和函数_GetBaseMessageMap的地址(不使用MFC DLL时,是基类消息映射数组的地址)。

1.成员函数

●_GetBaseMessageMap()

用来得到基类消息映射的函数。

GetMessageMap()

用来得到自身消息映射的函数。

1.消息映射实现的解释

消息映射实现的实质是初始化声明中定义的静态成员函数 _messageEntries和messageMap,实现所声明的静态或虚拟函数GetMessageMap、_GetBaseMessageMap。

这样,在进入 WinMain函数之前,每个可以响应消息的MFC类都生成了一个消息映射表,程序运行时通过查询该表判断是否需要响应某条消息。

1.对消息映射入口表 (消息映射数组)的初始化

如前所述,消息映射数组的元素是消息映射条目,条目的格式符合结构 AFX_MESSAGE_ENTRY的描述。所以,要初始化消息映射数组,就必须使用符合该格式的数据来填充:如果指定当前类处理某个消息,则把和该消息有关的信息(四个)和消息处理函数的地址及原型组合成为一个消息映射条目,加入到消息映射数组中。

显然,这是一个繁琐的工作。为了简化操作, MFC根据消息的不同和消息处理方式的不同,把消息映射划分成若干类别,每一类的消息映射至少有一个共性:消息处理函数的原型相同。对每一类消息映射,MFC定义了一个宏来简化初始化消息数组的工作。例如,前文提到的ON_COMMAND宏用来映射命令消息,只要指定命令ID和消息处理函数即可,因为对这类命令消息映射条目,其他四个属性都是固定的。ON_COMMAND宏的初始化内容如下:

{ WM_COMMAND,

CN_COMMAND,

(WORD)ID_APP_ABOUT,

(WORD)ID_APP_ABOUT,

AfxSig_vv,

(AFX_PMSG)OnAppAbout

}

这个消息映射条目的含义是:消息 ID是ID_APP_ABOUT,OnAppAbout被转换成AFX_PMSG指针类型,AfxSig_vv是MFC预定义的枚举变量,用来标识OnAppAbout的函数类型为参数空(Void)、返回空(Void)。

在消息映射数组的最后,是宏 END_MESSAGE_MAP的内容,它标识消息处理类的消息映射条目的终止。

2.对 messageMap的初始化

如前所述, messageMap的类型是AFX_MESSMAP。

经过初始化,域 lpEntries保存了消息映射数组_messageEntries的地址;如果动态链接到MFC DLL,则pfnGetBaseMap保存了_GetBaseMessageMap成员函数的地址;否则pBaseMap保存了基类的消息映射数组的地址。

3.对函数的实现

_GetBaseMessageMap()

它返回基类的成员变量 messagMap(当使用MFC DLL时),使用该函数得到基类消息映射入口表。

GetMessageMap() :

它返回成员变量 messageMap,使用该函数得到自身消息映射入口表。

顺便说一下,消息映射类的基类 CCmdTarget也实现了上述和消息映射相关的函数,不过,它的消息映射数组是空的。

既然消息映射宏方便了消息映射的实现,那么有必要详细的讨论消息映射宏。下一节,介绍消息映射宏的分类、用法和用途。

1.消息映射宏的种类

为了简化程序员的工作, MFC定义了一系列的消息映射宏和像AfxSig_vv这样的枚举变量,以及标准消息处理函数,并且具体地实现这些函数。这里主要讨论消息映射宏,常用的分为以下几类。

1.用于 Windows消息的宏,前缀为“ON_WM_”。

这样的宏不带参数,因为它对应的消息和消息处理函数的函数名称、函数原型是确定的。 MFC提供了这类消息处理函数的定义和缺省实现。每个这样的宏处理不同的Windows消息。

例如:宏 ON_WM_CREATE()把消息WM_CREATE映射到OnCreate函数,消息映射条目的第一个成员nMessage指定为要处理的Windows消息的ID,第二个成员nCode指定为0。

2.用于命令消息的宏 ON_COMMAND

这类宏带有参数,需要通过参数指定命令 ID和消息处理函数。这些消息都映射到WM_COMMAND上,也就是将消息映射条目的第一个成员nMessage指定为WM_COMMAND,第二个成员nCode指定为CN_COMMAND(即0)。消息处理函数的原型是void (void),不带参数,不返回值。

除了单条命令消息的映射,还有把一定范围的命令消息映射到一个消息处理函数的映射宏 ON_COMMAND_RANGE。这类宏带有参数,需要指定命令ID的范围和消息处理函数。这些消息都映射到WM_COMMAND上,也就是将消息映射条目的第一个成员nMessage指定为WM_COMMAND,第二个成员nCode指定为CN_COMMAND(即0),第三个成员nID和第四个成员nLastID指定了映射消息的起止范围。消息处理函数的原型是void (UINT),有一个UINT类型的参数,表示要处理的命令消息ID,不返回值。

( 3)用于控制通知消息的宏

这类宏可能带有三个参数,如 ON_CONTROL,就需要指定控制窗口ID,通知码和消息处理函数;也可能带有两个参数,如具体处理特定通知消息的宏ON_BN_CLICKED、ON_LBN_DBLCLK、ON_CBN_EDITCHANGE等,需要指定控制窗口ID和消息处理函数。 控制通知消息也被映射到 WM_COMMAND上,也就是将消息映射条目的第一个成员的nMessage指定为WM_COMMAND,但是第二个成员nCode是特定的通知码,第三个成员nID是控制子窗口的ID,第四个成员nLastID等于第三个成员的值。消息处理函数的原型是void (void),没有参数,不返回值。

还有一类宏处理通知消息 ON_NOTIFY,它类似于ON_CONTROL,但是控制通知消息被映射到WM_NOTIFY。消息映射条目的第一个成员的nMessage被指定为WM_NOTIFY,第二个成员nCode是特定的通知码,第三个成员nID是控制子窗口的ID,第四个成员nLastID等于第三个成员的值。消息处理函数的原型是void (NMHDR*, LRESULT*),参数1是NMHDR指针,参数2是LRESULT指针,用于返回结果,但函数不返回值。

对应地,还有把一定范围的控制子窗口的某个通知消息映射到一个消息处理函数的映射宏,这类宏包括 ON__CONTROL_RANGE 和ON_NOTIFY_RANGE。这类宏带有参数,需要指定控制子窗口ID的范围和通知消息,以及消息处理函数。

对于 ON__CONTROL_RANGE,是将消息映射条目的第一个成员的nMessage指定为WM_COMMAND,但是第二个成员nCode是特定的通知码,第三个成员nID和第四个成员nLastID等于指定了控制窗口ID的范围。消息处理函数的原型是void (UINT),参数表示要处理的通知消息是哪个ID的控制子窗口发送的,函数不返回值。

对于 ON__NOTIFY_RANGE,消息映射条目的第一个成员的nMessage被指定为WM_NOTIFY,第二个成员nCode是特定的通知码,第三个成员nID和第四个成员nLastID指定了控制窗口ID的范围。消息处理函数的原型是void (UINT, NMHDR*, LRESULT*),参数1表示要处理的通知消息是哪个ID的控制子窗口发送的,参数2是NMHDR指针,参数3是LRESULT指针,用于返回结果,但函数不返回值。

( 4)用于用户界面接口状态更新的ON_UPDATE_COMMAND_UI宏

这类宏被映射到消息 WM_COMMND上,带有两个参数,需要指定用户接口对象ID和消息处理函数。消息映射条目的第一个成员nMessage被指定为WM_COMMAND,第二个成员nCode被指定为-1,第三个成员nID和第四个成员nLastID都指定为用户接口对象ID。消息处理函数的原型是 void (CCmdUI*),参数指向一个CCmdUI对象,不返回值。

对应地,有更新一定 ID范围的用户接口对象的宏ON_UPDATE_COMMAND_UI_RANGE,此宏带有三个参数,用于指定用户接口对象ID的范围和消息处理函数。消息映射条目的第一个成员nMessage被指定为WM_COMMAND,第二个成员nCode被指定为-1,第三个成员nID和第四个成员nLastID用于指定用户接口对象ID的范围。消息处理函数的原型是 void (CCmdUI*),参数指向一个CCmdUI对象,函数不返回值。之所以不用当前用户接口对象ID作为参数,是因为CCmdUI对象包含了有关信息。

( 5)用于其他消息的宏

例如用于用户定义消息的 ON_MESSAGE。这类宏带有参数,需要指定消息ID和消息处理函数。消息映射条目的第一个成员nMessage被指定为消息ID,第二个成员nCode被指定为0,第三个成员nID和第四个成员也是0。消息处理的原型是LRESULT (WPARAM, LPARAM),参数1和参数2是消息参数wParam和lParam,返回LRESULT类型的值。

( 6)扩展消息映射宏

很多普通消息映射宏都有对应的扩展消息映射宏,例如: ON_COMMAND对应的ON_COMMAND_EX,ON_ONTIFY对应的ON_ONTIFY_EX,等等。扩展宏除了具有普通宏的功能,还有特别的用途。关于扩展宏的具体讨论和分析,见4.4.3.2节。

作为一个总结,下表列出了这些常用的消息映射宏。

表 4-1 常用的消息映射宏

消息映射宏 用途

ON_COMMAND 把 command message映射到相应的函数

ON_CONTROL 把 control notification message映射到相应的函

数。MFC根据不同的控制消息,在此基础上定义了更

具体的宏,这样用户在使用时就不需要指定通知代

码ID,如ON_BN_CLICKED。

小峰电脑书库

实验三 MFC 消息映射编程实验

实验三MFC 消息映射编程实验 一、实验目的 (1) 熟悉Visual Studio 开发环境; (2) 掌握消息映射机制的基本原理和手工添加消息映射的方法; (3) 熟练掌握在Visual Studio 开发环境调试程序的方法。 二、实验内容 设计MFC 应用程序,手工添加消息映射,实现下面的功能: (1) 按下CTRL 键,拖动鼠标绘制矩形; (2) 按下SHIFT 键,拖动鼠标绘制椭圆。 三、实验结果 (1)总结手工添加消息映射的基本步骤; 1、在BEGIN_MESSAGE_MAP 和END_MESSAGE_MAP 之间添加消息映射宏; BEGIN_MESSAGE_MAP(CDemoView, CView) ON_MESSAGE(WM_KEYDOWN, OnKeyDown) ON_COMMAND(ID_OPER_TEST, OnOperTest) END_MESSAGE_MAP( ) 2 、在类声明中声明成员函数; 3、在类的实现部分实现成员函数。列出鼠标绘图功能的实现代码; (2)列出鼠标绘图功能的实现代码; 头文件: #include "afxwin.h" class CDemoWnd:public CFrameWnd { public: CDemoWnd(); ~CDemoWnd(); public: LRESULT OnPaint(WPARAM wParam,LPARAM lParam); LRESULT OnLButtonDown(WPARAM wParam,LPARAM lParam); LRESULT OnMouseMove(WPARAM wParam,LPARAM lParam); DECLARE_MESSAGE_MAP() public: int m_nX0; int m_nY0; int m_nX1;

消息映射编程实验

MFC 消息映射编程实验 实 验 报 告 姓名:杨培培 班级:电气12级3班 12053307

【预备知识】 1、消息映射 消息映射本质上就是一个数组,MFC 使用消息映射建立消息和类的成员函数的对应关系。消息映射数组中存储的信息 (1) 所处理的消息; (2) 消息应用的控件ID,或者ID 范围; (3) 消息所传递的参数; (4) 消息所期望的返回值。 2、消息映射宏 下面介绍常用的两个消息映射宏: (1)ON_MESSAGE:处理任意消息 语法规则: ON_MESSAGE(ID,func) LRESULT func(WPARAM wParam, LPARAM lParam); 举例:映射鼠标左键按下消息 ON_MESSAGE(WM_LBUTTONDOWN, OnLButtonDown) LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam); (2)ON_COMMAND:处理WM_COMMAND 消息 语法规则: ON_COMMAND(ID,func) void func( ); 举例:映射菜单项命令消息

ON_COMMAND(ID_OPER_TEST, OnOperTest) void OnOperTest ( ); 3、消息映射步骤 MFC 中手工添加消息映射按照如下步骤进行: (1)在BEGIN_MESSAGE_MAP 和END_MESSAGE_MAP 之间添加消息映射 宏; BEGIN_MESSAGE_MAP(CDemoView, CView) ON_MESSAGE(WM_KEYDOWN, OnKeyDown) ON_COMMAND(ID_OPER_TEST, OnOperTest) END_MESSAGE_MAP( ) (2) 在类声明中声明成员函数; (3) 在类的实现部分实现成员函数。 【实验目的】 (1) 熟悉Visual Studio 开发环境; (2) 掌握消息映射机制的基本原理和手工添加消息映射的方法; (3) 熟练掌握在Visual Studio 开发环境调试程序的方法。【实验内容】 设计 MFC 应用程序,手工添加消息映射,实现下面的功能: (1) 按下CTRL 键,拖动鼠标绘制矩形; (2) 按下SHIFT 键,拖动鼠标绘制椭圆。 【实验报告】 (1) 总结手工添加消息映射的基本步骤;

中国地质大学(北京)继续教育学院--Windows程序设计模拟题

《Windows程序设计》模拟题 一.单项选择题 1、项目文件的扩展名是【1】。 A)exe B)dsp C)dsw D)cpp 2、利用ClassWizard不能【2】。 A)建立新类B)进行消息映射 C)增加类的成员变量D)插入资源 3、下列【3】不是MFC消息映射机制有关的宏。 A)DECLARE_MESSAGE_MAP B)BEGIN_MESSAGE_MAP C)DECLARE_SERIAL D)END_MESSAGE_MAP 4、要使鼠标箭头在按钮上暂停时能显示工具栏按钮提示,必须设置工具栏的风格为【4】。 A)CBRS_TOOLTIPS B)CBRS_FLYBY C)CBRS_NOALIGN D)WS_VISIBLE 5、下面【5】不是GDI对象。 A)CFont B)CPalette C)CClientDC D)CBitmap 6、要将模式对话框在屏幕上显示需要用到【6】。 A)Create B)DoModal C)OnOK D)构造函数 7、类CButton不是下列【7】控件对应的类。 A)命令按钮B)单选按钮 C)复选框D)静态文本框 8、根据对话框的行为性质,对话框可以分为两类【8】 A)对话框资源和对话框类B)模式对话框和非模式对话框 C)对话框资源和对话框模板D)消息对话框和模式对话框 9、所有的控件都是【9】类的派生类,都可以作为一个特殊的窗口来处理。 A)CView B)CWnd C)CWindow D)CDialog 10、使用GetDC()获取的设备上下文在退出时,必须调用【10】释放设备上下文。 A)ReleaseDC() B)delete C)DeleteDC() D)Detach() 11、希望菜单无效,应该用CCmdUI类的【11】成员函数。 A)Enable B)SetRadio C)SetCheck D)SetText 12、当滑块滑动时,滑块条控件将发送滚动消息来通知父窗口,水平滑动条发送【12】消息。

cos dscp映射机制

https://www.doczj.com/doc/948107012.html,/hlz_2599/blog/static/142378474201151265035648/?suggestedreading&wumii CoS & DSCP 映射机制 对于CoS和DSCP,只是分类的标准,可以自己设置信任哪个。而且CoS和DSCP 之间有映射,只是标识了包的优先级的不同,根据包的优先级选择不同的出队列,不同出队列所占的带宽资源,拥塞时丢弃比例不同。从而实现服务质量的目标。QoS的实现以IETF 的DiffServ 体系为基础。DiffServ体系规定每一个传输报文将在网络中被分类到不同的类别,分类信息被包含在了IP 报文头中,DiffServ 体系使用了IP 报文头中的TOS(Type Of Service)中的前6 个比特来携带报文的分类信息。当然分类信息也可以被携带在链路层报文头上。一般地,附带在报文中的分类信息有: 1 帧头的Tag Control Information 中的前3 个比特,它包含了8 个类别的优先级信息,通常称这三个比特为为User Priority bits。 2 报文头中的TOS 字段前 3 个比特,称作IP precedence value;或者携带在IP 报文头中的TOS 字段前6 个比特,称作Differentiated Services Code Point (DSCP) value。 在遵循DiffServ 体系的网络中,各交换机和路由器对包含同样分类信息的报文采取同样的传输服务策略,对包含不同分类信息的报文采取不同的传输服务策略。报文的分类信息可以被网络上的主机、交换机、路由器或者其它网络设备赋予。可以基于不同的应用策略或者基于报文内容的不同为报文赋予类别信息。识别报文的内容以便为报文赋予类别信息的做法往往需要消耗网络设备的大量处理资源,为了减少骨干网络的处理开销,一般这种赋予类别信息的方式都使用在网络边界。 交换机或路由器根据报文所携带的类别信息,可以为各种交通流提供不同的传输优先级,或者为某种交通流预留带宽,或者适当的丢弃一些重要性较低的报文、或者采取其他一些操作等等。这些独立设备的这种行为在DiffServ 体系中被称作每跳行为(per-hop behavior)。如果网络上的所有设备提供了一致的每跳行为,那么对于DiffServ 体系来说,这个网络就可以构成end-to-end QoS solution。 下面几个段落将详细介绍本交换机所提供的以DiffServ 体系为基础的QoS 模型。 QoS入口端动作包括Classifying、Policing 和Marking。 Classifying:确保将网络交通流划分成以DSCP值来标识的各个数据流。随后交换机将根据DSCP值来对各个数据流实施不同的QoS策略。有关分类的更详细介绍,请参阅Classifying章节。

MFC的运行机制和消息响应机制

MFC的类层次结构与运行机制 MFC的类层次结构 如图所示(子类指向父类): 其中: CObject:是MFC提供的绝大多数类的基类。该类完成动态空间的分配与回收,支持一般的诊断、出错信息处理和文档序列化等。 CCmdTarget:主要负责将系统事件(消息)和窗口事件(消息)发送给响应这些事件的对象,完成消息发送、等待和派遣调度等工作,实现应用程序的对象之间的协调运行。 CWinApp:是应用程序的主线程类,它是从CWinThread类派生而来的。CWinThread类用来完成对线程的控制,包括线程的创建、运行、终止和挂起等。 CDocument:是文档类,包含了应用程序在运行期间所用到的数据。 CWnd:是一个通用的窗口类,用来提供Windows中的所有通用特性、对话框和控件。 CFrameWnd是从CWnd类继承来的,并实现了标准的框架应用程序。 CDialog类用来控制对话框窗口。 CView:用于让用户通过窗口来访问文档。 CMDIFrameWnd和CMDIChildWnd:分别用于多文档应用程序的主框架窗口和文档子窗口的显示和管理。CMiniFrameWnd类是一种简化的框架窗口,它没有最大化和最小化窗口按钮,也没有窗口系统菜单,一般很少用到它。 MFC运行机制 在程序中,当定义一个类对象时,它会自动调用相应的构造函数。所谓"类对象",就是用该类定义的"变量",这个"变量"又称为类的一个实例。例如,theApp就是类CSimpApp的一个对象。 MFC正是利用类的这种"自动调用相应的构造函数"特性,使得WinMain()函数的调用变成了应用程序框架内部的调用,所以我们在代码中看不到每个Windows程序所必须有的WinMain()函数。 当应用程序运行到"CSimpApp theApp;"时,系统就会先调用基类CWinApp构造函数,进行一系列的内部初始化操作,然后自动调用CSimpApp的虚函数InitInstance(),该函数会进一步调用相应的函数来完成主窗口的构造和显示工作。下面来看看上述程序中InitInstance的执行过程。 首先执行的是: m_pMainWnd = new CMainFrame; 该语句用来创建从CFrameWnd类派生而来的用户框架窗口CMainFrame类对象,继而调用该类的构造函数,使得Create函数被调用,完成了窗口创建工作。

MFC消息映射机制

由于工作需要,这几天学了一点MFC,在AFX里看到很多熟悉的东西,如类型信息,序列化,窗口封装和消息分派。几乎每个界面库都必须提供这些基础服务,但提供的手法却千差万别。MFC大量地借用了宏,映射表来实现,而VCL则更多的在语言级别上给与支持。这其实是很容易理解的,因为C++是一个标准,不会因某个应用而随便扩展语言;相反Delphi完全由一个公司掌握,因此每支持一项新技术,变化最大的往往是语言本身。 学习MFC的代码,再对照VCL的实现,这真是一个很有意思的过程,其中可以看到两个框架在一些设计思想上是殊途同归的,所不同的是表现手法,以及封装的程度。我计划将这段时间阅读MFC的心得写成一系列文章,其中可能会穿插与VCL的对比,不管你熟悉VCL还是MFC,通过这些文章或许可从另一个角度来看待自己熟悉的框架。 这是第一篇:消息分派。 消息处理函数表 MFC和VCL在对消息进行封装的时候,都没有使用虚函数机制。原因是虚函数带来了不必要的空间开销。那么它们用什么来代替虚函数,即可减少空间浪费,也可实现类似虚函数的多态呢?让我们从一个例子开始。 假设父类ParentWnd处理了100个消息,并且将这100个处理函数声明为虚函数;此时有一个子类ChildWnd它只需要处理2个消息,另外98个交由ParentWnd默认处理,但是ChildWnd的虚表仍然占有100个函数指针,其中2个指向自己的实现,另外98个指向父类的实现,情况大概像下面这样: 指向父类实现的函数指针浪费了空间,当控件类非常多的时候,这种浪费就非常明显。因此必须走另一条路,将不必要的函数指针去掉,如下图所示:

ChildWnd去掉函数指针之后,当有一个消息需要Fun100处理时,ChildWnd就束手无策了。需要一个方法让ChildWnd能够找到父类的表,我们再对这个数据结构进行改进如下: 现在看来好多了,如果ChildWnd有一个消息需要Fun1处理,则查找ChildWnd的MsgHandlers,找到Fun1函数指针调用之;如果需要Fun100处理,发现ChildWnd的MsgHandlers没有Fun100,则通过ParentTable找到父类的MsgHandlers继续查找。如此一直查找,到最后再找不到,就调用DefWindowProc作默认处理。 MFC和VCL都是通过类似的方法实现消息分派的。只是VCL有编译器的支持,直接将这个表放到VMT中,因此实现起来非常简单,只需在控件类里作如下声明: procedure WMMButtonDown(var Message: TWMMButtonDown); message WM_MBUTTONDOWN; TObject.Dispatch会将WM_MBUTTONDOWN正确分派到WMMButtonDown。

框架基础知识

SSH基础 Struts,Spring,Hibernate框架基础 1.Hibernate工作原理及为什么要用? 原理:1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory 3.打开Session 4.创建事务Transation 5.持久化操作6.提交事务7.关闭Session 8.关闭SesstionFactory 为什么要用:1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。 4. hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。 2.Hibernate是如何延迟加载? 1. Hibernate2延迟加载实现:a)实体对象b)集合(Collection) 2. Hibernate3 提供了属性的延迟加载功能当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,他节省了服务器的内存开销,从而提高了服务器的性能。 3.Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系) 类与类之间的关系主要体现在表与表之间的关系进行操作,它们都市对对象进行操作,我们程序中把所有的表与类都映射在一起,它们通过配置文件中的many-to-one、one-to-many、many-to-many 4.Struts1流程: 1、客户端浏览器发出HTTP请求。 2、根据web.xml配置,该请求被ActionServlet接收。 3、根据struts-config.xml配置,ActionServlet先将请求中的参数填充到ActionForm中,然后ActionServlet再将请求发送到Action 进行处理。 4、是否验证,需要验证则调用ActionForm 的validate方法,验证失败则跳转到input,成功则继续。 5、Action从ActionForm获得数据,调用javabean 中的业务方法处理数据。 6、Action返回ActionForward对象,跳转到相应JSP 页面或Action。 7、返回HTTP响应到客户端浏览器。 MVC设计模式:modal:“模型”也称业务逻辑,是正真完成任务的代码,相当与JavaBeanview:视图,其实就是显示界面,相当于JSPcontroller:控制器,他控制模型和视图的交互过程,相当于servletstruts1是基于MVC设计模式hibernate是基于ORM对象关系映射 5.struts是什么? struts1是基于JSP和servlet的一个开源的Web应用框架,使用的是MVC的设计模式struts2是基于webwork技术的框架,是sun和webwork公司联手开发的一个功能非常齐全的框架,struts2和struts1没有任何关系,是一个全新的框架 6.spring是什么? spring是一个集成了许多第三方框架的大杂烩,其核心技术是IOC(控制反转,也称依赖注

MFC消息映射机制如何运用ClassWizard

M F C消息映射机制如何 运用C l a s s W i z a r d The Standardization Office was revised on the afternoon of December 13, 2020

画图的基本应用: Point的应用,在mfc中的很多的位置都要用到。只是当前点的信息,xy坐标,MoveToEx 移动位置函数The MoveToEx function updates the current position to the specified point and optionally returns the previous position. LineTo 画直线的函数 CDC类,作图相关的操作 GetDC,cwnd::getdc 以及cdc的释放(区别hdc),两者的范围不同,调用方式不同 CClientDC 不需要显示地调用getdc和releasedc,只需要声明类的定义和类的调用。 Cliendc对象里利用view指针构造,但是调用的时候用的是对象的点调用方式。 Cwnd::getparent 获得父窗口的指针,view的父窗口是frame。注意区别view 和framework的客户区域。 Cwindowdc类和clientdc一样自动调用getdc和releasedc。了解他的访问客户区的范围。 Getdesktopwindow 获得桌面窗口。 创建画笔: CPen 类,设置画笔的属性,包括一些类型宽度,颜色。 CDC::SelectObject 用的过程中要保存原来的画笔指针。 创建一个阴影线的笔只能是1或更小。(其他的注意情况看msdn)。

07837面向对象程序设计(C )自学考试课程复习题

(07837)《面向对象程序设计C++》复习题 一、单选题 1.对类成员访问权限的控制,是通过设置成员的访问控制属性实现的,下列不是访问控制属性的是(D ) A. 公有类型 B. 私有类型 C. 保护类型 D. 友元类型 2.下列关于多态性的描述,错误的是( C ) A. C++语言的多态性分为编译时的多态性和运行时的多态性 B. 编译时的多态性可通过函数重载实现 C. 运行时的多态性可通过模板和虚函数实现 D. 实现运行时多态性的机制称为动态绑定 3.在C++语言中,数据封装要解决的问题是( D ) A. 数据的规范化 B. 便于数据转换 C. 避免数据丢失 D. 防止不同模块之间数据的非法访问 4.使用private修饰的成员变量,以下说法正确的是(A ) A. 只能由本类中的函数使用,不能被外面的程序所访问。 B.可以由本类中的函数使用,也可以被外面的程序所访问。 C. 只能由本类和派生类中的函数使用。 D. 可以在主函数中使用。 5.对类的构造函数和析构函数描述正确的是(A ) A.构造函数可以重载,析构函数不能重载 B.构造函数不能重载,析构函数可以重载 C.构造函数可以重载,析构函数也可以重载 D.构造函数不能重载,析构函数也不能重载 6.下面对静态数据成员的描述中,正确的是(A ) A. 静态数据成员是类的所有对象共享的数据 B.类的每个对象都有自己的静态数据成员 C.类的不同对象有不同的静态数据成员值 D.静态数据成员不能通过类的对象调用 7.在VC++语言类体系中,不能被派生类继承的有(B ) A. 转换函数 B.构造函数 C.虚函数 D.静态成员函数 8.下面关于句柄正确的说法是(A ) A. 句柄是一个标识Windows资源和设备等对象的变量。 B. 句柄是用户程序自定义的数据类型。 C. 用户程序使用句柄时不需要定义。 D. 句柄仅仅是一个抽象的概念,程序中不能使用句柄。 9.下面关于动态链接库正确的说法是(B ) A. 动态链接库提供的函数,在编译阶段能够连接到应用程序中。 B.动态链接库提供的函数,在运行阶段能够连接到应用程序中。 C. 动态链接库本身不能单独设计、编译和调试。 D. 动态链接库的使用使得程序缺乏灵活性。 10.下面关于MFC应用程序中InitInstance函数正确的说法是(D ) A. 该函数由用户定义。 B.该函数不需要用户程序覆盖。 C. 该函数在WinMain函数内被显式调用。 D.通过应用程序类的全局指针自动调用。 11.为了在程序中显示一个模式对话框,应使用CDialgl类的成员函数(C ) A. ShowWindow() B. Create()

mfc原理和消息映射

MFC思想 win32程序中创建一个窗口的过程:设计窗口阶段(由WNDCLASS结构描述部分)、窗口的注册及创建显示过程、消息循环部分。win32用标准的C语言代码实现,是面向过程的。在MFC中采用了面向对象的思想,即用面向对象的C++思想对以上代码进行了封装,也就是说将一些对窗口进行操作的API的函数封装到了一个类中,以下我将用简短的代码来演示一下这个过程: class CWnd { public: HWND m_hWnd; BOOL Create(); BOOL ShowWindow(); }; BOOL CWnd::Create() { WNDCLASS wndClass; wndClass.style=CS_HREDRAW; wndClass.lpfnWndProc=(WNDPROC)DefWndProc; wndClass.cbClsExtra=0; wndClass.cbWndExtra=0; wndClass.hInstance=hInstance; wndClass.hIcon=LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1)); wndClass.hCursor=LoadCursor(hInstance,MAKEINTRESOURCE(IDC_CURSOR1)); LOGBRUSH lgbr; lgbr.lbStyle=BS_SOLID; lgbr.lbColor=RGB(192,192,0); lgbr.lbHatch=0; wndClass.hbrBackground=CreateBrushIndirect(&lgbr); wndClass.lpszMenuName=NULL; wndClass.lpszClassName="mycls"; RegisterClass(&wndClass); HWND hWnd; m_hWnd=CreateWindow("mycls","窗口标题", WS_OVERLAPPEDWINDOW,0,NULL,NULL,hInstance,NULL); if(m_hWnd!=NULL) return true; else return false; } BOOL CWnd::ShowWindow() { return ShowWindow(hWnd,nCmdShow); } 为了保证代码和以前的执行方式一样,Winmain()函数可以写成如下形式:

MFC消息映射

消息映射的实现 Windows消息概述 Windows应用程序的输入由Windows系统以消息的形式发送给应用程序的窗口。这些窗口通过窗口过程来接收和处理消息,然后把控制返还给Windows。 消息的分类 队列消息和非队列消息 从消息的发送途径上看,消息分两种:队列消息和非队列消息。队列消息送到系统消息队列,然后到线程消息队列;非队列消息直接送给目的窗口过程。 这里,对消息队列阐述如下: Windows维护一个系统消息队列(System message queue),每个GUI线程有一个线程消息队列(Thread message queue)。 鼠标、键盘事件由鼠标或键盘驱动程序转换成输入消息并把消息放进系统消息队列,例如 WM_MOUSEMOVE、WM_LBUTTONUP、WM_KEYDOWN、WM_CHAR等等。Windows每次从系统消息队列移走一个消息,确定它是送给哪个窗口的和这个窗口是由哪个线程创建的,然后,把它放进窗口创建线程的线程消息队列。线程消息队列接收送给该线程所创建窗口的消息。线程从消息队列取出消息,通过Windows把它送给适当的窗口过程来处理。 除了键盘、鼠标消息以外,队列消息还有WM_PAINT、WM_TIMER和WM_QUIT。 这些队列消息以外的绝大多数消息是非队列消息。 系统消息和应用程序消息 从消息的来源来看,可以分为:系统定义的消息和应用程序定义的消息。 系统消息ID的范围是从0到WM_USER-1,或0X80000到0XBFFFF;应用程序消息从WM_USER (0X0400)到0X7FFF,或0XC000到0XFFFF;WM_USER到0X7FFF范围的消息由应用程序自己使用;0XC000到0XFFFF范围的消息用来和其他应用程序通信,为了ID的唯一性,使 用::RegisterWindowMessage来得到该范围的消息ID。 消息结构和消息处理 消息的结构 为了从消息队列获取消息信息,需要使用MSG结构。例如,::GetMessage函数(从消息队列得到消息并从队列中移走)和::PeekMessage函数(从消息队列得到消息但是可以不移走)都使用了该结构来保存获得的消息信息。 MSG结构的定义如下: typedef struct tagMSG { // msg HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; } MSG; 该结构包括了六个成员,用来描述消息的有关属性: 接收消息的窗口句柄、消息标识(ID)、第一个消息参数、第二个消息参数、消息产生的时间、消息产生时鼠标的位置。 应用程序通过窗口过程来处理消息 如前所述,每个“窗口类”都要登记一个如下形式的窗口过程: LRESULT CALLBACK MainWndProc (

4.MFC消息映射机制如何运用ClassWizard

. 画图的基本应用: Point的应用,在mfc中的很多的位置都要用到。只是当前点的信息,xy坐标,MoveToEx 移动位置函数The MoveToEx function updates the current position to the specified point and optionally returns the previous position. LineTo 画直线的函数 CDC类,作图相关的操作 GetDC,cwnd::getdc 以及cdc的释放(区别hdc),两者的范围不同,调用方式不同CClientDC 不需要显示地调用getdc和releasedc,只需要声明类的定义和类的调用。Cliendc对象里利用view指针构造,但是调用的时候用的是对象的点调用方式。Cwnd::getparent 获得父窗口的指针,view的父窗口是frame。注意区别view和framework 的客户区域。 Cwindowdc类和clientdc一样自动调用getdc和releasedc。了解他的访问客户区的范围。Getdesktopwindow 获得桌面窗口。 创建画笔: CPen 类,设置画笔的属性,包括一些类型宽度,颜色。 CDC::SelectObject 用的过程中要保存原来的画笔指针。 创建一个阴影线的笔只能是1或更小。(其他的注意情况看msdn)。 创建画刷: CBrush 类的方法 FillRect填充矩形的区域。 CRect类,几种不同的方法。 用位图填充画刷。CBitmap 的构造函数,没有参数。调用之前必需初始化。 透明画刷的创建: dc.Rectangle(); 画出矩形。 空画刷:GetStockObject CBrush::FromeHandle 空画刷的实现方法: CBrush *brush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); CBrush *oldbrush=dc.SelectObject(brush); dc.Rectangle(CRect(org,point)); dc.SelectObject(oldbrush); 理解 消息响应的知识: MouseMove 如有侵权请联系告知删除,感谢你们的配合! 精品

MFC课后简答题(1~11章)

第一章 1、什么是Windows SDK程序? 使用SDK开发出来的Windows应用程序,叫做Windows SDK程序 2、什么是Windows API函数? 为了设计Windows 应用程序,Windows 提供了大量预定义的用C语言编写的函数 3、查看windows.h文件,说明Windows系统的句柄的类型。 整型 4、窗口句柄、当前程序应用实例句柄、设备环境句柄 5、什么是事件?试举例说明。 能触发程序作出相应反映的刺激叫做事件,例如在键盘上按下一个键 6、如何显示和更新窗口? 调用函数ShowWindow显示窗口,调用函数UpdateWindow更新窗口 7、什么是消息循环? 在创建了窗口的应用程序中,应用程序将要不断地从消息队列中获取消息,并将消息指派给指定的窗口处理函数来处理,然后再回来从消息队列中获取消息,这个不断重复的工作过程叫做消息循环 8、Windows应用程序的主函数有哪3个主要任务? 注册窗口类、创建应用程序的窗口和建立消息循环 (注:如果题目问有哪2个主要任务,应该答后两个) 9、说明Windows应用程序的主函数,窗口函数与Windows系统之间的关系。 主函数和窗口函数都是Windows系统调用的函数; 主函数是应用程序启动后,系统首先调用的函数; 窗口函数是主函数在消息循环中获得消息并把消息发送给系统之后,由系统调用函数。 第二章 1、在窗口类CFrameWnd中需要封装哪些成员? 窗口句柄,窗口类的定义,注册窗口类,创建窗口和显示更新窗口 (注:对应书上P16 //窗体类的声明这一段代码) 2、应用程序类CWinApp应该具备哪些主要功能? 注册、创建、显示应用程序的窗口;建立消息循环 3、在MFC程序设计中,如果要建立拥有自己的风格的主窗口,应该重写什么函数? 在CWinApp的派生类中重写InitInstance函数 4、什么是消息映射表? 在MFC中,能够根据消息取得消息处理函数的表,叫做消息映射表。(我自己概括的) ////消息映射就是消息与消息处理函数一对一的联系 第三章 1、CObject is the principal base class for the MFC Library. (最“基”的一个类) 2、功能: CObject类:为其派生类提供了支持序列化、调试信息、运行期类型消息等一些通用功能。 CCmdTArget类:支持消息处理。 CWnd类:为所有子窗口类提供通用属性和方法。

消息映射的实现

消息映射的实现 1.Windows消息概述 Windows 应用程序的输入由Windows系统以消息的形式发送给应用程序的窗口。这些窗口通过窗口过程来接收和处理消息,然后把控制返还给Windows。 1.消息的分类 1.队列消息和非队列消息 从消息的发送途径上看,消息分两种:队列消息和非队列消息。队列消息送到系统消息队列,然后到线程消息队 列;非队列消息直接送给目的窗口过程。 这里,对消息队列阐述如下: Windows 维护一个系统消息队列(System message queue),每个GUI线程有一个线程消息队列(Thread message queue)。 鼠 标、键盘事件由鼠标或键盘驱动程序转换成输入消息并把消息放进系统消息队列,例如WM_MOUSEMOVE、WM_LBUTTONUP、WM_KEYDOWN、WM_CHAR等等。Windows每次从系统消息队列移走一个消息,确定它是送给哪个窗口的和这个窗口是由哪个线程创建的,然后,把它放进窗口创建线程的线程消息队列。线程消息队列接收送给该线程所创建窗口的消息。线程从消息队列取出消息,通过Windows把它送给适当的窗口过程来处理。 除了键盘、鼠标消息以外,队列消息还有 WM_PAINT、WM_TIMER和WM_QUIT。 这些队列消息以外的绝大多数消息是非队列消息。 2.系统消息和应用程序消息 从消息的来源来看,可以分为:系统定义的消息和应用程序定义的消息。 系统消息ID的范围是从0到WM_USER-1,或0X80000到0XBFFFF;应用程序消息从WM_USER(0X0400)到0X7FFF,或0XC000到 0XFFFF;WM_USER到0X7FFF范围的消息由应用程序自己使用;0XC000到0XFFFF范围的消息用来和其他应用程序通信,为了ID 的唯一性,使用::RegisterWindowMessage来得到该范围的消息ID。 1.消息结构和消息处理 1.消息的结构 为了从消息队列获取消息信息,需要使用MSG结构。例如,::GetMessage函数(从消息队列得到消息并从队列中移走)和::PeekMessage函数(从消息队列得到消息但是可以不移走)都使用了该结构来保存获得的消息信息。 MSG 结构的定义如下: typedef struct tagMSG { // msg HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt;

MFC中的消息发送与响应

MFC中的消息发送与响应 1. 主窗口向子窗口发送消息: https://www.doczj.com/doc/948107012.html,/phenixyf/article/details/9300425 从主窗口向子窗口发送消息,可以在子窗口中添加自定义的消息,然后在主窗口中需要地方呼叫该消息。 呼叫方法: 1.将子窗口添加为主窗口的成员变量; 2.主窗口呼叫该消息,成员变量名.SendMessage(UM_PROGRESS); 子窗口添加自定义消息步骤如下: 1、定义消息。 在Windows中,所有的消息都用一个特定的整数值来表示,为了避免自定义消息与已存在的其他消息发生冲突,应该利用Windows提供的一个常量:WM_USER,小于这个常量的是系统保留的。即用户自定义的消息至少为WM_USER+1,注意最后表示的消息的数值不要超过0x7FFF。在开发Windows95应用程序时,Microsoft推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。 #define UM_PROGRESS WM_USER + 100 将上句添加到子窗口类的头文件(.h)中。 2、在子窗口类头文件的AFX_MSG块中声明消息处理函数:

class CMainFrame:public CFrameWnd{ protected: //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnTimer(UINT nIDEvent); afx_msg LRESULT OnProgress(WPARAM wParam, LPARAM lParam); //}}AFX_MSG DECLARE_MESSAGE_MAP() 3、在子窗口类的实现文件(.cpp)中,使用ON_MESSAGE宏指令将消息映射到消息处理表中。 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_WM_TIMER() ON_MESSAGE(UM_PROGRESS, OnProgress)//注意这条语句的后面没有分号 //}}AFX_MSG_MAP END_MESSAGE_MAP() 4、实现消息处理函数。该函数使用WPRAM和LPARAM参数并返回LPESULT。 LRESULT CMainFrame::OnProgress(WPARAM wParam,LPARAM lParam){ CRect rect; m_wndStatusBar.GetItemRect(2,&rect); //获得窗格区域 //创建进度栏,注意第三个参数为CWnd* pParentWnd,根据情况选择父窗体 m_progress.Create(WS_CHILD|WS_VISIBLE|PBS_VERTICAL,rect,this,123); m_progress.SetPos(50); return 0; } 5、在适当的时候发送自定义消息,进行消息处理。需要注意使用SendMessage还是PostMessage进行处理:SendMessage是消息处理完毕后再返回;而PostMessage则是把消息放到消息队列后立即返回。 SendMessage(UM_PROGRESS); PostMessage(UM_PROGRESS); 如果用户需要整个系统唯一的消息,可以调用SDK函数RegisterWindowMessage并使用ON_REGISTER_MESSAGE宏指令取代ON_MESSAGE宏指令,其余步骤同上。 2. 子窗口向主窗口发送消息:

软件体系结构复习资料

软件体系结构知识点: 第一章: 1.什么是软件体系结构 答:软件体系结构=构件+连接件+约束软件体系结构是具有一定形式的结构化元素,即构件的集合,包括处理构件、数据构件和连接构件。处理构件负责对数据进行加工,数据构件是被加工的信息,连接构件把体系结构的不同部分组组合连接起来。这一定义注重区分处理构件、数据构件和连接构件,这一方法在其他的定义和方法中基本上得到保持。 2.软件体系结构形式化方法 答:1.根据对目标软件系统进行说明的方式: (1)面向模型的方法。在这个方法中,对目标软件系统的说明是为其构造一个模型,该模型的构成成分是一些具有特性的数据抽象,如域, 元组等 (2)面向性质的方法。这种方法是直接给出目标软件系统的一组特性来描述目标软件系统。通常是目标软件系统必须满足的形式公理,其形式 化说明仅描述目标软件系统的性质,而不涉及实现方法。 2.根据表达能力的形式方法可分为以下五大类 (1)基于模型的方法 (2)代数方法 (3)过程代数方法 (4)基于逻辑的方法 (5)基于网络的方法 3.软件质量定义、软件质量模型 答:,软件质量是软件符合明确叙述的功能和性能需求、文档中明确描述的开发标准、以及所有专业开发的软件都应具有的隐含特征的程度。影响软件质量的主要因素,这些因素是从管理角度对软件质量的度量。可划分为三组,分别反应用户在使用软件产品时的三种观点。正确性、健壮性、效率、完整性、可用性、风险(产品运行);可理解性、可维修性、灵活性、可测试性(产品修改);可移植性、可再用性、互运行性(产品转移)。 第二章: 4.Kruchten 4+1模型描述软件体系结构 Kruchten 4+1模型建立在体系结构的Perry&Wolf定义和Berry Boehm定义的基础上,采用多视图模型的方法描述软件体系结构。该模型由5个视图构成,每个视图只关心系统的一个侧面,5个视图结合在一起才能反映系统的软件体系结构的全部内容。 程序员软件管理 集成者信 性能可扩展性

中国石油大学(华东)VC 实验报告实验三_MFC消息映射编程实验

实验三 MFC消息映射编程实验 一、实验目的 (1) 熟悉 Visual Studio开发环境; (2) 掌握消息映射机制的基本原理和手工添加消息映射的方法; (3) 熟练掌握在 Visual Studio开发环境调试程序的方法。 二、实验内容 设计 MFC应用程序,手工添加消息映射,实现下面的功能: (1) 按下 CTRL键,拖动鼠标绘制矩形; (2) 按下 SHIFT键,拖动鼠标绘制椭圆。 三、总结手工添加消息映射的基本步骤 1.在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间添加消息映射宏;BEGIN_MESSAGE_MAP(CDemoView,CView) ON_MESSAGE(WM_LBUTTONDOWN,OnLButtonDown) ON_COMMAND(ID_OPER_TEST,OnOperTest) END_MESSAGE_MAP() ······ 2.在类声明中声明成员函数; DECLARE_MESSAGE_MAP() 3.在类的实现部分实现成员函数; 四、鼠标绘图功能的实现代码 1.头文件 #include "afxwin.h" class CDemoWnd:public CFrameWnd { public: CDemoWnd(); ~CDemoWnd(); public:

LRESULT OnPaint(WPARAM wParam,LPARAM lParam); LRESULT OnLButtonDown(WPARAM wParam,LPARAM lParam); LRESULT OnMouseMove(WPARAM wParam,LPARAM lParam); DECLARE_MESSAGE_MAP() public: int m_nX0; int m_nY0; int m_nX1; int m_nY1; }; class CDemoApp:public CWinApp { public: BOOL InitInstance(); }; CDemoApp thisApp; //全局应用程序对象2.源文件 #include "Demo.h" CDemoWnd::CDemoWnd() // 构造函数 { m_nX0 = 0; m_nY0 = 0; m_nX1 = 0; m_nY1 = 0; } CDemoWnd::~CDemoWnd() // 析构函数 { } BEGIN_MESSAGE_MAP(CDemoWnd,CFrameWnd)

相关主题
文本预览
相关文档 最新文档