数据对齐问题引发的API调用失败

数据对齐问题引发的Win64 API调用失败

在Win32中,数据对齐并不是很严格,但在Win64中对数据对齐有严格的要求,若不符合要求,则调用API将失败。以下通过3个例子来说明一些容易忽视的问题。

例1. Unicode字符串的对齐问题

在Win64中,如果要创建一个Unicode的控件,则控件的类名和标题名必须进行偶字节(2、4、8)对齐,如下所示。如果不进行偶字节对齐(如下面无align 2 句子),则控件创建将失败,但在Win32位中是可以的。

 .data
 db 1,2,3
 align 2   ;2字节对齐
 ctr_btn_calssW dw "B","U","T","T","O","N",0
 ctr_btn_title  dw "T","i","t","l","e",0

 .code

 invoke CreateWindowExW,0,ADDR ctr_btn_calssW,\
                          ADDR ctr_btn_title, \
                          WS_CHILD or WS_VISIBLE,\
                          10,10,80,24,\
                          hWin,100,hInstance,NULL

例2: 结构的对齐问题

我们经常调用SHFileOperation函数来操作文件,如文件的复制、移动等。该函数要使用一个SHFILEOPSTRUCT结构,它在Win32中的定义如下:

SHFILEOPSTRUCT STRUCT
   hwnd                   DWORD ?
   wFunc                  DWORD ?
   pFrom                  DWORD ?
   pTo                    DWORD ?
   fFlags                 WORD ?
   fAnyOperationsAborted  DWORD ?
   hNameMappings          DWORD ?
   lpszProgressTitle      DWORD ?
SHFILEOPSTRUCT ENDS

如果我们要在Win64中使用SHFileOperation函数,则需将SHFILEOPSTRUCT结构修改为以下格式:

SHFILEOPSTRUCT STRUCT QWORD
   hwnd                   HWND ?
   wFunc                  DWORD ?
   pFrom                  QWORD ?
   pTo                    QWORD ?
   fFlags                 WORD ?
   fAnyOperationsAborted  DWORD ?
   hNameMappings          QWORD ?
   lpszProgressTitle      QWORD ?
SHFILEOPSTRUCT ENDS

即Win64中,结构必须进行8字节(QWORD)对齐,否则SHFileOperation函数将失败。

在Win64中,有些结构的定义起始行中并没有QWORD对齐选项,这是因此采用了填充字节来实现8字节对齐。

如LOGFONT结构在Win32中的定义格式如下:

LOGFONT STRUCT
  lfHeight          DWORD     ?
  lfWidth           DWORD     ?
  lfEscapement      DWORD     ?
  lfOrientation     DWORD     ?
  lfWeight          DWORD     ?
  lfItalic          BYTE      ?
  lfUnderline       BYTE      ?
  lfStrikeOut       BYTE      ?
  lfCharSet         BYTE      ?
  lfOutPrecision    BYTE      ?
  lfClipPrecision   BYTE      ?
  lfQuality         BYTE      ?
  lfPitchAndFamily  BYTE      ?
  lfFaceName        BYTE LF_FACESIZE dup(?) ;32字节
LOGFONT ENDS

在Win64中的定义格式如下:

LOGFONT STRUCT
  lfHeight          DWORD     ?
  lfWidth           DWORD     ?
  lfEscapement      DWORD     ?
  lfOrientation     DWORD     ?
  lfWeight          DWORD     ?
  lfItalic          BYTE      ?
  lfUnderline       BYTE      ?
  lfStrikeOut       BYTE      ?
  lfCharSet         BYTE      ?
  lfOutPrecision    BYTE      ?
  lfClipPrecision   BYTE      ?
  lfQuality         BYTE      ?
  lfPitchAndFamily  BYTE      ?
  lfFaceName        BYTE LF_FACESIZE dup(?) ;32字节
                    BYTE 4 dup(?)
LOGFONT ENDS

即在Win64中,LOGFONT结构的定义起始行中并没有QWORD对齐选项,而是在最后使用4字节填充字节,使结构的字节长度为64(8的整倍数),来实现8字节对齐。

例3: 结构成员的数据类型变化问题

我们常通过NM_CUSTOMDRAW通知,对一些控件的某些内容进行自定义绘制,在处理NM_CUSTOMDRAW通知时要对NMCUSTOMDRAW结构进行操作。该结构在Win32位中定义如下:

NMCUSTOMDRAW STRUCT
  hdr               NMHDR  <>
  dwDrawStage       DWORD  ?
  hdc               DWORD  ?
  rc                RECT  <>
  dwItemSpec        DWORD  ? ;注意该成员
  uItemState        DWORD  ?
  lItemlParam       DWORD  ?
NMCUSTOMDRAW ENDS

在Win64中,我们可能会想当然地将该结构定义为如下形式:

NMCUSTOMDRAW STRUCT QWORD
  hdr               NMHDR  <>
  dwDrawStage       DWORD  ?
  hdc               QWORD  ?
  rc                RECT  <>
  dwItemSpec        DWORD  ? ;注意该成员
  uItemState        DWORD  ?
  lItemlParam       QWORD  ?
NMCUSTOMDRAW ENDS

在Masm64的Win64.inc文件中,NMCUSTOMDRAW结构的定义就是上述这个样子的,结果是控件的绘制总是失败。原因是因为在Win64中dwItemSpec成员已修改为QWORD类型。

总结:

(1)在Win64环境下,如果遇到API调用失败,首选要检查参数是否正确,再检查数据的对齐问题。

(2)编程环境所提供的头文件中的个别结构定义不一定是正确的,需要查阅最新的API文档以确认。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值