[VBA教程] 含API引用的VBA作品兼容64位系统的方法

用了office vba五年多了,很喜欢。自从微软有64系统后,发现以前很多作品无法正常运行了。
经过查阅office2010 vba开发人员参考手册,实用#if 语句进行有选择的编译。示例代码如下:

#If VBA7 Then
'定义窗体样式
Private Declare PtrSafe Function FindWindow Lib "user32" Alias _
    "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function SetWindowLong Lib "user32" Alias _
    "SetWindowLongA" (ByVal Hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
#Else
'定义窗体样式
Private Declare Function FindWindow Lib "user32" Alias _
    "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SetWindowLong Lib "user32" Alias _
    "SetWindowLongA" (ByVal Hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
#End If

经过以上处理,我的作品(主要是ppt和excel)在office2003、2007和2010版本、xp以上系统均可正常运行。

office2013未进行测试,我想应该也是可以的。


近期由于操作系统升级到64位,同时试用AutoCAD2014版本,原来的一些VBA程序运行上出了一些问题:

1) Declear声明语句无法正常运行。
    查了一些资料,发现可以使用Declare PtrSafe来代替原来的Declear以解决这个问题。如原来32位的:
Private Declare Function acedSetColorDialog Lib _
   "acad.exe" (color As Long, ByVal bAllowMetaColor _
   As Boolean, ByVal nCurLayerColor As Long) As Boolean
在64位系统中,需要写成:
Private Declare PtrSafe Function acedSetColorDialog Lib _
   "acad.exe" (color As Long, ByVal bAllowMetaColor _
   As Boolean, ByVal nCurLayerColor As Long) As Boolean

这样问题好象解决了,其实问题还没有解决,因为怎样让同一程序能够在32位系统和64位系统中兼容又是个问题。
当然,最终还是找到方法:



#If VBA7 ThenPrivate Declare PtrSafe Function acedSetColorDialog Lib _   "acad.exe" (color As Long, ByVal bAllowMetaColor _   As Boolean, ByVal nCurLayerColor As Long) As Boolean#ElsePrivate Declare Function acedSetColorDialog Lib _   "acad.exe" (color As Long, ByVal bAllowMetaColor _   As Boolean, ByVal nCurLayerColor As Long) As Boolean#End If


我们可以看到,这里用了一个系统变量“VBA7”,通过这个变量可以辨别VBA系统是否为VBA7,并通过这个判断来加载不同的语句。另外还有一个变量是“WIN64”,这个变量可以辨别系统是否为WIN64位系统,并通过它来加载不同的语句。

为什么这里用了VBA7而不是用WIN64变量呢,那是因为在2014版以前,虽然是Win64系统,但实际上VBA还是32位系统,Declear声明并不需要加上PtrSaft,所以通过VBA7来着判断会更为准确。

有个不完美的地方是,VBA7中对于没有加入PtrSaft的Declear的代码都标注为有误并显示红色,不过还好,显示归显示,运行还是给运行的,因为通过前面的判断语句,那句错误的语句并不会运行到,所以运行时不会出错。
以上解决方法具体说明链接:http://bbs.mjtd.com/thread-100890-1-1.html

2) 数据库连接ADO以及DAO方式都无法使用。
这项问题到目前找不到解决方案,还在找,不过象我的那个塑料公差标注程序,原来用了ACCESS数据库,由于VBA7是真64位,那些32位的数据库连接方式都彻底失效,而微软又没有针对64位出数据库连接方式(目前还未搜索到),所以只能改成非数据库方式运行,把数据全部变成字符串并通过split转成数组保存并在程序中定位调用,由于数据量少,影响不大。
等找到方法解决后,再跟大家分享。



