Windows SDK编程(Delphi版) 之 消息处理
2010年06月17日
之前,已经讲了如何进行SDK编程,以及SDK运行的一些机理条件,同时还给出了一个SDK的Delphi编程模板,大家可以通过那个模板来实现一个简单的SDK框架。
这回就记录一下SDK里面的消息处理。Windows的应用处理核心就在消息上,而这个消息的处理就在对应的窗口的窗口过程中,之前,我给的模板中,就有一些消息处理,只是很少,比如说WM_DESTROY,这个消息就是在窗口释放的时候会触发,然后我发送了一个退出程序的消息。
Windows是一个交互式及时响应操作系统,那么每步的操作都会产生大量的消息。每条消息由一个唯一的32位整型值来表示,并且每条消息相当于某个事件。例如WM_LBUTTONDOWN表示鼠标左键按下,WM_LBUTTONUP表示鼠标左键弹起等等。WM_LBUTTONDOWN这个在C中实际上,都被叫做宏名,是用#define定义的,而在Delphi中就是我们定义的常量,用Const关键字标记,一般的系统消息,我们可以在 Messages单元中看到。比如一些常用的消息:
WM_CHAR,WM_PAINT,WM_MOVE,WM_CLOSE,WM_LBUTTONDOWN,WM_LBUTTONUP等。每条消息,都伴随着其他两个值,这两个值获得与具体消息相关的消息。其中一个值是WPARAM类型,另一个是LPARAM类型。实际上这两个类型就是LongInt类型。通常,他们保存着消息的一些附加信息,比如保存光标或者鼠标的坐标、按键值或与系统相关的值。
消息都是由程序的窗口函数来处理的,窗口函数有4个参数,以前说过,分别为消息所服务的窗口的句柄、消息本身和两个附加信息wparam,lparam。有时,附加消息被译成两个包含wparam和lparam参数的字。为了便于访问wParam和lParam,在C中有LOWORD和HiWORD这两个宏,而在Delphi中也可以使用loword()强制转型与hiWOrd这个函数来实现一样的功能。比如x := loword(lparam); y := hiword(lparam);
分别返回低位和高位。
现在来举例一些常见的Windows消息,比如我们用键盘输入时产生的按键消息,WM_Char,实际上WM_CHAR是被 TranslateMessage这个转换过来的(这个在之前已经说过)。当我们每按键一次,WM_CHAR消息就被送到活动窗口中,然后系统会调用本活动窗口的窗口过程来处理这个按键值。每次发送WM_CHAR时,wParam中就包含了所按键的ASCII码值。loword(lparam)中包含由于持续按键锁导致的重复按键的次数。HIWORD(lparam)中的每一个位表示的信息为:
位 意义
15 如果正被释放则为1,如果正被按下则为0
14 如果在发送消息前则为1,否则为0
13 ALT被按下时为1,否则为0
12 ~9 Windows使用,我们不管
8 如果按下的键是由增强键盘提供的扩充键则为1,否则0
7~0 依赖于生产厂家的键盘代码(既扫描代码)
通过上面的这个,可以知道WParam中保存的就是我们需要的ASCII代码,那么就可以通过这个来获得用户的按键信息了。于是,在那个模板的窗口过程中,我们可以添加一个消息的处理过程为
WM_CHAR:
begin
MessageBox(hwnd,pchar('消息:您按下了 '+inttostr(wParam)+' ASCII:'+CHAR(wParam)),'消息',64);
end;
这样,就能够获得你输入的按键的编码和按键信息了。
现在,再来看看另一个消息,WM_Paint,这个消息主要是在绘制界面的时候产生,通过对这个消息进行处理,可以在界面上绘制出任何我们想要的效果。现在说他的目的就是将我们上面说的按键信息通过这个WM_PAINT绘制显示在界面上,而且让他一直存在!为什么,我这里会说一直存在!这个与 Windows的一个显示机制有关系,这个后面再说。WM_PAINT的主要目的是用来绘制界面的,那么这个绘制如何来与界面屏幕进行交互呢?这里有另外一个概念就是设备描述表。通过设备描述表,用户的程序就能够和屏幕之间建立一个链路。所谓的设备描述表实际上是一个描述窗口输出显示环境的结构体,它包括了设备驱动程序和不同的现实参数,如当前的字体类型等。所以,我们要想将用户的按键信息显示在界面上,那么首先,我们需要在界面屏幕与程序之间建立一个链路,也就是要获得界面的设备描述表,获得设备界面描述表有几种方式。不过在WM_PAINT消息中,获得对应窗口的设备描述表,我们只能使用 BeginPaint这个API函数。其原型为:
HDC BeginPaint(Hwnd hwnd,LPPAINTSTRUCT lpPS);
Delphi的为
function BeginPaint(hWnd: HWND; var lpPaint: TPaintStruct): HDC; stdcall;
这个函数,就返回一个hwnd句柄所对应的窗口的设备描述表句柄,如果函数成功返回句柄,失败,返回0第二个参数返回时所对应的结构体中将包含程序用来重画窗口的信息。
typedef struct tagPAINTSTRUCT{
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
Bool fIncUpdate;
Bool rgbReserved[32];
}PAINTSTRUCT;
Delphi中对应的结构在Windows单元中,可以看到,中hdc就包含被重画的窗口设备描述表句柄。此DC也是通过BeginPaint() 返回的。如果需要擦出窗口的背景,则fErase为非0值。不过只要在窗口创建时指定了一个背景画刷,就可以忽略fErase,系统会自动擦除窗口。 RECT类型是一个指定矩形区左上角和右下角的结构体。一旦我们获得了设备描述表,就可以像窗口中输出内容和绘制我们的信息。完成我们信息的绘制之后,必须调用EndPaint来释放设备描述表。
BOOL EndPaint(HWND hwnd,CONST PAINTSTRUCT *lpPS);
EndPaint返回非0值(它不可能失败)。hwnd指定重画窗口的句柄,第二个参数就是beginPaint的第二个参数。这里有两点需要主要,首先就是WM_PAINT中必须使用BeginPaint函数来获得设备描述表,然后就是使用BeginPaint获得设备描述表之后,必须使用 EndPaint来释放设备描述表。
另外获得设备描述表还有一个方法GetDC(HWND hwnd)用来获得指定窗口的设备描述表,释放设备描述表使用ReleaseDC(Hwnd,DC)。在不使用设备描述表的时候,释放它是必须的,因为设备描述表的数目只由自由内存的大小来决定,其数目有限,如果用户程序都不释放设备描述表,那么最终可用的设备描述表就会被耗尽,从而导致获得设备描述失败。
通过上面的描述,那么现在,我们就可将我们的按键信息一直显示在界面上,直到用户按下下一个按键位置。实现方式如下:
先定义一个LastChar: longint=-1,在winMain的时候初始化为-1,表示无效值
代码 WM_CHAR:
begin
//MessageBox(hwnd,pchar('消息:您按下了 '+inttostr(wParam)+' ASCII:'+CHAR(wParam)),'消息',64);
LastCHar := wParam;
r.Left := 30;
r.Top := 20;
r.Bottom := 50;
r.Right := 250;
Dc := GetDC(hwnd);
FillRect(Dc,r,GetStockObject(WHITE_BRUSH));
DrawText(Dc,Pchar('ASCII: '+inttostr(LastCHar)+' 字符:'+CHar(LastCHar)),-1,r,DT_CENTER or DT_SINGLELINE or DT_VCENTER);
ReleaseDC(Hwnd,Dc)
end;
此时将WM_CHar换成这样,然后用户在按键的时候,就会在界面上显示用户的按键信息了。里面用到了FillRect这个函数,这个函数是填充区域,使用它的目的是刷新界面为白色,去掉上次绘制的文字信息。但是现在这个有个问题,就是当用户将程序最小化在恢复的时候,我们记录的文字信息就丢失了。前面,我已经说过,这是由于Windows的显示机制决定的,Windows并不帮我们恢复窗口内所包含的记录,所以这种情况下,我们必须自己保存记录,然后重新显示窗口的内容,窗口每次恢复的时候,都会向用户的程序发送一个WM_Paint消息,每次接收到这个消息,他都必须重新显示窗口中的内容,于是我们需要在窗口中处理我们自己的绘制消息。这里实际上在模板中,我已经写了一个hello word的wm_Paint模板,现在我们只用将WM_CHar中的稍微修改,搬到WM_Paint的实现中去,就能够实现永久记录了。
WM_PAINT:
begin
GetWindowRect(hwnd,r1);
r.Left := 0;
r.Top := 0;
r.Right := r1.Right - r1.Left;
r.Bottom := r1.Bottom - r1.Top;
Dc := BeginPaint(hwnd,PaintStruct);
try
SetBkMode(Dc,TRANSPARENT);
DrawText(Dc,'Hello World!',-1,r,DT_CENTER or DT_SINGLELINE or DT_VCENTER);
if LastCHar > -1 then
begin
r.Left := 30;
r.Top := 20;
r.Bottom := 50;
r.Right := 250;
Dc := GetDC(hwnd);
FillRect(Dc,r,GetStockObject(WHITE_BRUSH));
DrawText(Dc,Pchar('ASCII: '+inttostr(LastCHar)+' 字符:'+CHar(LastCHar)),-1,r,DT_CENTER or DT_SINGLELINE or DT_VCENTER);
ReleaseDC(Hwnd,Dc)
end;
finally
EndPaint(hwnd,PaintStruct);
end;
end;
然后还有一些其他的非常多的消息,其处理过程都是根据自己的需要,在窗口过程中的Case结构中添加需要的消息,加上自己的处理过程就好了。我这里不再一一讲述,具体的消息参考可以去找《Microsoft Win32程序员参考大全(五)----消息、结构和宏》这本书看看!里面记录了所有Windows的消息信息以及参考资料。
发表评论
-
VBS脚本常用经典代码收集
2012-01-20 02:13 689VBS脚本常用经典代码收集 2010年06月21日 1. ... -
多线程加速图像模板匹配
2012-01-20 02:13 636多线程加速图像模板匹 ... -
Java编程思想――并发(3)
2012-01-20 02:13 837Java编程思想――并发(3) 2010年07月28日 ... -
ORACLE PL/SQL编程详解之七 程序包的创建与应用
2012-01-20 02:13 656ORACLE PL/SQL编程详解之七 ... -
fread函数和fwrite函数
2012-01-20 02:13 814fread函数和fwrite函数 2010年06月28日 ... -
[耀湾/微亚细亚] 夜降り萃梦乡 FIN.
2012-01-19 10:03 642[耀湾/微亚细亚] 夜降り萃梦乡 FIN. 2009年02月 ... -
她为我写的 ..........你就是我的天使…………
2012-01-19 10:03 538她为我写的 ..........你就是我的天使………… 2 ... -
D---的记忆3
2012-01-19 10:03 620D---的记忆3 2008年10月12日 一、洞察 ... -
《因为是你》--2
2012-01-19 10:03 614《因为是你》--2 2012年01月13日 兼职保姆 ... -
如何有效维护和发布“Windows + Android SDK + Eclipse”开发环境下的apk和代码
2012-01-17 02:44 994如何有效维护和发布“Windows + Android SDK ... -
Kinect for Windows SDK beta 放出
2012-01-17 02:43 560Kinect for Windows SDK beta 放出 ... -
Windows Mobile 6 SDK及中文版模拟器下载地址
2012-01-17 02:43 1495Windows Mobile 6 SDK及中文版模拟器下载地址 ... -
SDK 问题
2012-01-17 02:43 648SDK 问题 5小时前 问题:点击AVD Manager ... -
回顾日志_20110609
2012-01-15 22:20 465回顾日志_20110609 2011年06月09日 先来 ... -
笔记66-67
2012-01-15 22:19 591笔记66-67 2010年06月02日 ... -
FLEX网站收集
2012-01-15 22:19 882FLEX网站收集 2009年12月19日 1.FLEX网 ... -
ActionScript3.0 垃圾回收机制 2010-4-19 雨
2012-01-15 22:19 622ActionScript3.0 垃圾回收机制 2010-4-1 ... -
SNS网站设计的几大技术支持
2012-01-15 22:19 715SNS网站设计的几大技术支持 2010年04月04日 第 ...
相关推荐
VC,DELPHI外挂技术,驱动过保护,反汇编与逆向技术,Windows 程序设计 教会你写自己的外挂! 要求:有一定的编程基础(VC,DELPHI),即使不会也有基础课程 网站:www.zqsyr.com (知其所以然技术论坛)可以在...
kingiss temic rf V2版本的接口库
本書不教你如何使用Delphi整合環境,不講解Object Pascal,不是Win32基礎教學書籍,也不打算介紹COM/OLE/ADO等等新技術。...這本書的預設讀者群為,已脫離入門階段,對Windows SDK有基本認識的Delphi使用者。
Delphi XE8 iOS与Android移动应用开发(APP开发)[完整中文版],这是一本不可多得的介绍使用delphi xe8开发iOS与Android移动应用的电子书,实用的技术开发教程与技术开发手册。 Delphi XE8跨平台开发让你使用一套...
VC,DELPHI外挂技术,驱动过保护,反汇编与逆向技术,Windows 程序设计 教会你写自己的外挂! 要求:有一定的编程基础(VC,DELPHI),即使不会也有基础课程 网站:www.zqsyr.com (知其所以然技术论坛)可以在...
VC,DELPHI外挂技术,驱动过保护,反汇编与逆向技术,Windows 程序设计 教会你写自己的外挂! 要求:有一定的编程基础(VC,DELPHI),即使不会也有基础课程 网站:www.zqsyr.com (知其所以然技术论坛)可以在...
本书针对于具有Delphi编程基础并对Windows SDK有基本认识的使用者。 这是一本你从未见过的电脑技术书籍!一般技术书籍的焦点总是放在开发工具、程序语言、系统调用或最新技术上,即很少引导读者在拥有基本的程序...
本书针对于具有Delphi编程基础并对Windows SDK有基本认识的使用者。 这是一本你从未见过的电脑技术书籍!一般技术书籍的焦点总是放在开发工具、程序语言、系统调用或最新技术上,即很少引导读者在拥有基本的程序...
本书针对于具有Delphi编程基础并对Windows SDK有基本认识的使用者。 这是一本你从未见过的电脑技术书籍!一般技术书籍的焦点总是放在开发工具、程序语言、系统调用或最新技术上,即很少引导读者在拥有基本的程序...
因为本程序没有使用MFC,VCL等类库,用Windows SDK(Windows Software Development kit,即windows软件开发工具包)编写,可以说是在Windows下编程的最低层,也是windows程序的标准编写方式。相信本程序对理解在windows...
本绿色版包含了Windows SDK(MSDN 2001中的,含DirectX9),Windows DDK (2003 DDK版本),Visual C++(MFC和VC编译器等工具参考)。应该说包含了VC++编程所需要的所有MSDN内容。本版解压197M,可以放在U盘中运行。...
本书针对于具有Delphi编程基础并对Windows SDK有基本认识的使用者。 这是一本你从未见过的电脑技术书籍!一般技术书籍的焦点总是放在开发工具、程序语言、系统调用或最新技术上,即很少引导读者在拥有基本的程序...
支持语言:C/C++、VB、C#、Java、Delphi、Python、GoLang、Lua、易语言、火山等几乎所有编程语言,同时支持按键精灵、懒人精灵等脚本软件开发 可部署搭建在Windows、Linux等操作系统,支持宝塔、upupw、小皮等主流...
CLE(Common Language Extension)中间件支持多脚本语言混合编程。c/c++, lua, python, c#, ruby, java等语言可以通过CLE中间件直接使用其它语言中的类,函数,变量或者模块, 使得现有的功能库或者模块可以很容易的...
Windows核心编程(第五版)随书源代码 vc-ftp 多线程操作多文件传输的操作。 VC版下载者 源码 非常简单的一个实例,使用了URLDownloadToFile下载文件。 VC断点续传源代码 从fnMyDownload开始,程序首先解析输入的...
Windows核心编程(第五版)随书源代码 vc-ftp 多线程操作多文件传输的操作。 VC版下载者 源码 非常简单的一个实例,使用了URLDownloadToFile下载文件。 VC断点续传源代码 从fnMyDownload开始,程序首先解析输入的...
Windows核心编程(第五版)随书源代码 vc-ftp 多线程操作多文件传输的操作。 VC版下载者 源码 非常简单的一个实例,使用了URLDownloadToFile下载文件。 VC断点续传源代码 从fnMyDownload开始,程序首先解析输入的...
Windows核心编程(第五版)随书源代码 vc-ftp 多线程操作多文件传输的操作。 VC版下载者 源码 非常简单的一个实例,使用了URLDownloadToFile下载文件。 VC断点续传源代码 从fnMyDownload开始,程序首先解析输入的...
Windows核心编程(第五版)随书源代码 vc-ftp 多线程操作多文件传输的操作。 VC版下载者 源码 非常简单的一个实例,使用了URLDownloadToFile下载文件。 VC断点续传源代码 从fnMyDownload开始,程序首先解析输入的...