wParam与lParam的区别

摘要:
wParam和lParam之间的差异。lParam和wParam是宏定义。通常,这两种类型的参数在消息函数中用于存储窗口消息参数。在Win32 API中,原始的16位变量也扩展到32位,因此lParam和wParam的大小相同。在Win32API的早期,MS定义了两个宏,MPARAM和LPARAM,以确保代码与Win32API兼容。在MSDN网站上,WindowsDataTypes中有以下定义:LPARAM:Amessageparameter。此类型在Def中声明。如下:typedefLONG_PTRLPARAM;WPARAM:Amessageparameter.ThistypeiseclaredinDef。如下:typedefUINT_ PTRWPARAM;LPAR对于LONG_PTR(在win32上长)和__int64onx86_64.WPARAM是类型定义,对于UINT_PTR(在x86_64Inc#上长)是类型定义。在C#和C++之间的互操作中,可以使用IntPtr声明LPAR AM类型的变量,使用UIntPtr声明WPARAM类型的变量。当WPARAM、LPAR和LRESULT在32位和64位Windows系统中提供时会发生什么?

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所用自定义消息也在里面)的消息结构及定义

核心编程笔记---第一章
对于自己写的ErrorShow程序不足的地方的改进。

No.1

Edit_LimitText(GetDlgItem(hwnd,IDC_ERRORSHOW),8);限定Edit控件的输入长度
No.2
EnableWindow(GetDlgItem(hwnd, IDOK), Edit_GetTextLength(hwndCtl) > 0);
当EDIT控件什么也没有输入的时候,按钮不可用。
 
这两个算是小技巧。
下面是完整的代码:
#include <stdio.h>
#include <stdlib.h>
#include<windowsx.h>
#include <Windows.h>
BOOL  CALLBACK DlgErrorShow (HWND hwnd ,UINT message ,WPARAM wParam ,LPARAM lParam );
int WINAPI WinMain(HINSTANCE hInstance ,HINSTANCE hPrevInstance,PSTR szCmdLine ,int iCmdShow)
{
 
 DialogBox(hInstance,LPCTSTR(101),NULL,DlgErrorShow);
 
}
 
 
BOOL  CALLBACK DlgErrorShow (HWND hwnd ,UINT message ,WPARAM wParam ,LPARAM lParam )
{
 HLOCAL hlocal = NULL;
 DWORD dwError,systemLocale;
 BOOL fok;
 HMODULE hDLL;
 switch (message)
 {
 
 case WM_INITDIALOG:
  Edit_LimitText(GetDlgItem(hwnd,1001),8);
  break;
 case WM_COMMAND:
  switch (LOWORD(wParam))
  {
  case 1001:
   EnableWindow(GetDlgItem(hwnd, 1002), Edit_GetTextLength(GetDlgItem(hwnd,1001)) > 0);
   break;
  case 1002:
   dwError = GetDlgItemInt(hwnd,1001 ,NULL,FALSE);
   systemLocale = MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL);
   fok= FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER,NULL,dwError,systemLocale,(PTSTR)&hlocal,0,NULL);
   if (!fok)
   {
    hDLL = LoadLibraryEx(L"netmsg.dll",NULL,DONT_RESOLVE_DLL_REFERENCES);
    if (hDLL != NULL)
    {
     fok = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_IGNORE_INSERTS,hDLL,dwError,systemLocale,(PTSTR)&hlocal,0,NULL);
     FreeLibrary(hDLL);
    }
   }
   if (fok &&(hlocal != NULL))
   {
    SetDlgItemText(hwnd,1003,(PCTSTR)LocalLock(hlocal));
    LocalFree(hlocal);
   }
   else
   {
    SetDlgItemText(hwnd,1003,L"No text fount for this error number.");
   }
   break;
  }
 
  break;
 case WM_CLOSE:
     DestroyWindow(hwnd);
     break;
 }
   return 0 ;
}
 
 
FormatMessage函数:
FORMAT_MESSAGE_FROM_SYSTEM:希望获得一个系统定义的错误代码对应的字符串。
FORMAT_MESSAGE_ALLOCATE_BUFFER:要求函数分配一块足以容纳错误文本描述的内容。此块内存的句柄将返回到第5个参数中。
FORMAT_NEUTRAL|SUBLANG_NEUTRAL:操作系统的默认语言
 
 
核心编程--第二章
typedef  char CHAR
typedef wchar_t WCHAR
typedef CAHR *PCHAR
typedef CHAR *PSTR
typedef CONST CHAR *PCSTR 
typedf WCHAR *PWCHAR
typedf WCHAR *PWCHAR
typedef WCHAR *PWSTR
typedef CONST WCHAR *PCWSTR 
 
