Как мне сделать мой код VBA совместимым с 64-битной Windows? - PullRequest
32 голосов
/ 01 апреля 2011

У меня есть приложение VBA, разработанное в Excel 2007, и оно содержит следующий код, позволяющий получить доступ к функции 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 мне нужно альтернативное решение.Какие у меня варианты?(Я бы действительно предпочел не выпускать две отдельные версии моего приложения, если это вообще возможно).

Однако, согласно приведенному ниже ответу Дэвида, я ошибся в обстоятельствах, при которых мой Declare заявление не будет работать.Единственные обстоятельства, при которых он не работает, это 64-разрядная версия Office 2010 в 64-разрядной версии Windows.Итак, Office 2007 не проблема.

Ответы [ 8 ]

55 голосов
/ 01 апреля 2011

Я уже сталкивался с этой проблемой на людях, использующих мои собственные инструменты на новых 64-разрядных компьютерах с Office 2010.

все, что мне нужно было сделать, это изменить строки кода следующим образом:

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.

code Appearance

Приложения, использующие приведенный выше код, прекрасно компилируются и работают в 32 и 64-разрядных версиях Office 2003, 2007 и 2010.

4 голосов
/ 02 ноября 2015

я нашел этот код (обратите внимание, что некоторые 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

4 голосов
/ 01 апреля 2011

Office 2007 только 32-битный, поэтому здесь нет проблем.Ваши проблемы возникают только с 64-разрядной версией Office, которая имеет 32- и 64-разрядную версии.

Вы не можете надеяться на поддержку пользователей с 64-разрядной версией Office 2010, когда у вас установлен только Office 2007. Решение - обновить.

Если единственное, что у вас есть Declare, это ShellExecute, то вам нечем будет заниматься, когда вы получите 64-битный Office, но на самом деле невозможно поддерживать пользователей, когда вы не можете запуститьПрограмма, которую вы отправляете!Подумайте, что бы вы сделали, когда они сообщат об ошибке?

3 голосов
/ 01 апреля 2011

Используйте PtrSafe и посмотрите, как это работает в Excel 2010.

Исправлена ​​опечатка из книги "Microsoft Excel 2010 Power Programming с VBA".

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

val (application.version)> 12.0 не будет работать, поскольку Office 2010 имеет 32- и 64-разрядные версии

2 голосов
/ 25 июня 2012

На самом деле, правильный способ проверки 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 по константам компилятора

0 голосов
/ 27 августа 2018

Эта работа для меня:

#If VBA7 And Win64 Then
    Private Declare PtrSafe Function ShellExecuteA Lib "Shell32.dll" _
        (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 ShellExecuteA Lib "Shell32.dll" _
        (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

Спасибо Jon49 за понимание.

0 голосов
/ 17 апреля 2018

Чтобы писать для всех версий Office, используйте комбинацию более новых условных констант компилятора VBA7 и Win64.

VBA7 определяет, выполняется ли код в версии 7 редактора VB (версия VBA, поставляемая в Office 2010+).

Win64 определяет, какая версия (32-битная или 64-битная) Office работает.

#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 .

0 голосов
/ 01 апреля 2011

Этот ответ, скорее всего, неверен в контексте .Я думал, что VBA теперь работает на CLR, но это не так.В любом случае этот ответ может быть полезен кому-то .Или нет.


Если вы запускаете Office 2010 32-разрядный режим, то он аналогичен Office 2007. («Проблема» - это Office, работающий в 64-разрядном режиме).Здесь важна разрядность контекста выполнения (VBA / CLR), а разрядность загруженного VBA / CLR зависит от разрядности хост-процесса.

Между 32/64-битными вызовами, наиболее заметнымвещи, которые идут не так, используют long или int (с постоянным размером в 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 является "РУЧКОЙ", которая равна void* / "void pointer"), а не long.См. pinvoke.net ShellExecute в качестве примера.(Хотя некоторые «решения» на pinvoke.net не очень удобны, на первый взгляд это хорошее место).

Удачное кодирование.


Что касается любого «нового синтаксиса», японятия не имею.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...