我应该如何使我的VBA代码与64位Windows兼容?

我有一个在Excel 2007中开发的VBA应用程序,它包含以下代码以允许从Shell32.dll访问ShellExecute函数:

 Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long 

我原本说:

显然,该应用程序不会在64位版本的Windows上编译(仍然使用32位Office 2007)。 我认为这是因为Declare声明需要更新。

我读过Office 2010引入了一个新的VBA运行时(VB7),并且这个新的关键字可以在Declare语句中使用,以允许它在64位Windows上正常工作。 VB7还具有新的预定义编译器常量,以支持使用旧声明或新声明的条件编译,具体取决于应用程序是在32位还是64位Windows上运行。

但是,由于我坚持使用Office 2007,我需要一个替代解决scheme。 我有什么select? (如果可能,我真的不希望发布我的应用程序的2个独立版本)。

然而,根据David的回答,我错误地认为我的Declare声明不起作用的情况。 Office 64在Windows 64位上的唯一情况是不起作用的。 所以,Office 2007不是问题。

我已经在使用Office 2010的新型64位计算机上使用我的内部工具的人遇到过这个问题。

我所要做的就是改变这样的代码行:

 Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _ (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long 

为此:

 #If VBA7 Then Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _ (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long #Else Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _ (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long #End If 

你当然想要确保你使用的库在两台机器上都可用,但是到目前为止,我用过的一切都是问题。

请注意,在旧的VB6,PtrSafe甚至不是一个有效的命令,所以它会显示为红色,就好像你有一个编译错误,但它实际上不会给出错误,因为编译器将跳过第一部分if块。

代码外观

使用上述代码的应用程序可以在Office 2003,2007和2010 32和64位上完美编译和运行。

Office 2007只有32位,所以没有问题。 您的问题只出现在具有32位和64位版本的Office 64位上。

当您只有Office 2007时,您不能希望使用64位Office 2010支持用户。解决scheme是升级。

如果您唯一DeclareShellExecute那么一旦您获得了64位Office,就不会有太多的事情要做,但是当您无法运行您发布的程序时,支持用户并不是真正可行的! 试想一下,当他们报告错误时你会怎么做?

我发现这个代码(注意一些Long被改为LongPtr ):

 Declare PtrSafe Function ShellExecute Lib "shell32.dll" _ Alias "ShellExecuteA" (ByVal hwnd As LongPtr, ByVal lpOperation As String, _ ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As _ String, ByVal nShowCmd As Long) As LongPtr 

来源: http : //www.cadsharp.com/docs/Win32API_PtrSafe.txt

实际上,检查32位或64位平台的正确方法是使用在所有版本的VBA(16位,32位和64位版本)中定义的Win64常量。

 #If Win64 Then ' Win64=true, Win32=true, Win16= false #ElseIf Win32 Then ' Win32=true, Win16=false #Else ' Win16=true #End If 

来源:VBA帮助编译器常量

使用PtrSafe并查看Excel 2010如何工作。

更正了“Microsoft Excel 2010 Power Programming with VBA”一书中的错字。

 #If vba7 and win64 then declare ptrsafe function .... #Else declare function .... #End If 

val(application.version)> 12.0将不起作用,因为Office 2010同时具有32位和64位版本

这个答案可能是错误的上下文错误 。 我认为现在VBA现在在CLR上运行,但事实并非如此。 无论如何,这个回复可能对某人有用。 或不。


如果运行Office 2010 32位模式,则与Office 2007相同。(“问题”是Office以64位模式运行)。 这是执行上下文(VBA / CLR)的位,这在这里很重要,加载的VBA / CLR的位数取决于主进程的位数。

在32/64位调用之间,出错的最常见的事情是在“指针types”中使用longint (CLR中的常量大小)而不是IntPtr (基于位的dynamic大小)。

ShellExecute函数有一个签名:

 HINSTANCE ShellExecute( __in_opt HWND hwnd, __in_opt LPCTSTR lpOperation, __in LPCTSTR lpFile, __in_opt LPCTSTR lpParameters, __in_opt LPCTSTR lpDirectory, __in INT nShowCmd ); 

在这种情况下,重要的是HWND是IntPtr (这是因为HWND是一个“HANDLE”,它是void* /“void pointer”)并且不long 。 以pinvoke.net ShellExecute为例。 (虽然一些“解决scheme”在pinvoke.net上是阴暗的,但这是一个很好的起点)。

快乐的编码。


至于任何“新的语法”,我不知道。