#ifdef UNICODE
typedef WCHAR TCHAR ,*PTCHAR,PTSTR
typedef CONST WCHAR *PCTSTR
#define _TEXT(quote) quote
#else
typedef CHAR TCHAR ,*PTCHAR,PTSTR;
typedef CONST CHAR *PCTSTR
#define _TEXT(quote) quote
#endif
#define TEXT(quote) _TEXT(quote)
C运行库中的Unicode函数和ANSI函数
_tcslen :strlen--wcslen  ---------返回字符串长度
 
_countof用啦计算啊一个静态分配的数组中的元素的个数 
sizeof用来计算字节数
 
eg
#include <Windowsx.h>
#include <tchar.h>
#include <Windows.h>
#include <errno.h>
int WINAPI _tWinMain(HINSTANCE hinsttExe ,HINSTANCE ,PTSTR szCmdLine ,int )
{
 TCHAR szBefore[5] = {L'B',L'B',L'B',L'B',L'

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇gulp几个常见问题及解决方案C# String小技巧下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

使用云开发数据库构建更生动的小程序

长连接服务被广泛应用在消息提醒、即时通讯、推送、直播弹幕、游戏等场景。本篇文章将介绍云开发数据库的长连接服务 - 实时数据推送,使用它来构建更生动的小程序。 什么是实时数据推送 通过云开发数据库的实时数据推送能力,小程序端可实时监听数据库变更,即它支持根据开发者给定的查询语句进行监听,每当查询语句的结果发生变化时,小程序端就会收到包含更新内容的推送,并对实...

iOS 数据持久化 NSUserDefault

每一个应用都有一个 NSUserDefaults 实例,向 NSUserDefaults 类发送 standardUserDefaults 消息可以得到该实例。 NSUserDefaults 实例类似与 NSMutableDictionary,可以通过键存取或删除该对象。 当应用第一次使用 NSUserDefaults 实例时,NSUserDefaults...

SpringBoot 2.x 整合Lombok

Lombok的官方介绍 Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java. Lombok以简单的注解形式来简化java代码,提高开发人员的开发效率 lombok是一个编译级别的插件,...

PreTranslateMessage作用和用法

PreTranslateMessage作用和用法 PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的,绝大多数本窗体的消息都要通过这里,比較经常使用,当须要在MFC之前处理某些消息时,经常要在这里加入代码. MFC消息控制流最具特色的地方是CWnd类的虚拟函数PreTranslateMessage()...

Subversion版本控制环境在Windows系统下的安装

转自:http://www.ibm.com/developerworks/cn/opensource/os-subversion/ 在Windows下安装最为方便的办法就是下载安装程序,你可以到下面这个地址下载最新的二进制压缩版本svn-win32-1.2.3.zip ,地址是: http://subversion.tigris.org/servlets/...

Java转码工具native2ascii

背景:在做Java开发的时候,常常会出现一些乱码,或者无法正确识别或读取的文件,比如常见的validator验证用的消息资源(properties)文件就需要进行Unicode重新编码。原因是java默认的编码方式为Unicode,而我们的计算机系统编码常常是GBK等编码。需要将系统的编码转换为java正确识别的编码问题就解决了。 1、native2asc...