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

时间:2011-03-31 22:06:59

标签: excel vba 64-bit

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

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我需要一个替代解决方案。   我有什么选择? (我真的   不想发布2   如果我的应用程序的单独版本   尽可能。)

但是,根据大卫在下面的回答,我错误地认为我的Declare陈述不起作用的情况。它无法运行的唯一情况是Windows 64位上的Office 2010 64位。因此,Office 2007不是问题。

8 个答案:

答案 0 :(得分:53)

在使用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

To This:

#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块的第一部分。

code Appearance

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

答案 1 :(得分:4)

Office 2007仅为32位,因此没有问题。只有使用32位和64位版本的Office 64位才会出现问题。

当您只拥有Office 2007时,您无法支持使用64位Office 2010的用户。解决方案是升级。

如果您拥有的唯一DeclareShellExecute,那么一旦您获得64位Office,您就没有太多工作要做了,但是当您可以支持用户时,它真的不可行运行你发送的程序!试想一下他们报告错误时你会做什么?

答案 2 :(得分:4)

我找到了这段代码(请注意,有些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

答案 3 :(得分:2)

使用PtrSafe并查看Excel 2010的工作原理。

更正了“使用VBA进行Microsoft Excel 2010 Power Programming”一书中的拼写错误。

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

val(application.version)> 12.0 无效,因为Office 2010同时具有32位和64位版本

答案 4 :(得分:2)

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

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

来源:VBA帮助编译器常量

答案 5 :(得分:0)

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


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

在32/64位调用之间,出现问题的最明显的事情是使用longint(CLR中的常量大小)而不是IntPtr(基于位数的动态大小) )“指针类型”。

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”)而不是{{1 }}。请参阅pinvoke.net ShellExecute作为示例。 (虽然pinvoke.net上的一些“解决方案”是阴暗的,但最初看起来是个好地方。)

快乐的编码。


就任何“新语法”而言,我都不知道。

答案 6 :(得分:0)

要为所有版本的Office编写,请使用较新的VBA7和Win64条件编译器常量的组合。

VBA7确定代码是否在VB编辑器的第7版中运行(Office 2010+中提供的VBA版本)。

Win64确定正在运行的Office版本(32位或64位)。

#If VBA7 Then
'Code is running VBA7 (2010 or later).

     #If Win64 Then
     'Code is running in 64-bit version of Microsoft Office.
     #Else
     'Code is running in 32-bit version of Microsoft Office.
     #End If

#Else
'Code is running VBA6 (2007 or earlier).

#End If

有关详细信息,请参阅Microsoft Support Article

答案 7 :(得分:0)

为我工作:

function checkForm(frm){
  var inps = document.getElementsByName('user[]');
  console.log(inps );// but its displaying blank nodelist
}

感谢Jon49的见识。