首页 > 范文大全 > 正文

Borland C++Builder响应Windows消息机制的分析

开篇:润墨网以专业的文秘视角,为您筛选了一篇Borland C++Builder响应Windows消息机制的分析范文,如需获取更多写作素材,在线客服老师一对一协助。欢迎您的阅读与分享!

摘要:Windows是一套以消息驱动的操作系统。C++ Builder的可视化组件库 (VCL)提供了对大多数Windows消息的处理机制,程序开发人员在一般情况下无需理会Windows消息的细节。然而作为一个windows程序开发者,实有必要掌握C++Builder中如何进行Windows消息的捕获。该文阐述了Windows消息的概念,对C++Builder的消息映射机制进行了系统分析,同时结合一个实际范例,仔细说明了其中之技巧。

关键词:Windows;borland C++ Builder;Windows 消息; 消息映射机制

中图分类号:TP316文献标识码:A文章编号:1009-3044(2010)09-2150-02

Analysis of the Response mechanism of Windows Message in Borland C++ Builder

TANG Yan-hua

(Hunan Urban Professional College, Changsha 410137, China)

Abstract: Windows is a operating system which is based on message driver. Visual Component Library (VCL) in C++ Builder supplies the process mechanism to the most of Windows messages and the programmer needn't pay attention to the detail of Windows message in general. However, it is necessary to hold Windowsmessage'sresponsemechanismin C++ Builder. In this paper, The conception of Windows message and the C++ Builder message map mechanism is introduced, at one time, the technique is explained with a example.

Key words: Windows; Borland C++ Builder; Windows message; message map mechanism

Windows是一套以消息驱动的操作系统,C++ Builder的VCL提供了对大多数Windows消息的处理机制,程序设计者在一般情况下无需理会Windows消息的细节。然而由于Windows事件驱动方式主要基于消息机制,因此在遇到c++builder没有定义的Windows消息时,如何进行捕获Windows消息仍然是C++Builder程序员不可或缺的能力。 不可否认,C++Builder所提供的事件处理能力已具备了某一程度的完备性,然而我们也必须承认,VCL仍有不尽完美之处。例如程序员自定义消息的处理、Winsock消息的处理及一些Windows消息如WM_NC**** 系列的消息都是C++Builder的控件所未包含的。本文将讨论如何以C++Builder来处理Windows消息,并使用这一技术,实现在一般VCL控件所无法做到的功能。

1 何谓Windows消息

Windows 程序设计是一种以事件为驱动方式的的程序设计,而事件又主要基于消息处理机制。当用户需要完成某种功能时,需要调用OS的某种支持,然后OS将用户的需要包装成消息,并投入到消息队列中,最后应用程序从消息队列中取走消息并进行响应。所谓消息是由windows操作系统送往程序的事件。它是系统中各个控件沟通的方式,举例来说,当移动鼠标、按下鼠标键、改变窗体大小时,Windows都会送出消息以通知程序。当然,为了要辨别事件的内容,Windows系统中定义了许多的消息,如WM_PAINT,WM_CHAR等等。当事件发生时,Windows会判断该事件必须由哪个程序接收,然后将事件以消息的方式送往程序的窗体中。虽然在Windows系统中包含了数以百计的事件,但是操作系统并没有为各个事件设计不同的消息结构,而是以一个一般性的结构来描述消息,这个结构在C++Builder就称为TMessage。当然,随着事件的不同,对于消息的解释也有所不同,在C++Builder中也为各种常用的消息定义了专门的结构,你可以直接使用它们来解释消息。这些消息定义在C++Builder目录下的Include\vcl\messages.hpp中,你可以决定要自行解释TMessage参数或是直接将其转换成专门的结构。例如,以WM_NCHITTEST消息来说,C++Builder为它定义了TWMNCHitTest的专门结构,所以你可以直接经由它来得到XPos、YPos等值。或者你也可以直接由TMessage的LParam取得其值,只看你使用的方便。仔细观察TMessage及TWMNCHitTest两个结构,你会发现它们是等价的,也就是说它们的大小是一致的,因此你可以直接用强制类型互相转换(这有点类似union的方法)。

2 C++ Builder的消息处理机制

C++Builder为了处理消息的方便,定义了三个处理消息的宏(Macro)。

BEGIN_MESSAGE_MAP

MESSAGE_HANDLER(< message >,< message structure >,< message handler >)

END_MESSAGE_MAP(ClassName)

其中比较重要的是MESSAGE_HANDLER;它共需要三个参数,第一个参数代表消息的ID,第二个代表参数类型,最后一个则是消息事件处理函数。乍看之下,这个宏与MFC及OWL所使用的宏有几分相似,不过其机制却更为简洁,我们可以看看C++Builder对于这三个宏的原始定义:

#define BEGIN_MESSAGE_MAP virtual void __fastcall Dispatch(void *Message) \

{ \

switch (((PMessage)Message)->Msg) \

{

#define MESSAGE_HANDLER(msg,type,meth) \

case msg: \

meth(*((type *)Message)); \

break;

#define END_MESSAGE_MAP(base) default: \

base::Dispatch(Message); \

break; \

} \

}

