Pourquoi vos macros cassent en 64 bits
Le VBA d'avant Office 2010 (VBA 6 et antérieurs) visait implicitement le 32 bits : un handle de fenêtre ou un pointeur tenait dans un Long, sur 4 octets. En 64 bits, ces valeurs occupent 8 octets. Les ranger dans un Long les tronque, ce qui peut, selon Microsoft, écraser de la mémoire, produire des résultats faux ou faire planter l'application.
Office 2010 a introduit VBA7, qui ajoute ce qu'il faut pour écrire un code valable en 32 et en 64 bits. Le sujet est devenu courant parce que l'architecture installée par défaut a changé :
| Version d'Office | Architecture installée par défaut |
|---|---|
| Office 2010, 2013, 2016 | 32 bits (le 64 bits se choisit à l'installation) |
| Office 2019, Microsoft 365 | 64 bits |
Seul le code exécuté dans un Office 64 bits doit être modifié. Le code VBA ordinaire (cellules, plages, boucles, formulaires MSForms) n'est pas concerné : ce sont les appels à l'API Windows, et quelques composants 32 bits, qui cassent.
Le symptôme : une erreur de compilation à l'ouverture
Dans un Office 64 bits, un module qui contient un Declare sans PtrSafe ne compile pas. Le message complet, dans la version anglaise d'Office, est :
The code in this project must be updated for use on 64-bit systems.
Please review and update Declare statements and then mark them with the PtrSafe attribute.
Pour l'utilisateur, le classeur ou le document affiche une erreur de compilation, souvent dès l'ouverture quand une macro s'y lance automatiquement.
PtrSafe, LongPtr, LongLong : ce que fait chaque mot-clé
| Élément | Rôle | Disponible |
|---|---|---|
PtrSafe | déclare que le Declare est prévu pour le 64 bits ; obligatoire en Office 64 bits | VBA7 (Office 2010 et suivants) |
LongPtr | type des pointeurs et handles : devient Long en 32 bits, LongLong en 64 bits | VBA7 |
LongLong | entier signé sur 64 bits | Office 64 bits uniquement |
CLngPtr, CLngLng | conversions vers LongPtr et LongLong | VBA7 ; CLngLng en 64 bits uniquement |
VBA7 | constante de compilation, vraie dans l'éditeur VBA7 | Office 2010 et suivants |
Win64 | constante de compilation, vraie dans un Office 64 bits | VBA7 |
LongPtr n'est pas un vrai type : c'est un alias résolu à la compilation. C'est précisément ce qui permet d'écrire une seule déclaration valable sur les deux architectures.
Corriger un Declare, étape par étape
Prenons l'exemple donné par Microsoft. La déclaration d'origine :
Declare Function GetActiveWindow Lib "user32" () As Long
Ajouter seulement PtrSafe fait disparaître l'erreur de compilation, mais laisse un handle tronqué : c'est le cas le plus dangereux, parce que le code semble fonctionner.
' Compile, mais reste faux en 64 bits
Declare PtrSafe Function GetActiveWindow Lib "user32" () As Long
La version correcte type le handle renvoyé en LongPtr :
Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
La méthode à suivre pour chaque Declare :
- Ajoutez
PtrSafeaprèsDeclare. - Repérez les paramètres et la valeur de retour qui portent un handle (
hWnd,hDC,hInstance,hKey…) ou un pointeur (lp…, adresses mémoire) : passez-les enLongPtr. - Laissez en
Longles entiers qui restent sur 32 bits dans l'API (tailles, indicateurs, codes de retour). Microsoft recommandeLongPtrpour les pointeurs et les handles, pas pour tout. - Suivez ces valeurs dans le code : les variables qui reçoivent le handle, les champs des structures
Typepassées à l'API, les variables locales intermédiaires doivent aussi devenirLongPtr.
Un exemple typique, avec un handle en retour et deux chaînes en paramètres :
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Sub Exemple()
Dim h As LongPtr
h = FindWindow(vbNullString, "Calculatrice")
End Sub
Garder un seul code pour 32 et 64 bits : #If VBA7
Si certains postes ont encore un Office antérieur à 2010, le mot-clé PtrSafe et le type LongPtr n'y existent pas. La compilation conditionnelle sépare les deux mondes :
#If VBA7 Then
Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
#Else
Private Declare Function GetActiveWindow Lib "user32" () As Long
#End If
Dans la plupart des parcs, #If VBA7 suffit : LongPtr s'adapte tout seul à l'architecture. Réservez #If Win64 aux cas où la logique doit réellement différer entre 32 et 64 bits, par exemple pour manipuler des valeurs LongLong, qui n'existent pas en 32 bits :
#If Win64 Then
Dim compteur As LongLong
#Else
Dim compteur As Long
#End If
Si tous vos postes ont Office 2010 ou plus récent, la branche #Else est inutile : une déclaration PtrSafe avec des LongPtr fonctionne en 32 comme en 64 bits.
Ce que PtrSafe ne règle pas
Certaines dépendances n'ont tout simplement pas de version 64 bits. Le catalogue de règles d'Inventaire VBA en relève plusieurs familles :
| Dépendance | Symptôme en 64 bits | Remplacement possible |
|---|---|---|
| MSCOMCTL (ListView, TreeView), MSCOMCT2 (DTPicker), contrôle Calendar | contrôle ou référence « manquant » dans le formulaire | contrôle MSForms, saisie de date maison, bibliothèque 64 bits |
| Script Control (MSScriptControl) | référence manquante | réécriture en VBA ou appel à PowerShell |
Microsoft.Jet.OLEDB.4.0, DAO 3.6, pilotes ODBC « .mdb » et « .xls » | connexion impossible | Microsoft.ACE.OLEDB.12.0 et la bibliothèque « Microsoft Office Access database engine Object Library » |
Ces cas demandent plus de travail qu'un Declare : un formulaire à refaire, une connexion à retester avec les données réelles.
Méthode pour un parc entier
- Inventorier tous les fichiers à macros (
.xlsm,.xlsb,.xlam,.xls,.docm,.dotm…) sur les partages, pas seulement ceux que l'on connaît. - Chercher les lignes
DeclaresansPtrSafe, puis lesDeclare PtrSafedont un handle ou un pointeur est encore enLong. - Repérer les références et contrôles 32 bits ainsi que les chaînes de connexion Jet.
- Corriger en priorité les fichiers utilisés par plusieurs services, et les copies d'un même outil en une seule fois.
- Tester sur un poste 64 bits chaque fonction qui appelle l'API Windows : un handle tronqué ne se voit pas à la compilation.
Trouver les macros concernées dans un parc
Inventaire VBA fait les étapes 1 à 3 : il lit les fichiers Office des partages sans ouvrir Office, sans exécuter de macro ni rien envoyer sur le réseau, et liste fichier par fichier les Declare sans PtrSafe, les handles déclarés en Long, les contrôles 32 bits et les accès Jet ou DAO 3.6, avec la ligne en cause. Il traite aussi les signatures V3, le nouvel Outlook et VBScript. C'est une analyse statique : il ne sait pas quelles versions d'Office sont installées sur vos postes, et la détection des handles en Long repose sur les noms des paramètres (hWnd, lp…), donc à relire. La correction du code reste à faire.
Sources
- Microsoft Learn, 64-bit Visual Basic for Applications overview
- Microsoft Learn, PtrSafe keyword
- Microsoft Learn, LongPtr data type
- Microsoft Learn, The code in this project must be updated for use on 64-bit systems
- Inventaire VBA, catalogue des règles B64-001 à B64-004 (src/regles.mjs)
- Textes relus le 2026-10-27