wParam与lParam的区别

Posted 游子日月长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了wParam与lParam的区别相关的知识,希望对你有一定的参考价值。

wParam与lParam的区别


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‘\0‘};
 TCHAR szBuffer[10] = {L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘\0‘};
 TCHAR szAfter[5] = {L‘A‘,L‘A‘,L‘A‘,L‘A‘,L‘\0‘};
 errno_t resulr = _tcscpy_s(szBuffer,_countof(szBuffer),L"0123456789");
 return 0;
}
这个函数会造成溢出。下面是改进,但是还是会少一位。下面这个函数有截断作用。可以防止溢出
#include <Windowsx.h>
#include <tchar.h>
#include <Windows.h>
#include <errno.h>
#include <strsafe.h>
int WINAPI _tWinMain(HINSTANCE hinsttExe ,HINSTANCE ,PTSTR szCmdLine ,int )
{
 TCHAR szBefore[5] = {L‘B‘,L‘B‘,L‘B‘,L‘B‘,L‘\0‘};
 TCHAR szBuffer[10] = {L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘-‘,L‘\0‘};
 TCHAR szAfter[5] = {L‘A‘,L‘A‘,L‘A‘,L‘A‘,L‘\0‘};
 errno_t resulr = StringCchCopy(szBuffer,_countof(szBuffer),L"0123456789");
 return 0;
}
 
windows字符串函数:
CompareString 函数:
eg:
---------------------------------------------------------------------------------------------------------------------
#include <Windowsx.h>
#include <Windows.h>
#include <tchar.h>
#include <Shlwapi.h>
int WINAPI _tWinMain(HINSTANCE hinsttExe ,HINSTANCE ,PTSTR szCmdLine ,int )
{
 TCHAR val[] = L"xiaopao";
 TCHAR val2[] = L"xiao";
 LCID hcid ;
 hcid = GetThreadLocale();
 int k ;
 k = CompareString(hcid,NORM_IGNORECASE,val,_tcslen(val),val2,_tcslen(val2));
 if (k == 0 )
 {
  MessageBox(NULL,L"函数调用失败",L"Compare",MB_OK);
 }
  if (k == 1)
 {
  MessageBox(NULL,L"string1 < string2",L"Compare",MB_OK);
 }
  if(k == 2)
  {
   MessageBox(NULL,L"string1 = string2",L"Compare",MB_OK);
  }
 if ( k == 3 )
   MessageBox(NULL,L"string1 >string2",L"Compare",MB_OK);
 
 return 0;
}
---------------------------------------------------------------------------------------------------------------------
科普:
为什么要用UNICODE
1:UNICODE有利于应用程序的本地化
2:使用Unicode,只需发布一个二进制(.exe或DLL)文件,就可以支持所有语言
3:Unicode提升了应用程序的效率,因为代码执行速度更快,占用内存更少。Windows内部的一切工作都是使用Unicode字符和Unicode字符串,所以,假如我们坚持传入ANSI字符或字符串,Windows就会被迫分配内存,并将ANSI字符或字符串转换为等价的Unicode
4:使用Unicode,应用程序可以轻松调用所有尚未被弃用的Windows函数,因为一些windows函数提供的版本只能处理unicode字符和字符串
5:应用程序很容易与COM集成
6:应用程序很容易与.NET Framework集成
7:能保证应用程序的代码能够轻松操作我们自己的资源。
 
推荐的字符和字符串处理方式:
1:开始将文本字符串想象为字符的数组,而不是char或字节的数组
2:用通用数据类型(TCAHR/PTSTR)来表示文本字符和字符串
3:用明确的数据类型(如BYTE/PBYTE)来表示字节 字节、字节指针和数据缓冲区
4:用TEXT或_T宏来表示字面量字符和字符串,但为了保持一致性和更好的可读性,避免两者的混用
5:执行全局替换(PTSTR替换PSTR)
6:避免使用printf系列函数  应使用MultiByteToWideChar和WideCharToMultiByte
7:_countof()-->sizeof()           malloc(nCharacters*sizeof(TCHAR))  ----->malloc(nCharacters)
8:UNICODE与_UNICODE符号要么不定义,要么同时定义
 
 
字符串处理函数应该遵循的基本准则:
1:始终使用安全的字符串处理函数,eg后缀为_s的函数,或者是前缀为StringCch的函数
2:不要使用不安全的C运行库字符串处理函数,一般情况下,如果一个缓冲区处理函数的参数中不包括目标缓冲区的长度,那么我们就应该避免使用这样的函数,同时还应避免自己实现这样的函数
3:利用/GS和/RTCs编译器标志来自动检测缓冲区溢出
4:不要用Kernel32方法进行字符串处理
5:字符串比较CompareString CompareStringOrdinal 
 
