《Inside VCL(深入核心——VCL架构剖析)》.(李维) 一

一、回到从前:
1.1、多任务操作系统是如何设计和实现的?
1.1.1、系统——多个应用程序
方案1:(系统不断读取应用程序状态)
系统通过大型循环(Loop)不断坚持么一个恶用用程序是否触发了特定的事件。
方案2:(事件驱动模型——事件/消息处理模型)

执行环境将事件转换成代表事件的消息,然后发送给对应的应用程序。


//消息大概格式
TMyMessage = packed record //用来存储事件信息
Message : Longint;
wParam : Longint;
lParam : Longint;
time : Longint;
pt : TPoint;
end;


1.2、事件/消息模型还需要解决的问题:
1、应用程序可能拥有多个窗口,如何把触发的消息分派给正确地窗口去处理?

2、把消息分派给应用程序或者窗口是如何办到的?

3、当分派了消息给窗口之后,窗口要如何处理此消息?

1.2.1、窗口运作模型:(问题1)

执行环境中可能有多个应用程序,一个应用程序可能建立多个窗口。如何保证执行环境的事件能分配到正确应用程序的正确窗口?

因此,我们可以在MyMessage中再加入一个代表窗口的识别值来分辨应用程序的不同窗口:

TMyMessage = packed record
hwnd : HWND;
Message : Longint;
wParam : Longint;
lParam : Longint;
time : Longint;
pt : TPoint;
end;

hwnd: HWND;//代表窗口的标识。消息中有唯一代表窗体的hWnd,通过hwnd可以准确的将消息发送到对应的窗口。


2、高速缓存(caching)执行环境为每个应用程序建立一个消息队列(Message Queue)。当事件发生时执行环境酒吧代表他的消息分派到此消息队列,等待应用程序从中取出并且处理。
如此,问题1解决。

1.2.2、执行系统、事件、消息和触发应用程序代码

1.2.2.1、执行环境需要哪些信息才能正确地为应用程序创建窗口呢?

窗口的位置和大小;

窗口的格式、使用的颜色以及使用的光标种类;

窗口使用的菜单以及其他资源;

当窗口发生事件时,能够处理窗口消息的函数地址。

执行环境提供了一个标准窗口的类别数据结构,在这个标准数据结构中即可定义上述信息的字段,应用程序只要在每个字段中填入正确地信息已表达想要创建的窗口格式即可。

MyWindowClassInfo = packed record
	style: UINT;			//代表窗口的格式
	iWidth: Integer;		
	iHeight: Integer;		
	lpfnWndProc: Pointer;		//处理窗口消息的函数的地址
	hIcon: HICON;
	hCursor: HCURSOR;		
	hbrBackground: HBRUSH;
	lpszMenuName: PAnsiChar;
	lpszClassName: PAnsiChar;	//窗口的类名称
	hIconSm: HICON;
end;

应用程序为每个窗体向系统提供MyWindowsClassInfo数据结构,再分别向执行环境注册每一个窗体的MyWindowsClassInfo信息。当创建特定窗口种类时,只需要提供要创建窗口的类名称,执行环境再根据窗口的类名称找到相应的MyWindowsClassInfo数据结构,最后根据MyWindowsClassInfo中的信息来创建窗口。

解决了执行环境如何创建窗口的问题后,那么,窗体如何来处理执行环境发生过来的事件消息?

让执行环境调用窗口提供的函数并且传递消息给此函数来处理,在上面部分MyWindowClassInfo的lpfnWndProc字段就指向了处理该窗口消息的函数(回调函数)。执行环境通过调用该函数,将消息分派给指定的窗体。

执行环境需定义回调函数的原型:

function WindowProced(Window: HWnd;  AMessage: UINT; WParam: WPARAM; LParam: LPARAM):LRESULT; stdcall; export;

在上面的回调函数原型中参数Window、WPrarm和LPrarm字段,代表发生事件的窗口ID以及窗口消息的辅助信息等。而参数AMessage则代表事件的窗口消息值。因此当英语程序遵照回调函数的原型提供了适当的处理窗口消息的函数并且指定给MyWindowClassInfo中的lpfnWndProc字段,那么应用程序就可以等待这个回调函数在窗口事件发生后自动由执行环境调用了。(至此,问题2解决

最后,当执行环境调用了回调函数后,其中的AMessage就代表了发生事件的ID,因此在回调函数中就可以通过判断AMessage的数值来得知发生的时间,再格恩局不同的时间使用相应的程序代码来处理:

case AMessage of
	WM_PAINT://重画窗体的消息
	...
	WM_DESRROY://窗体消灭的消息
	...
end;
由于应用程序要判断回调函数中发生的消息ID值,因此执行环境当然必须为触发时间定义代表消息ID及每个消息的意义了:

unti Messages;

	...
const
	WM_NULL		= $0000;
	WM_Create	= $0001;
	WM_DESTROY	= $0002;
	WM_MOVE		= $0003;
	...
	WM_PAINT	= $000F;
	...
应用程序只需要uses这个消息单元就可以根据其中的消息ID值来判断AMessage代表的事件了。(至此,问题3解决

现在我们几乎已经完整地定义了执行环境如何使用 事件/消息/回调函数 的机制在多任务环境中提供应用程序处理事件的机制。首先,应用程序经由填入MyWindowClassInfo数据结构来注册窗口信息,之后应用程序在调用创建窗口并且提供窗口回调函数。

 当应用程序欲创建窗口时只要提供窗口类名称,执行环境便会在所有已经注册的窗口类中搜寻MyWindowClassInfo中lpszClassName字段值与提供的窗口类名称一致的MyWindowClassInfo数据结构。找到之后根据其中的窗口特性值来创建按窗口。

当执行环境产生消息后,会根据窗口的ID值,即MyMessage中的hwnd字段,找到此窗口的MyWindowClassInfo数据结构,再调用其中的回调函数字段lpfnWndProc。如此,执行环境便可以正确调用到应用程序提供的窗口消息处理函数了。


《深入核心——VCL架构剖析》光盘说明-、光盘用途 本光盘为《深入核心——VCL架构剖析书的配套光盘,供读者阅读图书时参考和学习。二、光盘内容 光盘“源代码”目录中包含了书中所有源代码,文件目录和图书的目录相对应。如“Chap01”表示书中第1章的范例源代码。 光盘包含了全部的pas、dfm和dpr文件。 我们已经对所有文件进行了简体化工作。如果您在使用中发现有界面乱码问题,请将窗体Font改为“宋体”,Charset改为gb2312即可,并请即时告知我们,让更多读者受益。三、运行环境 多数代码可以直接在Delphi6和Delphi7环境下运行。部分涉及.NET技术内容的代码,需要在Delphi 7上安装Borland .NET Complier for Delphi编译器方可编译执行。Borland已经正式推出Delphi 8 for .NET,所以本书范例中部分内容可能与D8最终版本不符。四、使用方法 直接将范例文件拷贝至硬盘适当目录即可。 多数完整应用程序代码已经编译为.exe可执行文件,读者可直接运行之。五、防病毒 本光盘所有文件都已经过Norton Antivirus扫描,未发现有任何已知病毒。六、风险 读者须对使用光盘所附代码、文件所造成的切后果负责。 七、如果对代码有任何疑问、建议或者发现有遗漏、错误之处请与 liwei@csdn.net联系。六、所有源代码可以在学习和工作中直接使用,但请不要用于商业目的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值