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

核心编程笔记---第一章

对于自己写的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''};
 TCHAR szBuffer[10] = {L'-',L'-',L'-',L'-',L'-',L'-',L'-',L'-',L'-',L''};
 TCHAR szAfter[5] = {L'A',L'A',L'A',L'A',L''};
 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''};
 TCHAR szBuffer[10] = {L'-',L'-',L'-',L'-',L'-',L'-',L'-',L'-',L'-',L''};
 TCHAR szAfter[5] = {L'A',L'A',L'A',L'A',L''};
 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
要分配堆的字节数。
 
 
 
 
原文地址:https://www.cnblogs.com/yzryc/p/6404621.html