多字节字符转换为宽字节字符
函数:

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 //目的字符串长度 
  );

eg:
---------------------------------------------------------------------------------------------------------------------
#include <Windowsx.h>
#include <tchar.h>
#include <Shlwapi.h>
int WINAPI _tWinMain(HINSTANCE hinsttExe ,HINSTANCE ,PTSTR szCmdLine ,int )
{
 char val[]="xiaopao";
 int k ;
 wchar_t * val2 ;
 
 k = MultiByteToWideChar(CP_ACP,0,val,-1,NULL,0);       //分配一块足以容纳转换后的Unicode字符串的内存
 val2 = new wchar_t[k*sizeof(wchar_t)+1];
 MultiByteToWideChar(CP_ACP,0,val,-1,val2,k);
 
 MessageBox(NULL,val2,L"Hello",MB_OK);
 
 return 0;
}
---------------------------------------------------------------------------------------------------------------------
 
宽字节字符转换为多字节字符
int WideCharToMultiByte(
    UINT CodePage, 
    DWORD dwFlags, 
    LPWSTR lpWideCharStr, 
    int cchWideChar, 
    LPCSTR lpMultiByteStr, 
    int cchMultiByte, 
    LPCSTR lpDefaultChar, 
    PBOOL pfUsedDefaultChar 
  );
---------------------------------------------------------------------------------------------------------------------
#include <Windowsx.h>
#include <tchar.h>
#include <Shlwapi.h>
int WINAPI _tWinMain(HINSTANCE hinsttExe ,HINSTANCE ,PTSTR szCmdLine ,int )
{
 TCHAR val[]=L"xiaopao";
 int k ;
 char * val2 ;
 TCHAR val3[20];
 k = WideCharToMultiByte(CP_ACP,0,val,-1,NULL,0,NULL,NULL);       //分配一块足以容纳转换后的Unicode字符串的内存
 val2 = new char[k+1];
 memset((void*)val2,0,sizeof(char)*(k+1));
 WideCharToMultiByte(CP_ACP,0,val,-1,val2,k,NULL,NULL);
 return 0;
}
---------------------------------------------------------------------------------------------------------------------
字符串的逆转---有中变量
---------------------------------------------------------------------------------------------------------------------
#include <Windowsx.h>
#include <tchar.h>
#include <Shlwapi.h>
PWSTR StringReverseW(PWSTR pWideCharStr ,DWORD  cchLength );
int WINAPI _tWinMain(HINSTANCE hinsttExe ,HINSTANCE ,PTSTR szCmdLine ,int )
{
 PWSTR val =  L"xiaopao";
 int k = 0 ;
 
 k =wcslen(val);
  StringReverseW(val,k);
 
 return 0;
}
 
PWSTR StringReverseW(PWSTR pWideCharStr, DWORD  cchLength)
{
 PWSTR pEndOfStr = pWideCharStr + wcsnlen_s(pWideCharStr, cchLength) - 1;
 PWSTR pResult = (WCHAR*)malloc(sizeof(WCHAR));
 WCHAR * p=pResult;
 wchar_t cCharT;
 int i = 0;
 int k = wcslen(pResult);
 while (cchLength)
 {
 
  pEndOfStr--;
  cchLength--;
  cCharT = *pEndOfStr;
  *p = cCharT;
  p++;
 }
 MessageBox(NULL, pResult, L"Hello", MB_OK);
 
 return pResult;
}
---------------------------------------------------------------------------------------------------------------------
字符串逆转--无中间变量
---------------------------------------------------------------------------------------------------------------------
#include <Windowsx.h>
#include <tchar.h>
#include <Shlwapi.h>
PWSTR StringReverseW(PWSTR pWideCharStr ,DWORD  cchLength );
int WINAPI _tWinMain(HINSTANCE hinsttExe ,HINSTANCE ,PTSTR szCmdLine ,int )
{
 PWSTR val =  L"xiaopao";
 int k = 0 ;
 
 k =wcslen(val);
  StringReverseW(val,k);
 
 return 0;
}
 