相较于MFC或 OWL的宏,C++Builder的宏实在是简单多了,这是因为C++Builder已替我们完成了大部份的工作。

3 程序实例

下面就用一个例子具体说明C++Builder中如何编程实现对Windows消息的响应。一般Windows程序的标题栏位于窗体的上方,我们可以利用该标题栏来移动窗体。下面示范程序将说明如何利用C++Builder作出置于窗体左方的标题栏,并响应WM_NCHITTEST消息。程序主窗体如图1所示。

从图1,你可以很清楚地看到,这个窗体和其他的窗体有很大的不同;它的标题栏位于左方,而且其颜色为蓝色,同时其文字的走向为由下而上的90度,而其功能则和一般的标题栏相同,你可以将鼠标移至该处,然后移动该窗体。其实现的基本步骤如下:

1) 创建一个新工程,将单元文件保存为MyForm.cpp,工程文件保存为Msgp.bpr。

2) 创建一个无标题栏的窗体,将Form1的BorderStyle属性设为bsNone。注意在设计时创建的所有C++ Builder窗体都会有一个标题栏。

3) 打开MyForm.h文件,在类声明中建立消息映射表,将 WM_NCHITTEST消息的处理权交给自定义的消息处理函数。WM_NCHITTEST消息名称为"非客户区命中测试",它优先于所有其它的客户区和非客户区鼠标消息,Windows应用程序通常把这个消息传送给DefWindowProc,然后Windows用这个消息产生基于鼠标位置的所有其它鼠标消息。部分代码如下:

class TForm1 : public TForm

{ __published: // IDE-managed Components

private: // User declarations

public: // User declarations

__fastcall TForm1(TComponent* Owner);

BEGIN_MESSAGE_MAP

VCL_MESSAGE_HANDLER(WM_NCHITTEST,TMessage,OnNcHitTest)

END_MESSAGE_MAP(TForm)

};

4) 在类声明的private区内声明消息处理函数。

void __fastcallOnNcHitTest(TMessage &Msg);

5) 在MyForm.cpp中写出消息处理函数,在此实现你需要的功能。部分代码如下:

void __fastcallTForm1::OnNcHitTest(TMessage &Msg)

{ TPoint pt;

pt.x=LOWORD(Msg.LParam);

pt.y=HIWORD(Msg.LParam);

pt=ScreenToClient(pt);

RECT rc;

::SetRect(&rc,0,0,20,384);

if(PtInRect(&rc,pt))

Msg.Result=HTCAPTION;

else

DefaultHandler(&Msg);

}

说明:OnNcHitTest函数首先取得目前鼠标所在点,注意,WM_NCHITTEST消息所传入的点为相对于屏幕的绝对座标,因此在取得该点后必须利用ScreenToClient函数将它转为TForm的相对座标值,然后再据以判断是否落于我们所定义的标题栏范围内,若是则传回HTCAPTION值,否则就交由内定的处理函式DefaultHandler来处理。

下面的程序就是建立一个旋转90度的字形,然后将字串以此字形画于屏幕上,此段程序码的关键在于你必须知道Canvas->Handle即是代表GDI绘图的HDC。其余的函数说明你都可以在一般讲解传统Windows SDK绘图的书籍中找到。

void __fastcall TForm1::FormPaint(TObject *Sender

{

RECT rc;

::SetRect(&rc,0,0,20,ClientHeight);

Canvas->Pen->Color=clBlue;

Canvas->Brush->Color=clBlue;

Canvas->Rectangle(0,0,20,ClientHeight);

char *msg=Caption.c_str();

LOGFONT fontRec;

memset(&fontRec,0,sizeof(LOGFONT));

fontRec.lfHeight=-13;

fontRec.lfWeight=FW_NORMAL;

fontRec.lfEscapement=900;//旋转文字的关键

StrCopy(fontRec.lfFaceName,"宋体");

HFONT hFont=CreateFontIndirect(&fontRec);

HFONT hOld=::SelectObject(Canvas->Handle,hFont);

::SetRect(&rc,0,0,20,ClientHeight);

::SetTextColor(Canvas->Handle,RGB(255,255,255));

::TextOut(Canvas->Handle,3,ClientHeight-3,msg,lstrlen(msg));

::SelectObject(Canvas->Handle,hOld);

::DeleteObject(hFont);

}

4 结论

本文说明了在C++Builder中处理消息的方法,同时以一个实际的自定义标题栏窗体为范例,仔细说明了其中之技巧。除此之外,在Windows系统中,消息是无所不在的,它是许多传统的窗体控件用以互相沟通的关键,因此了解Windows消息是Windows程序员不可或缺的能力。

参考文献:

[1] 杨强,李堂秋.Win9X虚拟设备驱动程序编程指南[M].北京:清华大学出版社,1999.

[2] 罗日成,李卫国:基于Windows DLL技术实现监测软件中端口读写方法[J].电力自动化设备,2001,21(10):30-32.

[3] 陈周造,陈灿煌.C++ Builder4 彻底研究[M].北京:中国铁道出版社,2000.

[4] Ezzell B.Windows 32位编程指南[M].北京:清华大学出版社,1996.

[5] Ezzell B.Windows 32 Byte Programming Guide[M].Beijing:TsingHua University Press,1996.