32位和64位版本的Office2010之间的兼容性
32 位和 64 位版本的 Office 2010 之间的兼容性
Office 2010
摘要:针对处理 2GB 或更多数据的客户,Microsoft Office 2010 现在作为 64 位版本提供。本⽂讨论有关 32 位版本与新的 64 位版本和旧的 32 位 Office 应⽤程序之间兼容性的问题,并提供了相应的解决⽅案。(7 个打印页)
上次修改时间: 2015年4⽉24⽇
适⽤范围: Excel 2010 | Office 2007 | Office 2010 | Open XML | PowerPoint 2010 | SharePoint Server 2010 | VBA | Visual Basic for Applications 7.0 (VBA 7.0) | Word 2010
本⽂内容
Applies to:  Microsoft Office 2010
发布时间:2010 年 3 ⽉
供稿⼈:Microsoft Corporation
内容
Microsoft Office 2010 system 同时具有 32 位和 64 位版本。64 位版本使您能够处理更⼤的数据集。如果要在 Microsoft Excel 2010 中处理⼤量数字,则尤其需要使⽤此版本。
随着新的 64 位版本 Microsoft Office 2010 的引⼊,Microsoft 发布了称为 Microsoft Visual Basic for Applications 7.0 (VBA 7)的新版本的 Microsoft Visual Basic for Applications (VBA) 以同时处理 32 位和 64 位应⽤程序。需要特别注意的是,本⽂中介绍的更改只适⽤于 64 位版本的 Microsoft Office 2010。如果使⽤的是 32 位版本的 Office 2010,则可以不加修改地使⽤以前版本的Microsoft Office 中内置的解决⽅案。
在安装 Office 2010 时,默认安装的是 32 位版本,即使在 64 位系统上也是如此。您必须明确 选择 Office 2010 64 位版本安装选项。
在 VBA 7 中,必须更新现有 Windows 应⽤程序编程接⼝ (API) 语句(Declare 语句)才能处理 64 位版本。另外,还必须更新这些语句使⽤的⽤户定义类型中的地址指针和显⽰窗⼝句柄。本⽂将详细讨论这⼀点以及 32 位和 64 位版本的 Office 2010 之间的兼容性问题,并提供建议的解决⽅案。
使⽤ 64 位版本的 Office 2010 构建的应⽤程序可以引⽤更⼤的地址空间,因此提供了使⽤⽐以往更多的物理内存的机会,从⽽有可能减少将数据移⼊和移出物理内存所需的开销。
除了引⽤应⽤程序⽤于存储数据或存储编程指令的物理内存中的特定位置(⼜称为指针)外,还可以使⽤地址来引⽤显⽰窗⼝标识符(称
为句柄)。根据您使⽤的是 32 位系统还是 64 位系统,可确定指针或句柄的⼤⼩(以字节为单位)。
在使⽤ 64 位版本的 Office 2010 运⾏现有解决⽅案时存在两个基本问题:
Office 2010 中的本机 64 位进程⽆法加载 32 位⼆进制⽂件。在使⽤现有 Microsoft ActiveX 控件和现有加载项时,这被认为是⼀个常见问题,
VBA 以前不具有指针数据类型,因此,开发⼈员使⽤ 32 位变量来存储指针和句柄。但现在在使⽤ Declare 语句时,这些变量会截断API 调⽤返回的 64 位值。
VBA 7 是新的基本代码,取代了早期版本的 VBA。32 位和 64 位版本的 Office 2010 中均包含 VBA 7。它提供了两个条件编译常
量:VBA7 和 Win64。通过测试您的应⽤程序使⽤的是 VBA 7 还是以前版本的 VBA,VBA7 常量可帮助确保您的代码的后向兼容
性。Win64 常量⽤于测试代码是以 32 位还是 64 位形式运⾏的。下⽂将介绍这两个编译常量。
本⽂中的其他部分介绍了⼀些例外情况,当在应⽤程序的 64 位版本中加载⽂档时,该⽂档(还包括⼯作簿和演⽰⽂稿)中使⽤该应⽤程序的 32 位版本创建的宏也适⽤。
第三⽅及 Microsoft 提供的现有 32 位 ActiveX 控件与 64 位版本的 Office 2010 不兼容。对于 ActiveX 控件和 COM 对象,有三种可能的解决⽅案:
如果您有源代码,则可以⾃⼰⽣成 64 位版本,
您可以与供应商联系以获取更新版本,
也可以搜索其他解决⽅案。
Office 2010 中的本机 64 位进程⽆法加载 32 位⼆进制⽂件。这包括 MSComCtl 的常见控件(TabStrip、Toolbar、StatusBar、ProgressBar、TreeView、ListViews、ImageList、Slider、ImageComboBox)和 MSComCt2 的控件(Animation、UpDown、MonthView、DateTimePicker、FlatScrollBar)。这些控件以前由之前版本的 Microsoft Office 安装,现在由 32 位 Office 2010 安装。必须到现有 Microsoft Office VBA 解决⽅案的⼀种替代⽅法,以便在代码迁移到 64 位 Office 2010 后利⽤这些控件。64 位Office 2010 不提供常见控件的 64 位版本。
VBA 和类型库的结合为您提供了许多⽤于创建 Microsoft Office 应⽤程序的功能。不过,有时,您必须直接与计算机的操作系统及其他组件进⾏通信,例如在您管理内存或进程时,在使⽤⽤户界⾯(例如窗⼝和控件)时,或在修改 Windows 注册表时。在这些情况下,最好选择使⽤⼀个嵌⼊动态链接库 (DLL) ⽂件中的外部函数。为此,可在 VBA 中使⽤ Declare 语句进⾏ API 调⽤。
Declare 语句类似于以下代码之⼀,具体取决于您调⽤的是⼦例程(没有返回值)还是函数(有返回值)。
VBA
Public/Private Declare Sub SubName Lib "LibName" Alias "AliasName" (argument list)
Public/Private Declare Function FunctionName Lib "Libname" alias "aliasname" (argument list) As Type
SubName 函数或 FunctionName 函数会被替换为 DLL ⽂件中过程的实际名称,表⽰在从 VBA 代码调⽤过程时所使⽤的名称。如果需要,您还可以为过程名称指定 AliasName 参数。包含要调⽤的过程的 DLL ⽂件的名称位于 Lib 关键字之后。最后,参数列表将包含必须传递给该过程的参数和数据类型。
下⾯的 Declare 语句将打开 Windows 注册表中的⼀个⼦项 并替换其值。
VBA
Declare Function RegOpenKeyA Lib "advapi32.dll" (ByVal Key As Long, ByVal SubKey As String, NewKey As Long) As Long
RegOpenKeyA 函数的 Windows.h(窗⼝句柄)条⽬如下所⽰:
VBA
LONG RegOpenKeyA ( HKEY hKey, LPCSTR lpSubKey, HKEY *phkResult );
在 Microsoft Visual C 和 Microsoft Visual C++ 中,前⾯的⽰例对 32 位和 64 位都能够正确编译。这是因为 HKEY 定义为指针,其⼤⼩反映了在其中编译代码的平台的内存⼤⼩。
在以前版本的 VBA 中,没有特定指针数据类型,因此使⽤了 Long 数据类型,⽽ Long 数据类型始终为 32 位,所以它在具有 64 位内存的系统上使⽤时会发⽣中断,因为前 32 位可能被截断或可能覆盖其他内存地址。以上任⼀情况都会导致不可预测的⾏为或系统崩溃。
为解决此问题,VBA 现在包含真正的指针 数据类型 LongPtr。此新数据类型使您能够正确编写原始 Declare 语句,如下所⽰:
VBA
Declare PtrSafe Function RegOpenKeyA Lib "advapire32.dll" (ByVal hKey as LongPtr, ByVal lpSubKey As String, phkResult As LongPtr) As Long
此数据类型和新的 PtrSafe 属性使您能够在 32 位或 64 位系统上使⽤此 Declare 语句。PtrSafe 属性向 VBA 编译器指⽰ Declare 语句⾯向 64 位版本的 Office 2010。如果不使⽤此属性,那么在 64 位系统中使⽤ Declare 语句会导致编译时错误。请注意,PtrSafe 属性在 32 位版本的 Office 2010 上是可选的。这使现有 Declare 语句始终能够正常运⾏。
下表提供了有关已讨论过的新限定符和数据类型以及另⼀种数据类型、两个转换运算符和三个函数的详细信息。
项说明
PtrSafe指⽰ Declare 语句与 64 位兼容。此属性在 64 位系统上是必需的。
类型LongPtr
⼀种变量数据类型,在 32 位版本的 Office 2010 上是 4 字节数据类型,在 64 位版本上是 8 字节数据类型。这是
为新代码声明指针或句柄的推荐⽅法,但如果它必须运⾏在 64 位版本的 Office 2010 中,则也为旧代码声明指针或
句柄。只有 32 位和 64 位上的 VBA 7 运⾏时⽀持此数据类型。请注意,您可以为它赋予数值,但不能赋予数值类
型。
据类型LongLong
这是只能在 64 位版本的 Office 2010 中使⽤的 8 字节数据类型。您可以赋予数值,但不能赋予数值类型(以避免
截断)。
CLngPtr将简单表达式转换为 LongPtr 数据类型。
CLngLng将简单表达式转换为 LongLong 数据类型。
VarPtr变量转换器。在 64 位版本上返回 LongPtr,在 32 位版本上返回 Long(4 字节)。
ObjPtr对象转换器。在 64 位版本上返回 LongPtr,在 32 位版本上返回 Long(4 字节)。
StrPtr字符串转换器。在 64 位版本上返回 LongPtr,在 32 位版本上返回 Long(4 字节)。
下⾯的⽰例演⽰如何在 Declare 语句中使⽤其中某些项。
VBA
Declare PtrSafe Function RegOpenKeyA Lib "advapi32.dll" (ByVal Key As LongPtr, ByVal SubKey As String, NewKey As LongPtr) As Long
请注意,没有 PtrSafe 属性的 Declare 语句被假定为与 64 位版本的 Office 2010 不兼容。
如前所述,有两个新的条件编译常量:VBA7 和 Win64。为确保与以前版本的 Microsoft Office 的向后兼容性,可使⽤ VBA7 常量(这是较典型的情况)来防⽌ 64 位代码在早期版本的 Microsoft Office 中运⾏。对于在 32 位版本和 64 位版本之间有所不同的代码(例如调⽤数学 API,它对其 64 位版本使⽤ LongLong,对其 32 位版本使⽤ Long),可使⽤ Win64 常量。下⾯的代码演⽰如何使⽤这两个常量。
VBA
#if Win64 then
Declare PtrSafe Function MyMathFunc Lib "User32" (ByVal N As LongLong) As LongLong
#else
Declare Function MyMathFunc Lib "User32" (ByVal N As Long) As Long
#end if
#if VBA7 then
Declare PtrSafe Sub MessageBeep Lib "User32" (ByVal N AS Long)
#else
Declare Sub MessageBeep Lib "User32" (ByVal N AS Long)
#end if
总⽽⾔之,如果您编写 64 位代码并打算在以前版本的 Microsoft Office 中使⽤它,则需要使⽤ VBA7 条件编译常量。不过,如果您在Office 2010 中编写 32 位代码,则该代码的⼯作⽅式与在以前版本的 Microsoft Office 中⼀样,⽆需使⽤编译常量。如果希望确保对32 位版本使⽤ 32 位语句,对 64 位版本使⽤ 64 位语句,则最好选择使⽤ Win64 条件编译常量。
下⾯的代码是需要更新的旧 VBA 代码的⽰例。请注意旧代码中更新为使⽤ LongPtr 的数据类型,因为它们引⽤句柄或指针
旧 VBA 代码
VBA
Declare Function SHBrowseForFolder Lib "shell32.dll" _
Alias "SHBrowseForFolderA" (lpBrowseInfo As BROWSEINFO) As Long
Public Type BROWSEINFO
hOwner As Long
pidlRoot As Long
pszDisplayName As String
lpszTitle As String
ulFlags As Long
lpfn As Long
lParam As Long
iImage As Long
End Type
新 VBA 代码
VBA
#if VBA7 then    ' VBA7
Declare PtrSafe Function SHBrowseForFolder Lib "shell32.dll" _
Alias "SHBrowseForFolderA" (lpBrowseInfo As BROWSEINFO) As Long
Public Type BROWSEINFO
hOwner As LongPtr
pidlRoot As Long
pszDisplayName As String
lpszTitle As String
ulFlags As Long
lpfn As LongPtr
lParam As LongPtr
iImage As Long
End Type
#else    ' Downlevel when using previous version of VBA7
Declare Function SHBrowseForFolder Lib "shell32.dll" _
Alias "SHBrowseForFolderA" (lpBrowseInfo As BROWSEINFO) As Long
Public Type BROWSEINFO
visual basic pdf
hOwner As Long
pidlRoot As Long
pszDisplayName As String
lpszTitle As String
ulFlags As Long
lpfn As Long
lParam As Long
iImage As Long
End Type
#end if
Sub TestSHBrowseForFolder ()
Dim bInfo As BROWSEINFO
Dim pidList As Long
bInfo.pidlRoot = 0&
bInfo.ulFlags = &H1
pidList = SHBrowseForFolder(bInfo)
End Sub
下⾯是与 Microsoft Office 32 位版本和 64 位版本相关的常见问题。
何时应该使⽤ 64 位版本的 Microsoft Office?