windows消息

2024-05-14

windows消息(共3篇)

windows消息 篇1

0 引言

在文献[1]中详细叙述了Windows消息处理的机制,本文对消息处理的重要应用之一:窗口的子类化做详细的分析,通过一些具体的实例我们可以了解窗口子类化在Windows程序设计中的一些重要应用。

1 窗口消息子类化的原理

消息最终将交给窗口过程处理以实现各种功能,如果希望改变系统提供的窗口类(比如树视窗、按钮、列表框等窗体)对某些消息的处理方式,可以将窗口消息交给自己编写的函数处理,这个过程称为对窗口子类化。通过Win32提供的函数SetWindowLong可以对窗口子类化,在MFC中使用某些标准控件时通常将它们绑定到派生于CWnd的MFC类来实现子类化,CWnd派生类提供的Attach函数可以实现对窗口绑定,函数SubClassWindow可以对窗口动态子类化。窗口子类化后,需要特殊处理的消息通过CWnd派生类添加对应的消息映射宏,并且在CWnd类的派生类中添加消息处理函数即可,不必做特殊处理的消息仍交给系统默认的窗口过程处理。

一般来说,一个Win32应用程序在运行期间表现为进程,进程是应用程序的一个运行实例。一个进程可以拥有多个线程,线程描述了进程中的一条执行路径,实际上进程虚拟地址空间的代码是由线程负责执行的。在运行期间,当进程的一个线程创建了窗口,系统会给这个线程附加一个消息队列,用来存储发送给该窗口的各种消息,等待窗口过程来处理,处理消息的窗口过程(通常是一个回调函数)由创建这个窗口的线程调用。操作系统发送给窗口的消息放在创建这个窗口的线程的消息队列中,窗口过程的代码必须由创建该窗口的线程来执行。如果一个线程创建了多个窗口,这些窗口共享一个消息队列,消息队列和创建窗口的线程——对应,属于线程而非窗口。一个线程如果创建了窗口(拥有消息队列)称为用户界面线程,否则称为工作线程。一旦用户界面线程被创建,Win32系统确保该线程拥有一个不受其它线程影响的上下文环境,维护它自己对键盘焦点、窗口活动、鼠标捕捉等事件的看法。但是如果应用程序开发者想改变某一个窗口对某一事件的看法,一般要使用窗口子类化,比如要用鼠标左键单击窗口关闭按钮,一般会关掉整个应用程序,但是我们想要的可能是让窗口最小化后在后台运行。这个时候必须采用窗口子类化,把这个关闭消息WM_CLOSE交给开发者自己写的消息处理函数处理,而不是执行默认的关闭整个程序或窗口的操作。

子类化的目的是在不修改现有代码的前提下,扩展现有窗口的功能。它的思路很简单,就是将窗口过程地址修改为一个新函数地址,新的窗口过程函数处理自己感兴趣的消息,将其它消息传递给原窗口过程。通过子类化,我们不需要现有窗口的源代码,就可以定制窗口功能。子类化可以分为实例子类化和全局子类化。实例子类化就是修改窗口实例的窗口过程地址;全局子类化就是修改窗口类的窗口过程地是址。实例子类化仅仅是影响被修改的窗口;全局子类化会影响在修改之后,按照该窗口类创建的所有窗口。显然,对窗口全局子类化不影响修改前已经创建的窗口。

下面我们就MFC实现对窗口的子类化进行一些分析。利用MFC开发的应用程序采用的窗口一般都利用CWnd类或它的派生类进行了包装。MFC设计了该类的公共接口函数CreatcEX用来创建Wi ndows窗口,而这个函数在创建窗口前调用Set Windows HookEx函数安装了一个钩子函数AfxCbtFilterHook,这个钩子函数主要是调甩SetWindowLong函数将窗口默认的消息处理过程(或称默认消息处理函数)改成AfxWndProcBase。所以大部分利用MFC开发的应用程序的窗口在创建开始就已经实现了窗口子类化。如果开发者想改变一个默认消息的处理方式,要做的仅仅是在消息处理函数中把处理该消息的代码换成自己编写的代码。CWnd的函数WindowProc主要用来判别当前窗口的消息是交给用户自己写的消息处理函数还是由系统默认的窗口消息处理函数来处理,一般说来,不做特殊处理的消息将会被发送给原来的默认的窗口过程处理。

