web-dev-qa-db-fra.com

Comment dois-je rendre mon code VBA compatible avec Windows 64 bits?

J'ai une application VBA développée dans Excel 2007 et qui contient le code suivant pour permettre l'accès à la fonction ShellExecute à partir de 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

J'ai d'abord dit:

Apparemment, l'application ne le fera pas compiler sur une version 64 bits de Windows (toujours en utilisant Office 2007 32 bits). JE supposons que c'est parce que le La déclaration Declare doit être mise à jour.

J'ai lu l'introduction d'Office 2010 un nouveau runtime VBA (VB7), et que cela a de nouveaux mots-clés qui peuvent être utilisés dans l'instruction Declare pour l'autoriser pour fonctionner correctement sous Windows 64 bits . VB7 a également un nouveau compilateur prédéfini constantes à prendre en charge conditionnel compilation où soit l'ancien ou nouvelle déclaration sera utilisée, en fonction de l'application fonctionne sous Windows 32 ou 64 bits.

Cependant, depuis que je suis coincé avec Office 2007 J'ai besoin d'une solution alternative . Quelles sont mes options? (Je préférerais vraiment Ne pas avoir à publier 2 Versions séparées de mon application si Dans la mesure du possible).

Cependant, selon la réponse de David ci-dessous, je me suis trompé sur les circonstances dans lesquelles ma déclaration Declare ne fonctionnera pas. Les seules circonstances dans lesquelles cela ne fonctionnera pas sont Office 2010 64 bits sur Windows 64 bits. Ainsi, Office 2007 n'est pas un problème.

29
Gary McGill

J'ai déjà rencontré ce problème sur des personnes utilisant mes outils internes sur de nouvelles machines 64 bits avec Office 2010.

tout ce que je devais faire était de changer les lignes de code comme ceci:

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

Pour ça:

#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

Vous voudrez bien sûr vous assurer que la bibliothèque que vous utilisez est disponible sur les deux machines, mais jusqu'à présent, rien de ce que j'ai utilisé n'a posé de problème.

Notez que dans l’ancien VB6, PtrSafe n’est même pas une commande valide. Il apparaît donc en rouge comme si vous aviez une erreur de compilation, mais cela ne produira jamais une erreur car le compilateur ignorera la première partie le bloc if.

code Appearance

Les applications utilisant le code ci-dessus se compilent et fonctionnent parfaitement sous Office 2003, 2007 et 2010 32 bits et 64 bits.

51
Alain

Office 2007 est uniquement en version 32 bits, il n'y a donc aucun problème. Vos problèmes ne se posent qu’avec Office 64 bits, qui comporte à la fois des versions 32 et 64 bits.

Vous ne pouvez pas espérer prendre en charge les utilisateurs avec Office 2010 64 bits avec Office 2007 uniquement. La solution consiste à mettre à niveau.

Si la seule Declare que vous avez est cette ShellExecute, vous n'aurez plus grand-chose à faire une fois que vous aurez mis la main sur Office 64 bits, mais ce n'est pas vraiment viable de prendre en charge les utilisateurs lorsque vous ne pouvez pas exécuter le programme que vous envoyez! Pensez-vous simplement à ce que vous feriez quand ils rapporteront un bogue?

4
David Heffernan

j'ai trouvé ce code (notez que certains Long sont remplacés par 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

source: http://www.cadsharp.com/docs/Win32API_PtrSafe.txt

4

Utilisez PtrSafe et voyez comment cela fonctionne dans Excel 2010.

Correction d'une faute de frappe du livre "Microsoft Excel 2010 Programmation énergétique avec VBA".

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

val (application.version)> 12.0 ne fonctionnera pas car Office 2010 existe en version 32 et 64 bits

2
Jon49

En fait, pour vérifier la plate-forme 32 bits ou 64 bits, vous devez utiliser la constante Win64 définie dans toutes les versions de VBA (versions 16 bits, 32 bits et 64 bits).

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

Source: Aide VBA sur les constantes du compilateur

2
Dee Bee

Pour écrire pour toutes les versions d'Office, utilisez une combinaison des nouvelles constantes de compilateur conditionnelles VBA7 et Win64. 

VBA7 détermine si le code est exécuté dans la version 7 de l'éditeur VB (version VBA livrée dans Office 2010+). 

Win64 détermine quelle version (32 bits ou 64 bits) d'Office est en cours d'exécution.

#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

Voir Article de support Microsoft pour plus de détails.

0
GollyJer

Ce travail pour moi:

#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

Merci Jon49 pour la perspicacité.

0

Cette réponse est probablement fausse fausse le contexte. Je pensais que VBA fonctionnait maintenant sur le CLR, mais ce n'est pas le cas. Dans tous les cas, cette réponse peut être utile à quelqu'un. Ou pas.


Si vous exécutez le mode Office 2010 32 bits, il est identique à Office 2007. (Le "problème" concerne Office qui s'exécute en mode 64 bits). C'est le bitness du contexte d'exécution (VBA/CLR) qui est important ici et le bitness du VBA/CLR chargé dépend du bitness du processus de l'hôte.

Entre les appels 32/64 bits, les problèmes les plus évidents sont l'utilisation de long ou int (taille constante dans le CLR) au lieu de IntPtr (taille dynamique en fonction du nombre de bits) pour "types de pointeur".

La fonction ShellExecute a une signature de:

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

Dans ce cas, il est important que HWND soit IntPtr (car un HWND est un "HANDLE" qui est void*/"void pointer") et non long. Voir pinvoke.net ShellExecute à titre d'exemple. (Bien que certaines "solutions" soient louches sur pinvoke.net, c'est un bon endroit pour commencer dans la recherche).

Bonne codage.


En ce qui concerne toute "nouvelle syntaxe", je n'en ai aucune idée.

0
user166390