Faire cohabiter du code VBA 32 bits et 64 bits
Depuis Office 2010, Access peut exister en version 32 bits ou 64 bits, selon votre version de Windows. Ceci a un impact sur votre code VBA, lorsque vous utilisez des bibliothèques (DLL) externes. Dans un article précédent, on a vu comment adapter les déclarations de fonctions API de 32 bits en 64 bits.
Mais comment faire si votre base doit tourner à la fois sur une machine 32 bits et sur un ordinateur 64 bits ? Vous ne souhaitez pas corriger toutes vos déclarations API à chaque fois !
La solution
La solution passe par la compilation conditionnelle. Kezako ?
En VBA, il existe des directives particulières, à taper dans le code, pour compiler celui-ci en fonction de critères précis. Le principe consiste à dire quelque chose comme :
Si Access ou Windows est en version 64 bits Alors Utiliser les déclarations API 64 bits Sinon Utiliser les déclarations API 32 bits
La syntaxe générale est la suivante :
1 2 3 4 5 |
#If ... Then ... #Else ... #End If |
Comme vous le voyez, ça ressemble à un If / End If
Visual Basic, mais cette fois la condition a un impact sur le code qui sera compilé.
Quelques constantes utiles
Pour permettre de détecter la version de VBA ou de Windows, Microsoft fournit quelques constantes système :
WIN64
vaut Vrai (True
) si Windows est en 64 bits, et Faux (False
) sinon.VBA7
vaut Vrai si la version d’Office est 2010 ou plus, et Faux sinon.- D’autres constantes existent encore, comme VBA6, WIN32, WIN16, mais elles ne nous serviront pas ici.
- Il est également possible de définir vos propres constantes, de cette manière :
1 2 |
#Const ACCESS2003=True #Const VERSION="2003" |
Les déclarations API en 64 bits sont compatibles avec Access 2010, qu’il soit 32 ou 64 bits. Ça veut dire qu’il suffit de vérifier si on est en VBA7
pour déclarer une API 64 bits. On progresse ! Maintenant, il est possible de d’écrire des tests de ce genre dans notre code VBA :
1 2 3 4 5 |
#If VBA7 Then ... #Else ... #End If |
Ou accessoirement, avec nos propres constantes (mais ça n’est pas le sujet de cet article) :
1 2 3 4 5 6 7 8 9 10 11 |
#If ACCESS2003 Then ... #Else ... #End If #If VERSION="2003" Then ... #Else ... #End If |
Exemple pratique
Concrètement, reprenons le cas de la fonction API ShellExecute
, qui permet d’ouvrir un fichier quelconque dans son application par défaut, sans connaître celle-ci. Par exemple, un document .xlsx s’ouvrira dans Excel, un .pdf s’ouvrira dans Acrobat Reader, à moins que vous ayez installé un autre lecteur de PDF (comme Sumatra PDF).
La déclaration API de cette fonction a changé en version 64 bits (voyez l’article précédent). Pour faire cohabiter les versions 32 et 64 bits dans une même base de données, écrivez ceci :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
' --- DECLARATION API WINDOWS #If VBA7 Then Private 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 #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 |
Bonjour,
je suis d’accord avec les solutions que vous proposez.
Cependant, cela ne fonctionne pas avec Gdiplus.dll
Auriez vous une idée ?
Par avance, merci de vos réponses.
Quel appel de GdiPlus, par exemple ?
Bonjour Monsieur Inisan,
Effectivement ce sera mieux
Didier Granier > Effectivement, ça marche comme ça. Mais je mettrais plutôt toute la procédure
ShellExec
entière dans le#If / #End If
. Le fait de déplacer uniquement la variable dans ce bloc la transforme en variable globale, ce qui n’est pas utile ici.Ouala !
Merci pour cet article
Je viens de faire le test et il faut rajouter la déclaration de la variable lngRes dans les déclaration des API Windows pour que cela fonctionne avec la Procédure Function ShellExec(…).
Il faut également supprimer la ligne
Dim lngRes as Long
dans la Procédure Function ShellExec(…).
‘ — DECLARATION API WINDOWS
#If VBA7 Then
Private 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
Dim lngRes As LongPtr
#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
Dim lngRes As Long
#End If
‘ —
‘ OUVRIR/IMPRIMER UN DOCUMENT A PARTIR DE SON CHEMIN
‘ —
‘ Entrée : strFichier <- Nom du fichier à ouvrir/imprimer.
‘ strOperation <- Opération sur le fichier.
‘ explore, find, open, print
‘ strParametres <- Paramètres à transmettre au programme,
‘ lorsque strFichier est un .exe.
‘ strDossier <- Dossier d’exécution par défaut (pour un .exe).
‘ awsAffichage <- Mode d’affichage de la fenêtre.
‘
Public Function ShellExec( _
ByVal STRfichier As String, _
Optional ByVal strOperation As String = « Open », _
Optional ByVal awsAffichage As VbAppWinStyle = VbAppWinStyle.vbNormalFocus, _
Optional ByVal strParametres As String = « », _
Optional ByVal STRdossier As String = « ») _
As Boolean
‘ Dim lngRes As Long
lngRes = ShellExecute(Access.hWndAccessApp, strOperation, _
STRfichier, strParametres, STRdossier, awsAffichage)
ShellExec = (lngRes < 0) Or (lngRes > 32)
End Function