CWnd::OnWndMsg就是“MFC消息泵”的入口,也就说任何发送或投递到本窗口的消息都会经过这个函数过滤后处理。开发者需要做特殊处理的消息通过这个入口流入MFC消息映射中的消息处理函数。而其它的消息则不做任何处理交给默认的窗口过程DefWindowProc处理。其实我们在用MFC编程时使用的一些消息映射宏,其实就是对一些控件进行子类化的包装。

2 窗口消息子类化的应用

下面我们列举一些窗口子类化在应用程序开发中的一些应用例子。在利用MFC的应用开发中经常会用到对话框,以及将一些控件放在对话框上,如按钮、编辑框等等。如果我们希望添加一个编辑框并且处理一些消息,比如获得输入焦点等,可以用两种方法实现对编辑框控件的子类化。一是使用m_edit.SubclassDlgItcm(IDC_EDIT1,this);另一种是使用宏DDX_Control (pDX,1DC_EDIT1,m_edit)。两种方法基本是一样的,都是将系统发送或投递到编辑框窗口的消息交给在它的父窗口(这里是对话框)的消息处理函数进行处理。我们可以改写这些消息处理函数的代码来满足自己程序的需求。经过这两种方式子类化后的编辑框的窗口过程被改成了Af xWndProcBase,所有该窗口的消息都由这个函数过滤后再交给各种消息处理函数处理。

通过窗口的子类化,应用程序就可以根据需要,自己对某种消息处理进行独特的处理。需要注意的是在利用DDX或者SubclassDlg I tem函数子类化控件时,函数PreSubclassWindow一定会被调用。重载这个函数我们可以在子类化控件之前定制这个控件。比如有时候我们想使用一个可以选中全行的列表框控件,但是如果在列表框控件类的PreCreateWindow函数中定制这一个样式,由于对话框是由函数CrcatcDlg Indirect创建的,而PreCrcateWi ndow并不会被执行,所以列表框的这一样式不会实现。而在PreSubclassWindow中定制列表框的这一样式,只要这个列表框控件被子类化,这个函数一定会被调用。

3 结束语

消息处理是Windows编程的核心内容之一,窗口子类化作为Windows处理的一个重要方面,在各种应用程序的开发中起着重要作用。对Windows的一些窗口消息不做默认的处理,就必须使用窗口子类化,我们对窗口子类化的原理以及应用都做了详细的分析,为开发Windows应用程序提供有益的资料。

摘要:Win32消息处理机制是Win32应用编程的核心内容之一。Windows窗口消息的子类化,是根据消息处理的基本原理,把发送或投递到一个窗口的消息交给自己定义的函数处理,而不是交给默认的窗口过程处理。利用窗口子类化,开发者可以实现对应用程序的窗口消息进行独特的处理。

关键词:线程,消息队列,消息循环,子类化。

参考文献

[1]Jeffrey Richter.Advanced Windows(third edition)[M].Microsoft Press,1999.

[2]侯捷译.Win32多线程编程[J].武汉:华中科技大学出版社,2002.

[3]Charles Petzold.Windows Programming[M]. Microsoft Press,1999.

[4]潘爱民译.Visual C++5.0内幕(第四版)[M].北京:清华大学出版社,1997.

[5]Joel Scambray,Stuart McClure,George Kurtz著,钟向群等译.黑客大暴光[M].北京:清华大学出版社,2001.

windows消息 篇2

对于一个win32程序来说消息的整个系统是非常重要的,程序的运行必须是在消息传递的前提下完成。消息从本质上说是系统确定的32位数值,根据它的唯一性确定事件,通过指令的形式告诉Windows程序已经发生。消息是以记录的形式发送给应用程序的,记录中不仅包括消息的类型,而且还包括的其它信息。

通常情况下,消息是由应用程序或者系统产生。应用程序产生消息使窗体执行任务,或者与其他应用程序中的窗口通讯。如果系统出现输入事件,它就会生成消息,比如说敲键盘,单击鼠标等都可以生成消息。系统也会生成消息,进而和应用程序的变化保持一致性,例如使用应用程序改变字体形式。

二、消息的发送和接收

1. 消息的发送