PWSTR StringReverseW(PWSTR pWideCharStr, DWORD  cchLength)
{
 PWSTR pEndOfStr = pWideCharStr + wcsnlen_s(pWideCharStr, cchLength) - 1;
 PWSTR pResult = (TCHAR*)malloc(cchLength*sizeof(TCHAR));
 wchar_t cCharT;
 int i = 0;
 int k = wcslen(pResult);
 while (cchLength)
 {
  pEndOfStr--;
  cchLength--;
  cCharT = *pEndOfStr;
  *pResult = cCharT;
  pResult++;
 
 }
 pResult--;
 pResult--;
 pResult--;
 pResult--;
 pResult--;
 pResult--;
 
 MessageBox(NULL, pResult, L"Hello", MB_OK);
 return pResult;
}
 
---------------------------------------------------------------------------------------------------------------------
多字节字符串的逆转
---------------------------------------------------------------------------------------------------------------------
//引入库文件
#include <Windowsx.h>
#include <tchar.h>
#include <Shlwapi.h>
 
//声明方法
BOOL StringReverseW(PWSTR pWideCharStr ,DWORD  cchLength );
BOOL StringReverseA(PSTR pMultiByteStr, DWORD  cchLength);
 
//调用
int WINAPI _tWinMain(HINSTANCE hinsttExe ,HINSTANCE ,PTSTR szCmdLine ,int )
{
 PSTR val =  "xiaopao";
 int k = 0 ;
 
 k =strlen(val);
 StringReverseA(val,k);
 return 0;
}
 
//实现
BOOL StringReverseW(PWSTR pWideCharStr, DWORD  cchLength)
{
 PWSTR pEndOfStr = pWideCharStr + wcsnlen_s(pWideCharStr, cchLength) - 1;
 PWSTR pResult = (WCHAR*)malloc(sizeof(WCHAR));
 WCHAR * p=pResult;
 wchar_t cCharT;
 int i = 0;
 int k = wcslen(pResult);
 while (cchLength)
 {
 
  pEndOfStr--;
  cchLength--;
  cCharT = *pEndOfStr;
  *p = cCharT;
  p++;
 }
 
 return TRUE;
}
BOOL StringReverseA(PSTR pMultiByteStr, DWORD  cchLength)
{
 PWSTR pWideCharStr ;
 int nLenOfWideCharStr ;
 BOOL fOk = FALSE;
 
 nLenOfWideCharStr =MultiByteToWideChar (CP_ACP,0,pMultiByteStr,cchLength,NULL,0);
 pWideCharStr = (PWSTR)HeapAlloc(GetProcessHeap(),0,nLenOfWideCharStr*sizeof(wchar_t));  
 
 if (pWideCharStr == NULL)
  return NULL;
 MultiByteToWideChar (CP_ACP,0,pMultiByteStr,cchLength,pWideCharStr,nLenOfWideCharStr);
 fOk = StringReverseW(pWideCharStr,cchLength);
 
 if (fOk)
 {
  WideCharToMultiByte(CP_ACP,0,pWideCharStr,cchLength,pMultiByteStr,(int)strlen(pMultiByteStr),NULL,NULL);
 
 }
 HeapFree(GetProcessHeap(),0,pWideCharStr);
 return TRUE;
}
---------------------------------------------------------------------------------------------------------------------
注:HeapAlloc它用来在指定的堆上分配内存,并且分配后的内存不可移动
LPVOID HeapAlloc(
HANDLE hHeap,
DWORD dwFlags,
SIZE_T dwBytes,
);
hHeap
要分配堆的句柄,可以通过HeapCreate()函数或GetProcessHeap()函数获得。
dwFlags
堆分配时的可选参数,其值可以为以下的一种或多种:
意义
HEAP_GENERATE_EXCEPTIONS
如果分配错误将会抛出异常,而不是返回NULL。异常值可能是STATUS_NO_MEMORY, 表示获得的内存容量不足,或是STATUS_ACCESS_VIOLATION,表示存取不合法。
HEAP_NO_SERIALIZE
不使用连续存取。
HEAP_ZERO_MEMORY
将分配的内存全部清零。
dwBytes
要分配堆的字节数。
 
 
 
 

 

以上是关于wParam与lParam的区别的主要内容,如果未能解决你的问题,请参考以下文章

WPARAM和LPARAM的含义

windows消息处理机制的消息内容

WM_COMMAND 和 WM_NOTIFY 的区别

wParam和lParam两个参数到底是什么意思?

WM???????????????Message????????????Lparam???WParam

WinAPI 中的菜单:我对 WM_COMMAND 使用 LPARAM 还是 WPARAM?