wParam与lParam的区别
wParam与lParam的区别
lParam 和 wParam 是宏定义,一般在消息函数中带这两个类型的参数,通常用来存储窗口消息的参数。
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
wParam 通常用来存储小段信息,如,标志
lParam 通常用于存储消息所需的对象
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
typedef unsigned int UINT;
typedef long LONG;
typedef UINT WPARAM;
typedef LONG LPARAM;
lParam 和 wParam 是 Win16 系统遗留下来的产物,在 Win16 API 中 WndProc 有两个参数,一个 WORD 类型的 16 位整型变量,另一个是 LONG 类型的 32 位整型变量。根据匈牙利命名法(Hungarian notation),16 位的变量就被命名为 wParam,而 32 位的变量就被命名为 lParam。
到了 Win32 API 中,原来的 16 位变量也被扩展为 32 位,因此 lParam 和 wParam 的大小完全相同。在 Win32 API 的早期,为了保证和 Win16 API 的代码兼容,MS 定义了 MPARAM 和 LPARAM 两个宏。保留 w 前缀的原因一方面是由于 WPARAM 宏也以 W 开头,另一方面是希望提醒程序员注意到可移植性。到了现在,Win16 早已退出历史舞台,但是这个前缀仍然约定俗成的沿用了下来。
the history of WPARAM, LPARAM
Once upon a time, Windows was 16-bit. Each message could carry with it two pieces of data, called WPARAM and LPARAM. The first one was a 16-bit value ("word"), so it was called W. The second one was a 32-bit value ("long"), so it was called L.
You used the W parameter to pass things like handles and integers. You used the L parameter to pass pointers.
When Windows was converted to 32-bit, the WPARAM parameter grew to a 32-bit value as well. So even though the "W" stands for "word", it isn't a word any more. (And in 64-bit Windows, both parameters are 64-bit values!)
It is helpful to understand the origin of the terms. If you look at the design of window messages, you will see that if the message takes a pointer, the pointer is usually passed in the LPARAM, whereas if the message takes a handle or an integer, then it is passed in the WPARAM. (And if a message takes both, the integer goes in the WPARAM and the pointer goes in the LPARAM.)
“在Win 3.x中,WPARAM是16位的,而LPARAM是32位的,两者有明显的区别。因为地址通常是32位的,所以LPARAM 被用来传递地址,这个习惯在Win32 API中仍然能够看到。在Win32 API中,WPARAM和LPARAM都是32位,所以没有什么本质的区 别。Windows的消息必须参考帮助文件才能知道具体的含义。如果是你定义的消息,愿意怎么使这两个参数都行。但是习惯上,我们愿意使用LPARAM传 递地址,而WPARAM传递其他参数。”
在 MSDN 网站中关于 Windows Data Types 中有如下定义:
LPARAM: A message parameter. This type is declared in WinDef.h as follows: typedef LONG_PTR LPARAM;
WPARAM: A message parameter. This type is declared in WinDef.h as follows: typedef UINT_PTR WPARAM;
LPARAM is a typedef for LONG_PTR which is a long (signed 32-bit) on win32 and __int64 (signed 64-bit) on x86_64.
WPARAM is a typedef for UINT_PTR which is an unsigned int (unsigned 32-bit) on win32 and unsigned __int64 (unsigned 64-bit) on x86_64
(x86_64 is how Microsoft now refer to amd64)
In c#, you should use IntPtr for LPARAM and UIntPtr for WPARAM.
在 C# 与 C++ 的互操作中,可以使用 IntPtr 来声明 LPARAM 类型变量,使用 UIntPtr 来声明 WPARAM 类型的变量。
当 WPARAM, LPARAM 和 LRESULT 在 32 位和 64 位 Windows 系统中传递的时候会发生什么?
如果是从 64 位 Windows 系统到 32 位系统,那么只有一个选择:截断 truncation。
如果是从 32 位到 64 位,那么对 WPARAM 采用补零扩展(zero-extended),对 LPARAM 和 LRESULT 采用符号扩展 (sign-extended)。
扩展方式不同的原因主要是因为 WPARAM 被定义为 “字 (WORD)” 也就是 “UINT_PTR”,而 LPARAM 和 LRESULT 被定义为 “LONG”,也就是 "LONG_PTR"。
What happens to WPARAM, LPARAM, and LRESULT when the travel between 32-bit and 64-bit windows?
The integral types WPARAM, LPARAM, and LRESULT are 32 bits wide on 32-bit systems and 64 bits on 64-bit systems. What happens when a 32-bit process sends a message to a 64-bit window or vice versa ?
There's really only one choice when converting a 64-bit value to a 32-bit value: Truncation. When a 64-bit process sends a message to a 32-bit window, the 64-bit WPARAM and LPARAM values are truncated to 32 bits. Similarly, when a 64-bit window returns an LRESULT back to a 32-bit sender, the value is truncate.
But converting a 32-bit value to a 64-bit value includes a choice: Do you zero-extend or sign-extend?
The answer is obvious if you remember the history of WPARAM, LPARAM, and LRESULT or if you just look at the header file.
The WPARAM is zero-extend, while LPARAM and LRESULT are sign-extended.
If you remember that WPARAM used to be a WORD and LPARAM and LRESULT used to be LONG, then this follows from the fact that WORD is an unsigned type (therefore zero-extended) and LONG is a signed type (therefore sign-extend).
Even if you didn't know that, you could look it up in the header file.
typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;
typedef LONG_PTR LRESULT;
UINT_PTR is an unsigned type (therefore zero-extended) and LONG_PTR is a signed type (therefore sign-extended).
具体的消息表示
1. WM_PAINT消息,LOWORD(lParam)是客户区的宽,HIWORD(lParam)是客户区的高
2. 滚动条WM_VSCROLL或WM_HSCROLL消息,LOWORD(wParam)指出了鼠标对滚动条的操作。比如上、下、左、右、翻页、移动等。
3. 击键消息,有WM_SYSKEYDOWN、WM_SYSKEYUP、WM_KEYUP、WM_KEYDOWN,其中wParam是虚拟键代码,lParam是包含属于击键的其他信息。lParam消息参数分为6个域,有重复计数、环境代码、键的先前状态等。4. 字符消息WM_CHAR、WM_DEADCHAR、WM_SYSCHAR、WM_SYSDEADCHAR,lParam消息参数跟击键消息的lParam 消息参数内容相同,wParam参数是ANSI或Unicode字符代码
5. 客户区鼠标消息WM_LBUTTONDOWN、WM_LBUTTONUP、WM_RBUTTONDOWN、WM_RBUTTONUP、 WM_MBUTTONDOWN、WM_MBUTTONUP,lParam参数的低位是鼠标的客户区x坐标,高位是客户区y坐标。wParam参数是指示鼠标键及Shift和Ctrl键的状态。wParam&MK_SHIFT或MK_CTRL,如果返回TRUE就意味着有按下Shift或Ctrl 键。
6. 非客户区消息,wParam参数指明移动或者单击鼠标键的非客户区位置,以HT开头,lParam参数低位指出了鼠标所在屏幕坐标的x坐标,高位指出了鼠标所在屏幕坐标的y坐标。
7. 鼠标轮滚动消息,WM_MOUSEWHEEL消息,lParam将获得鼠标的屏幕位置(坐标),wParam参数的低位表明鼠标键和Shift与Ctrl 键的状态。wParam高位有一个“delta”值,该值可正可负,指出了滚轮导致屏幕滚动几行,120表示向上3行。
8. 计时器消息WM_TIMER,wParam参数等于计时器的ID值,lParam为0
9. 按钮子窗口的WM_COMMAND消息,wParam参数的低位是子窗口ID,高位是通知码, lParam参数是接收消息的子窗口的句柄。
10. 焦点消息,对于正在失去焦点的窗口,会收到WM_KILLFOCUS消息,其wParam参数是即将接收输入焦点的窗口的句柄。对于即将获取焦点的窗口,会收到WM_SETFOCUS消息,其wParam参数是正在失去焦点的窗口的句柄。
11. 编辑控制的WM_COMMAND消息,wParam参数的低位是子窗口ID,高位是通知码, lParam参数是子窗口句柄。
12. 列表框的WM_COMMAND消息,wParam参数的低位是子窗口ID,高位是通知码, lParam参数是子窗口句柄。
13. 菜单消息1,WM_INITMENU,wParam是主菜单句柄,lParam是0.
14. 菜单消息2,WM_MENUSELECT,菜单跟踪消息,指针移到菜单的某一些,就会发送这个消息给窗口过程,其wParam参数的低位是选中项菜单的 ID或者弹出式菜单的句柄,高位是选择标识,lParam参数是包含选中项的菜单句柄。
15. 菜单消息3,WM_INITMENUPOPUP,准备显示一个弹出式菜单时产生的消息,wParam参数是弹出式菜单的句柄,lParam的低位是弹出式菜单的索引,如果该菜单是系统菜单,那么高位是1,否则为0.
16. 菜单消息4,WM_COMMAND,选中菜单后产生,wParam低位是击中菜单的ID,高位是0,lParam参数也是0
17. 菜单消息5,WM_SYSCOMMAND,表示用户从系统菜单中选择一个启用的菜单项,其wParam参数是菜单的ID, lParam为0.如果该消息是由按鼠标产生的,那么lParam参数是鼠标的屏幕坐标。
18. 加速键消息,WM_COMMAND消息,wParam低位是加速键ID,高位是1, lParam是0.
19.控制项着色消息,WM_CTLCOLORBTN消息,wParam是按钮的设备描述表句柄,lParam是按钮的窗口句柄。
VC中的消息的分类有3种:窗口消息、命令消息和控件通知消息
控件通知消息,是指这样一种消息,一个窗口内的子控件发生了一些事情,需要通知父窗口。
通知消息只适用于标准的窗口控件如按钮、列表框、组合框、编辑框,以及Windows公共控件如树状视图、列表视图等。
例如,单击或双击一个控件、在控件中选择部分文本、操作控件的滚动条都会产生通知消息。
她类似于命令消息,当用户与控件窗口交互时,那么控件通知消息就会从控件窗口发送到它的主窗口。但是这种消息的存在并不是为了处理用户命令,而是为了让主窗口能够改变控件,例如加载、显示数据。
在WM_NOTIFY中,lParam中放的是一个称为NMHDR结构的指针。在wParam中放的则是控件的ID。
在WM_COMMAND中,lParam用来区分是命令消息还是控件通知消息:如果lParam为NULL,则这是个命令消息,否则lParam里面放的必然就是控件的句柄,是一个控件通知消息。对于wParam则是低位放的是控件ID,高位放的是相应的消息事件。
Delphi中的消息
消息是Windows发出的一个通知,它告诉应用程序某个事件发生了。在Delphi中,大多数情况下Windows的消息被封装在VCL的事件中,我们只需处理相应的VCL事件就可以了,但如果我们需要编写自己的控件、截获或过滤消息就必须深入研究Win32的消息处理机制。
在Delphi中消息以TMessage记录的方式定义。
打开Message.pas文件,我们可以看到Tmessage是这样定义的:
type
TMessage = packed record
Msg: Cardinal;
case Integer of
0: ( WParam: Longint;
LParam: Longint;
Result: Longint);
1: ( WParamLo: Word;
WParamHi: Word;
LParamLo: Word;
LParamHi: Word;
ResultLo: Word;
ResultHi: Word);
end;
windows是消息驱动的系统,系统为每一个程序(应该说进程)建立一个消息队列。
消息的组成:一个消息由一个消息名称(UINT),和两个参数(WPARAM,LPARAM)。
WPARAM常常代表一些控件的ID或者高位低位组合起来分别表示鼠标的位置,如果消息的发送者需要将某种结构的指针或者是某种类型的句柄时,习惯上用LPARAM来传递,
例如当菜单转中之后会有WM_COMMAND消息发送,WPARAM的低字中(LOWORD(wParam))是命令的ID号,对菜单来讲就是菜单ID。当然用户也可以定义自己的消息名称,也可以利用自定义消息来发送通知和传送数据。
一个消息必须由一个窗口接收。在窗口的过程(WNDPROC)中可以对消息进行分析,对自己感兴趣的消息进行处理。例如你希望对菜单选择进行处理那么你可以定义对WM_COMMAND进行处理的代码,如果希望在窗口中进行图形输出就必须对WM_PAINT进行处理。
未处理的消息到那里去了:微软为窗口编写了默认的窗口过程,这个窗口过程将负责处理那些你不处理消息。正因为有了这个默认窗口过程我们才可以利用Windows的窗口进行开发而不必过多关注窗口各种消息的处理。例如窗口在被拖动时会有很多消息发送,而我们都可以不予理睬让系统自己去处理。
每个窗口都会有自己的窗口过程,所以用户的输入就会被正确的处理。
例如有两个窗口共用一个窗口过程代码,你在窗口一上按下鼠标时消息就会通过窗口1的句柄被发送到窗口1而不是窗口2。
示例:下面有一段伪代码演示如何在窗口过程中处理消息
LONG yourWndProc(HWND hWnd,UINT uMessageType,WPARAM wP,LPARAM)
{
switch(uMessageType)
{//使用SWITCH语句将各种消息分开
case(WM_PAINT): doYourWindow(...);//在窗口需要重新绘制时进行输出 break;
case(WM_LBUTTONDOWN): doYourWork(...);//在鼠标左键被按下时进行处理 break;
default: callDefaultWndProc(...);//对于其它情况就让系统自己处理 break;
}
}
消息机制:系统将会维护一个或多个消息队列,所有产生的消息都回被放入或是插入队列中。
系统会在队列中取出每一条消息,根据消息的接收句柄而将该消息发送给拥有该窗口的程序的消息循环。
每一个运行的程序都有自己的消息循环,在循环中得到属于自己的消息并根据接收窗口的句柄调用相应的窗口过程。而在没有消息时消息循环就将控制权交给系统所以Windows可以同时进行多个任务。
下面的伪代码演示了消息循环的用法:
while(1) {
id=getMessage(...);
if(id == quit) break;
translateMessage(...);
}
当该程序没有消息通知时getMessage就不会返回,也就不会占用系统的CPU时间。
举我们选择菜单的例子,当选择了一个菜单项的时候,Windows向菜单所属的窗口发送WM_COMMAND消息;而用户按下了一个加速键的时候,windows向TranslateAccelerate函数指定的目标窗口发送WM_COMMAND消息。一般这两者对应的窗口都是主窗口,所以在主窗口中的窗口过程中集中处理WM_COMMAND消息,而不必考虑它究竟是菜单引发的还是加速键引发的。
WM_COMMAND消息的两个参数是这样定义的:
wParam的高位 =wNotifyCode ;通知码
wParam的低位 =wID ;命令ID
lParam = hwdCtl ;发送WM_COMMAND 消息的子窗口句柄,即谁发的该消息
除了菜单和加速键,WM_COMMAND 消息也可以由其他子窗口引发,如主窗口中的按钮或工具栏,还有你提到的系统托盘的鼠标事件等等,lParam参数指定了引发消息的子窗口句柄,对于菜单和加速键引发的WM_COMMAND消息,lParam的值为0。wParam参数的低16位是命令ID,也就是资源脚本文件中菜单项的命令ID或加速键的命令ID,高16位是通知码,菜单消息的通知码是0,加速键消息的通知码为1。
这只是菜单和加速键的定义。其他的消息可能与此不同,具体查资料吧。
perform是给自己发消息,所以同SendMessage或PostMessage的区别只在于少了第一个HWND参数,
perform(WM_MESG,WPARAM,LPARAM);
可以打开Messages.pas,参考DELPHI所用(不仅仅Windows标准消息,还有很多VCL所用自定义消息也在里面)的消息结构及定义
核心编程笔记---第一章
No.1
核心编程--第二章
int MultiByteToWideChar(
UINT CodePage, //CP_ACP代码页就实现了ANSI与Unicode之间的转换CP_UTF8代码页就实现了UTF-8与Unicode之间的转换
DWORD dwFlags, //一般为0
LPCSTR lpMultiByteStr, //指定要传的字符串
int cchMultiByte, //字符串长度,-1时自己计算长度
LPWSTR lpWideCharStr, //目的字符串
int cchWideChar //目的字符串长度
);
UINT CodePage,
DWORD dwFlags,
LPWSTR lpWideCharStr,
int cchWideChar,
LPCSTR lpMultiByteStr,
int cchMultiByte,
LPCSTR lpDefaultChar,
PBOOL pfUsedDefaultChar
);
值
|
意义
|
---|---|
HEAP_GENERATE_EXCEPTIONS
|
如果分配错误将会抛出异常,而不是返回NULL。异常值可能是STATUS_NO_MEMORY, 表示获得的内存容量不足,或是STATUS_ACCESS_VIOLATION,表示存取不合法。
|
HEAP_NO_SERIALIZE
|
不使用连续存取。
|
HEAP_ZERO_MEMORY
|
将分配的内存全部清零。
|
wParam与lParam的区别的更多相关文章
- SendMessage和PostMessage区别以及WPARAM 和 LPARAM区别
WPARAM 和 LPARAM wParam和lParam 这两个是Win16系统遗留下来的产物,在Win16API中WndProc有两个参数:一个是WORD类型的16位整型变量:另一个是LONG类型 ...
- LRESULT与wParam和lParam的问题
在微软vc提供的头文件中有定义在winnt.h中typedef long LONG;在windef.h中typedef LONG LRESULT; 所以LRESULT就是long,也就是长整形之所以取 ...
- WPARAM和LPARAM的含义
lParam 和 wParam 是宏定义,一般在消息函数中带这两个类型的参数,通常用来存储窗口消息的参数. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uM ...
- 自定义消息中如果需要定义WPARAM和LPARAM,该怎么使用和分配?
写Windows程序不可避免要使用自定义的消息,也就是从WM_USER开始定义的消息.在定义一个消息后,往往我们还要定义针对该消息的WPARAM甚至是LPARAM.WPARAM和LPARAM是什么,可 ...
- wParam和lParam两个参数到底是什么意思?
在Windows的消息函数中,有两个非常熟悉的参数:wParam,lParam. 这两个参数的字面意义对于现在的程序来说已经不重要了,因为它是16位系统的产物,为了保持程序的可移植性,就将它保存了下来 ...
- SendMessage()、WPARAM、LPARAM函数使用例子(转)
http://chujiaba.blog.163.com/blog/static/18991813720106209350592/ 2010-07-20 21:35:00| 分类: C | 标 ...
- 利用自定义消息处理函数的WPARAM或LPARAM参数传递指针
有自定义消息: #define WM_TEST WM_USER+121 消息处理函数: afx_msg void OnTest(WPARAM wParam,LPARAM lParam); 该消息是一个 ...
- WM_PAINT在微软官方定义中,wParam和lParam都没有使用,所以就被Delphi给重定义了这个消息,还增加了DC(Delphi可任意改写消息的结构)
LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); Parameters wParam ...
- 【转】各种消息下wParam及lParam值的含义
转载自:http://bbs.fishc.com/forum.php?mod=viewthread&tid=52668#lastpost 01.WM_PAINT消息 LOWORD(lParam ...
随机推荐
- js浮点数运算封装, 起因财务部分精确计算
目录 背景 具体代码 背景 项目中用到浮点数,Int 等 js中 Number类型比较多, 加上牵涉到财务软件, 前台js运算等. 有时候会出现精确度的问题 , 公共方法中有好事者写的方法. 此处拿来 ...
- IDEA非sbt下spark开发
创建非sbt的scala项目 引入spark的jar包 File->Project Structure->Libararies引用spark-assembly-1.5.2-hadoop2. ...
- ngModel缺省是by reference,
1) 缺省是 by reference, not value, ngModel, ngOptions等都一样 2) 如果要 track value 用 "track by", ...
- 基于Linux命令行KVM虚拟机的安装配置与基本使用
背景 由于生产环境的服务器并不会安装桌面环境,简单操作的图形化安装也不适合批量部署安装.因此,我还是更倾向于在命令下安装配置KVM虚拟机.结合了一些资料和个人使用的状况,我大致列出了一些基本和常用的使 ...
- js控制高度自适应,做到响应式
//9宫格布局 var prints=window.innerHeight-($('.header').height()+40);//屏幕去掉(头部高度+头部padding) $('.weui-gri ...
- [Unity算法]斜抛运动(变种)
之前的斜抛运动,如果运动到游戏中,显然是太呆板了,那么可以试着加入一些效果,让它看起来更生动一些,类似游戏中的击飞或者掉落效果: 1.在达到最高点的时间点±X的时间段内,会有“减速”效果,形成一种在空 ...
- C# sqlserver winform
//public static readonly string LocalSqlServer = System.Configuration.ConfigurationManager.AppSettin ...
- RPC通信原理
什么是 RPCRPC(Remote Procedure Call Protocol)远程过程调用协议.通俗的描述是:客户端在不知道调用细节的情况下,调用存在于远程计算上的某个过程或函数,就像调用本地应 ...
- python中import和from-import的区别
. import导入模块的路径两种方式 # 将模块所在路径再程序中添加到sys.path列表中 import sys sys.path import导入模块按照sys.path顺序依次查找,“”代表当 ...
- <面试> PHP 常见算法
排序算法 1. 冒泡排序(数组排序) 基本思想:对需要排序的数组从后往前(逆序)进行多遍的扫描,当发现相邻的两个数值的次序与排序要求的规则不一致时,就将这两个数值进行交换.这样每遍历一次,最小的数值就 ...