消息向窗口的发送形式分为三种:广播、寄送以及发送。被使用在消息发送过程的函数包括SendNotifyMessage、SendMessageCallback以及SendMessage等;被使用在消息寄送中的函数包括PostThreadMessage以及PostMessage等;被用在消息广播过程中的函数主要有:BroadcastSystemMessageEx和BroadcastSystemMessage。

(1)SendMessage函数

函数功能:这个函数可以把制定的消息传递给各个窗口。这个函数也是规定的窗口调用窗口程序,必须在窗口程序处理之后,消息才能够返回。

函数原型是LRESULT SendMessage,包括三个方面:,WPARAM wParam,UINT MsgLPARAM IParam,HWND hWnd。

(2)PostMessage函数

函数功能:这个函数把消息寄送或放入在规定窗口建立的线程相联系消息队列中,并不需要线程处理结束就可以返回消息。通过使用PeekMessage和GetMessage获取消息队列中的消息。

函数原型是B00L PostMessage,分为三个:WPARAM wParam,LPARAM lParam,UINT Msg,HWND hWnd。

2. 消息的接收

(1)GetMessage函数

函数功能:这个函数在调用线程的消息队列中选取一个消息,然后再储存在制定的结构中。这个函数可以获取和制定窗口相联系的消息,而且,这些消息也是PostThreadMesssge寄送的线程消息。这个函数可以获取某一范围内的消息值。GetMessage不可以获取属于其他应用程序或者线程的消息。

函数声明是BOOL GetMessage,主要包括UINT wMsgFilterMin以及LPMSG lpMsg等。

(2)PeekMessage函数

函数功能:这个函数是属于消息检查线程消息队列,而且把这个消息储存在相应的结构中。

函数原型,也就是BOOL PeekMessage,主要包括HWND hWnd,UINT wMSGfilterMin以及LPMSG IpMsg等。

(3)WaitMessage函数

函数功能:这个函数能够控制其他线程,当线程的消息队列中并不存在消息。这个函数将停止线程,当出现消息进入线程队列时,函数才返回。

函数原型,也就是BOOL WaitMessage。

三、消息处理

1. 窗口函数及其基本结构

窗口函数确定了在窗口显示区域内显示什么以及窗口怎样响应用户的输入。

传给窗口函数的message参数实际上是数值。为了方便编程在Windows头文件WINUSER.H中,为每一个消息定义了识别字,它们都是以“WM”(窗口消息)为自首的字符串。一般来说,Windows编程人员使用switch和case结构来确定窗口函数接受的消息并处理它。窗口函数处理完消息后,返回0。凡是窗口函数不予处理的消息传给名为DefWindowProc的Windows函数。从DefWindowProc返回的值再由窗口函数返回。在HELLOWIN中WndProc只选择处理三个消息:WM-CREATE、WM-PAINT和WM-DESTROY[2]。

2. 消息的处理方式

程序靠消息的流动而获得生命,而消息的处理方式是在窗口函数中借助switch/case结构对消息进行筛选和处理的,这也是windows编程最容易出错的地方。

为了简化switch/case的动作,也让程序代码的模块性更强,就将命令和命令处理函数关联起来,从而使窗口函数内容更模块化、更一般化。

(1)MFC消息处理的实现方式

MFC处理命令消息最基本、最关键的就是CCmdTarget类。MFC给这个类的设计带来了成员数据以及成员函数,其目的主要是处理消息映射问题,它能够生成很多的事件或消息类,比如:框架类、视图类以及控件类等。

(2)MFC消息映射的实现方法

MFC消息映射通过利用ClassWizard进而有效的完成消息映射过程。具体的,要在源码中加入消息映射数据,再得到消息处理函数。

一般来说,在进行类的定义时,其不仅带来了消息处理函数声明,而且也提供消息映射的宏,也就是DECLARE_MESSAGE_MAP。通过使用类的实现文件,完成消息处理过程,然后再利用IMPLEMENT_MESSAGE_MAP宏进行消息映射。通常情况下,在这一过程中使用的声明和实现都是通过MFC的ClassWizard进行维护的。

四、结束语

