本帖最后由 ivccav 于 2023-3-17 16:59 编辑
64位API声明,虽然没有技术含量,但还是有很多童鞋不太了解,因此我花了点时间撸点文字,希望能对需要的人有所帮助。
从Office 2010开始,分32位和64位两个版本可供安装,同时VBA6升级到VBA7。Office2010之前的版本只有32位,没有64位。
在32位平台上的API函数中指针和句柄都是32位,由于VBA6和早期版本中没有指针或句柄的特定数据类型,
可使用Long数据类型(4字节)代表指针和句柄,相安无事。
但到了64位环境,指针和句柄升级到64位(8字节),64位数据无法保存在32位数据类型中,
当64位API函数使用或者返回指针和句柄时,会被截断,造成的后果是内存溢出、代码异常,甚至应用程序崩溃。
为了解决此问题,并使VBA代码能够在32位和64位环境中都能正常工作,
VBA7中新增了2种数据类型LongPtr和LongLong ,和一个声明关键字PtrSafe:
LongPtr:指针数据类型。LongPtr会根据Office版本进行不同解析,32位版本的Office中解析为Long,64位版本的Office中解析为LongLong。
LongPtr只能用于VBA7中(Office2010开始VBA版本才升级到VBA7),用来代表指针和句柄。
LongLong:带符号的64位整数。该数据类型只能在64位版本的Office中使用。在需要使用非常巨大的数据时可使用 LongLong类型。
PtrSafe:指针安全关键字。PtrSafe关键字只能用在Declare声明语句中。
说是指针安全,但并不会真的安全,API函数中所有64位的参数和接收返回值,都必须重新定义为64位。
以上3个新功能无法在VBA6及其之前版本中使用。
想要代码在32位和64位环境下通用,可以使用条件编译。
条件编译的语法和if语句一样,只在if、else、elseif和end if关键字前面加“#”,下面举例说明:
先看一段代码:
#If VBA7 Then
Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hwnd As LongPtr) As Long
#Else
Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
#EndIf
关键字前面带“#”,表示条件编译,VBA7是编译常数。
这段代码的意思是,如果VBA版本是VBA7,编译Declare PtrSafe Function...语句块,否则编译Declare Function语句块。
特别强调的是,VBA7常数不代表Office版本是32位或64位,仅仅指示VBA的版本是第7版。
在VBA7中,LongPtr数据类型可自动解析为32位和64位数据类型,这取决于安装的Office版本。
例子中hwnd是句柄,定义为LongPtr,VBA7会根据Office版本自动解析为32位或者64位数据类型。
因为LongLong只能用在64位Office版本中,如果需要使用该数据类型,
使用#If VBA7 And Win64 Then(当VBA7和Win64都为True时,才能确定Office是64位版本),如:
#if VBA7 then ' 运行在VBA7中,可能是32位或64位
Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hwnd As LongPtr) As Long
#if Win64 then ' 运行在64位Office
Dim i As LongLong
#else ' 运行在32位Office
Dim i As Long
#end if
#else ' 运行在VBA6及其之前版本,只有32位
Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
#end if
条件编译可用于代码的任何位置,甚至是函数或过程中:
#If VBA7 Then
Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hwnd As LongPtr) As Long
Declare PtrSafe Function GetClipboardData Lib "user32" Alias "GetClipboardDataA" (ByVal wFormat As Long) As LongPtr
#Else
Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Declare Function GetClipboardData Lib "user32" Alias "GetClipboardDataA" (ByVal wFormat As Long) As Long
#End If
Const CF_BITMAP = 2&
Sub test()
#If VBA7 Then
Dim hBmp As LongPtr
#Else
Dim hBmp As Long
#End If
If OpenClipboard(0) Then
hBmp = GetClipboardData(CF_BITMAP)
End If
End Sub
注意上例中,GetClipboardData函数返回一个剪贴板上的位图句柄,需要根据不同Office版本,定义接收参数hBmp,hBmp存放句柄。
无论是API或函数的返回值,还是API或者自定义函数的参数,只要是64位数据类型,如句柄或指针,都需要重新定义,否则程序运行会异常。
所以需要了解API函数的参数或者返回值是什么,才能定义恰当的数据类型进行传递或接收。这可以查询互联网了解函数参数,也可以用API浏览。
我之前上传了一个API Viewer,方便大家写API声明,需要的可下载:
https://club.excelhome.net/thread-1424969-31-1.html
301,302楼