<think>好的,我现在需要帮助用户解决在64VBA中正确声明API以调用Excel函数的问题。首先,我要回顾用户之前的提问和我的回答,确保信息一致。用户之前询问过如何在Access VBA中调用Excel函数,现在转向了API声明的部分,特别是64环境下的注意事项。 用户提供的引用内容提到了在VBA中调用Windows API方法,包括使用Declare语句和Alias关键字,以及64兼容性的问题。引用[3]展示了如何通过条件编译来区分VBA7(64)和旧版本,使用PtrSafe关键字。引用[4]提到在声明API时参数处理,尤其是字符串类型的注意事项。 首先,我需要明确用户的问题:如何在64VBA中正确声明API函数以便调用Excel函数。这可能涉及两个方面:正确声明Windows API函数以便与Excel交互,或者调用Excel自身的API函数。根据用户之前的关注点,应该是前者,即如何在64VBA中声明Windows API以便辅助调用Excel函数,比如处理窗口消息、文件操作等,从而间接支持Excel函数的调用。 接下来,我需要整理64VBA声明API的关键点。根据引用[3]和[4],主要要注意以下几点: 1. 使用PtrSafe关键字:64VBA必须使用Declare PtrSafe Function/Sub,确保指针和句柄参数兼容。 2. 参数类型调整:将Long改为LongPtr,以支持64内存地址。例如,hWnd参数在32下是Long,在64下是LongPtr。 3. 条件编译:使用#If VBA7 Then来区分64和32环境,确保代码在不同版本中的兼容性。 4. 字符串处理:声明API时,避免定长字符串参数,使用ByVal传递字符串,防止类型不匹配。 此外,用户可能希望了解如何将这些API声明应用到调用Excel函数的场景中。例如,使用API函数来操作Excel窗口,或者处理Excel进程等。需要举例说明如何正确声明并调用相关API,同时结合Excel对象模型。 同时,要注意用户可能在混合使用API调用和Excel对象模型时遇到的常见错误,例如参数类型不匹配、未正确释放资源等,需要给出错误处理的建议,如使用On Error语句,以及如何调试API声明的问题。 最后,确保回答结构清晰,分步骤说明,并提供示例代码,如声明MessageBoxA函数,或者查找Excel窗口句柄的API函数,并展示如何在VBA中使用这些声明来辅助调用Excel函数。同时,强调释放资源和兼容性处理的重要性,避免内存泄漏或崩溃。 可能还需要对比3264声明的不同,帮助用户理解改动的原因。例如,将Declare Function改为Declare PtrSafe Function,Long变为LongPtr,以及使用条件编译确保代码在不同环境下的正确性。 需要验证示例代码的正确性,确保语法正确,比如正确的Lib名称、参数类型,以及正确的别名使用。例如,MessageBoxA在user32.dll中的声明,是否在64系统下路径正确,是否需要使用Alias处理不同的字符集(如MessageBoxW和MessageBoxA的区别)。 总结回答的结构应该是: 1. 64VBA声明API的核心要求:PtrSafe、LongPtr、条件编译。 2. 具体示例(如MessageBox、查找窗口句柄等)。 3. 调用Excel函数时的结合应用示例。 4. 常见错误及处理。 5. 兼容性建议。 需要确保回答覆盖用户可能遇到的问题,如编译错误、运行时错误、参数传递问题等,并参考之前提供的引用内容,尤其是关于字符串处理和别名使用的部分。</think>在64VBA环境中正确声明API函数需遵循以下核心规范,结合Excel函数调用的实际需求,具体实现如下: --- ### 一、64API声明核心要点 1. **`PtrSafe`关键字强制声明** 所有API声明必须包`PtrSafe`,否则在64Office中会引发编译错误: ```vba #If VBA7 Then Declare PtrSafe Function ... '64声明 #Else Declare Function ... '32声明(兼容旧版本) #End If ``` 2. **指针类型转换** 将涉及内存地址的参数(如窗口句柄)从`Long`改为`LongPtr`: ```vba '32声明 Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long '64修正 #If VBA7 Then Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr #End If ``` 3. **字符串参数处理** 使用`ByVal`传递字符串,避免定长字符串(引用[4]): ```vba '错误方式:定长字符串参数 Declare PtrSafe Function BadExample Lib "user32" (sText As String * 256) As LongPtr '正确方式:变长字符串 Declare PtrSafe Function GoodExample Lib "user32" Alias "MessageBoxA" (ByVal hWnd As LongPtr, ByVal lpText As String, ByVal lpCaption As String, ByVal uType As Long) As Long ``` --- ### 二、调用Excel函数的典型场景 #### 场景1:通过API获取Excel窗口句柄 ```vba #If VBA7 Then Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" ( _ ByVal lpClassName As String, _ ByVal lpWindowName As String) As LongPtr #Else Declare Function FindWindow Lib "user32" Alias "FindWindowA" ( _ ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long #End If Sub ControlExcelWindow() Dim hWnd As LongPtr '获取Excel主窗口句柄(假设窗口标题为"Book1 - Excel") hWnd = FindWindow(vbNullString, "Book1 - Excel") If hWnd <> 0 Then '可在此调用其他API操作窗口(如最大化/最小化) MsgBox "成功定Excel窗口" End If End Sub ``` #### 场景2:API辅助Excel数据处理 ```vba #If VBA7 Then Declare PtrSafe Function CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _ ByVal Destination As LongPtr, _ ByVal Source As LongPtr, _ ByVal Length As Long) As LongPtr #End If Sub FastArrayProcessing() Dim arrData() As Variant arrData = Range("A1:C100").Value '从Excel读取数据 '使用API进行内存操作(例如数据加密/压缩) '...(需配合具体算法实现) '将处理后的数据写回Excel Range("D1:F100").Value = arrData End Sub ``` --- ### 三、常见错误与调试 | 错误类型 | 解决方案 | |-----------------------|--------------------------------------------------------------------------| | **错误48:DLL加载失败** | 检查DLL路径是否正确,确认系统目录中存在`user32.dll`、`kernel32.dll`等文件 | | **错误453:函数未找到** | 检查`Alias`名称是否与DLL导出函数完全一致(区分大小写) | | **内存访问冲突** | 确保`LongPtr`用于指针参数,避免32/64类型混淆 | --- ### 四、性能与安全建议 1. **减少跨进程调用** 优先通过Excel对象模型(如`Range.Value`)直接操作数据,避免频繁API调用。 2. **指针操作防护** 使用`CopyMemory`等内存操作API时,需严格验证内存地址,防止越界访问。 3. **释放资源** API创建的句柄或内存块必须显式释放: ```vba #If VBA7 Then Declare PtrSafe Function GlobalFree Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr #End If ``` --- ### 五、完整示例:API+Excel函数混合调用 ```vba '64API声明 #If VBA7 Then Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" ( _ ByVal hWnd As LongPtr, _ ByVal lpString As String, _ ByVal cch As Long) As Long #End If Sub GetExcelWindowTitle() Dim excelApp As Object Set excelApp = CreateObject("Excel.Application") excelApp.Visible = True excelApp.Workbooks.Add '通过API获取窗口标题 Dim hWnd As LongPtr, title As String * 255 hWnd = excelApp.Hwnd '获取Excel窗口句柄 GetWindowText hWnd, title, 255 '调用Excel函数验证 excelApp.Range("A1").Value = "当前窗口标题:" & Left(title, InStr(title, vbNullChar) - 1) excelApp.Quit Set excelApp = Nothing End Sub ``` ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值