本文讨论了windows系统环境下的消息传递的各种机制,通过掌握windows系统环境下的消息发送和接收,这其中用到的消息发送函数有Sendmessage和PostMessage;用到的消息接收函数有GetMessage、PeekMessage和WaitMessage这其中存在的问题是这三种不同的消息发送和接收函数之间具体有什么更深的内在联系还需要进一步解决。窗口函数是消息处理的关键,整个消息处理的过程大部分都是由窗口函数来完成的,所以掌握窗口函数的基本结构也是比较重要的。用MFC所建立的代码是完全可移植的。程序员只要操作简单的数据对象的方法.便可实现消息传递。

摘要:在Windows系统中进行的程序编写是事件驱动,通过消息进行传递。因此,只有深入了解消息传递机制才能够完成Windows系统中程序编写,笔者根据自己对消息传递以及相关资料来分析消息传递机制。让大家大致知道消息的传递方向,再解释消息传递机制。消息传递机制主要包括的内容是消息的定义、消息的发送、消息和接收、消息的处理以及消息的处理中与之相关的窗口函数。

关键词:消息,消息发送和接收,消息处理,窗口函数,MFC消息

参考文献

[1]姜晓铭《Visual C++6.0程序设计》北京工业大学出版社2002.5。

[2]张正秋《windows应用程序捆绑核心编程》清华大学出版社2006.12。

windows消息 篇3

1.Windows消息

消息就是指发出的一个通知, 告诉应用程序某个事情发生了。例如, 单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。而消息本身是作为一个记录传递给应用程序的, 这个记录中包含了消息的类型以及其他信息。

(1) WM_COPYDATA和TCopyDataStruct

WM_COPYDATA是Windows定义的消息, 被用于应用程序之间发送数据。对应的消息记录是TWMCopyData, 在Message.pas单元声明如下:

发送和接收的数据存放在TCopyDataStruct记录内, TCopyDataStruct在Windows.pas单元声明如下:

1) dwData用以区分收发数据的类型, 接收方针对dwData值调用相应的处理过程。

2) cbData和lpData确定了收发的数据在内存中具体存放位置和大小。

(2) 发送消息的方法

Windows发送消息有两种方式, SendMessage和PostMessage。SendMessage直接把一个消息发送给窗口过程, 等消息被处理后才返回。PostMessage () 只是把消息发送到消息队列, 然后立即返回 (SendMessage和PostMessage声明于Windows.pas单元的接口部分) 。

1) hwnd是接收消息的窗口的句柄。

2) Msg是消息标识符。

3) wParam是3 2位的特定附加信息。

4) lParam是3 2位的特定附加信息, 本文中用其存放发送数据的地址。

尽管SendMessage和PostMessage调用方式完全一样, 但它们的返回值不一样。SendMessage返回此消息被处理的结果值, PostMessage调返回一个布尔值, 表示消息是否已被放到消息队列中。

(3) 接收并处理消息

Delphi的VCL替程序员处理了许多Windows消息系统的细节, 开发者根本不用考虑怎样从消息队列中检索和接收消息, 只要关心如何处理消息即可。处理消息的方法是首先在窗体的Private部分声明一个处理消息的过程, 而后在单元的implementation部分实现这个过程即可。

1) 声明过程:procedure WMCopyData (var Msg:TWM-CopyData) ;message WM_COPYDATA;

2) 实现过程:procedure TReceiveForm.WMCopyData (var Msg:TWMCopyData) ;

2.发送数据代码

发送方首先往TCopyDataStruct记录中填充数据, 然后利用FindWindow函数查找接收方窗口句柄, 最后调用SendMessage函数发送消息。

(1) 发送字符串类型的数据

(2) 发送过程SendData

3.接收数据代码

接收方在消息处理过程中首先得到TWMCopyData记录, 然后对TWMCopyData.CopyDataStruct记录中的数据进行显示或其他处理, 最后设置TWMCopyData.Result值返回给发送方 (此返回值就是发送方调用SendMessage的返回值) 。

(1) 处理WM_COPYDATA消息过程

(2) 处理接收数据的过程HandleCopyDataString

上面介绍了利用WM_COPYDATA在单机环境下, 实现两个应用程序之间发送和接收字符串类型数据的方法。在此基础上, 通信双方可进一步约定TCopyDataStruct记录dwData的取值 (如0为字符串、1为图片、2为记录等) , 然后通过设置、读取lpData指针指向的数据地址, 可以实现图片或记录等其他类型数据的发送和接收。

上一篇:校企合作双重管理模式下一篇:有趣的数学之家