I. Quelle version dois-je installer ? 32 ou 64 bits ?▲
Tout d'abord, vérifiez que votre système Windows est 64 bits.
Ensuite, sachez qu’Office n'existe en version 64 bits qu'à partir d'Office 2010.
Pour plus de détails, consultez cette page du site de Microsoft :
Éditions 64 bits d'Office 2010
I-A. Avantages de la version 64 bits▲
Parmi les améliorations apportées, nous notons que :
Office 64 bits peut utiliser plus de mémoire que la version 32bits.
Cela peut améliorer les performances sur des fichiers volumineux ;
Excel peut charger des fichiers de plus de 2 Go.
I-B. Inconvénients de la version 64 bits▲
Les inconvénients sont à ce jour plus nombreux, nous notons que :
Les fichiers « compilés » de type MDE, ADE et ACCDE créés avec une version 32bits ne peuvent être utilisés sur une version 64 bits ;
Les contrôles ActiveX et AddIn COM doivent être compilés en 64 bits.
En d'autres termes, si vous utilisiez par exemple les programmes MzTools ou SmartIndenter, ceux-ci ne fonctionneront pas.
Même punition si vous avez installé un contrôle ActiveX.
Il faut alors installer une version 64 bits de ces composants, si elle arrive un jour…
Microsoft n'a pas prévu à ce jour de recompiler pour 64 bits les contrôles ActiveX tels que TreeView, ListView, ImageList; …
Le code d'appel aux API ne fonctionne plus en l'état.
Peut-être ne savez-vous pas que vous utilisez des API ?
Ces API sont des fonctions externes déclarées avec l'instruction Declare Function ou Declare Sub.
ShellExecute ou GetOpenFileName par exemple sont des API largement utilisées.
Une réécriture de ces instructions est nécessaire.
I-C. Que choisir ?▲
En attendant que 64 bits deviennent la norme pour tous les programmes, Microsoft conseille d'installer la version 32 bits d'Office.
C'est d'ailleurs la version installée par défaut.
N'installez la version 64 bits que si nécessaire.
Si vous n'êtes pas sûr, installez la version 32 bits.
Peut-être n'avez-vous pas le choix.
Vous avez des clients qui utilisent la version 64 bits ?
Alors nous allons voir comment rendre le code VBA compatible pour cette version.
II. Modification du modèle d'objets▲
Comme à chaque nouvelle version, le modèle d'objets a évolué.
Comprenez que certaines méthodes ou constantes ont été modifiées ou supprimées.
Certaines sont juste cachées, mais sont toujours utilisables (pour l'instant…).
Vous trouverez la liste de ces changements sur MSDN (en anglais) :
What's New in Excel 2010 ;
What's New in Access 2010 ;
What's New in Word 2010 ;
What's New in PowerPoint 2010.
Pour nous aider, Microsoft a mis à disposition un inspecteur de compatibilité :
Microsoft Office Code Compatibility Inspector
Cet outil n'est disponible que pour Excel, Word et PowerPoint.
Parmi les nouveautés du langage, Office 2010 a introduit deux nouveaux types de données : LongPtr et LongLong.
Ces types de données sont destinés à recevoir des pointeurs.
Ils peuvent contenir des valeurs supérieures à la limite du type de données Long.
LongPtr est en fait un Long en environnement 32 bits et un LongLong en environnement 64 bits.
Pour Office 2010, pas de problème donc : utilisez le Type LongPtr qui ciblera un Long en 32 bits et un LongLong en 64 bits.
Pour les versions antérieures, LongPtr n'existe pas, on continuera d'utiliser Long.
III. Cibler le code en fonction de la version▲
Pour que le code VBA cible une version particulière, il y a deux possibilités :
- vérifier le retour de la propriété SysCmd(acSysCmdAccessVer) (pour Access) ou Application.Version (pour les autres applications) ;
- utiliser des constantes de compilation.
La première possibilité ne peut être utilisée que si le code compile dans toutes les versions, par exemple :
If
Val
(
SysCmd
(
acSysCmdAccessVer)) <
14
then
MsgBox
"Ce code s'exécute sur les versions antérieures à Office 2010"
Else
MsgBox
"Ce code s'exécute sur les versions à partir de Office 2010"
End
if
L'instruction renvoie une chaîne de caractères :
- 8.x : Office 97 ;
- 9.x : Office 2000 ;
- 10.x : Office 2002 ;
- 11.x : Office 2003 ;
- 12.x : Office 2007 ;
- 14.x : Office 2010.
Notez l'absence de valeur 13 par superstition…
On utilise Val pour ne retourner que le chiffre avant le point.
La deuxième possibilité est utile pour écrire du code qui ne compilerait pas sur toutes les versions.
Par exemple les boutons de commandes possèdent, à partir d'Office 2010, une nouvelle propriété BorderColor.
Voici un petit code utilisant cette propriété :
If
Val
(
SysCmd
(
acSysCmdAccessVer)) >=
14
then
Me.CommanButton1.BorderColor
=
vbRed
End
if
Ce code fonctionne sur Office 2010, mais donne lieu à une erreur de compilation sur une version antérieure car BorderColor n'existe pas pour un bouton dans ces versions.
La solution est d'utiliser la nouvelle constante de compilation VBA7 :
#If VBA7 Then
Me.CommanButton1.BorderColor
=
vbRed
#End If
Notez l'utilisation importante des dièses (#).
VBA7 est une constante mise à disposition par VBA.
Elle vaut True (Vrai) à partir d'Office 2010.
Si on compile sur une version antérieure, ce qui est compris entre le #If VBA7 et le #End If est ignoré.
Il existe également la constante VBA6 qui est égale à True (Vrai) à partir d'Office 2000.
Pour finir, il existe également une nouvelle constante Win64 qui vaut True (Vrai) uniquement si Office est installé en 64 bits.
Ces constantes de compilation deviennent incontournables lorsqu'on utilise des API.
IV. Les API et Office 64 bits▲
Ce chapitre s'adresse plus particulièrement aux développeurs VBA.
Les API sont facilement détectables, ce sont des procédures dont la déclaration est :
- Declare Function ;
- Declare Sub.
Si vous exécutez un fichier contenant ce type de déclaration avec Office 2010 64 bits, ce code ne compile plus.
Pourquoi ?
Parce que le nouveau type de données LongPtr est désormais utilisé par les API.
Utiliser un type de données Long à la place ne serait pas correct car la valeur pourrait être tronquée.
Il est nécessaire de réécrire toutes ces déclarations et souvent l'appel à ces fonctions.
Cette page de MSDN résume la marche à suivre :
Compatibilité entre les versions 32 bits et 64 bits d'Office 2010
Et sur celle-ci, vous trouverez un fichier texte contenant les déclarations des principales API pour la version 64 bits :
Fichiers d’aide Office 2010 : Win32API_PtrSafe avec prise en charge de 64 bits
Le fichier est une archive autoextractible qui se décompresse dans : C:\Office 2010 Developer Resources.
Afin d'assurer une compatibilité entre les versions 32 bits et 64 bits,il est nécessaire d'utiliser les constantes de compilation vues précédemment afin d'écrire le code pour chaque version.
Nous allons maintenant voir un exemple concret.
IV-A. Exemple GetOpenFileName▲
L'exemple suivant s'applique à Access, mais le principe de développement est le même pour toutes les applications Office.
Afin d'ouvrir une fenêtre de sélection de fichier, l'API GetOpenFileName est couramment utilisée.
À partir d'Access 2002, FileDialog peut être employé mais n'est pas présent, par exemple, pour Access 2000.
Nous souhaitons pour cet exemple afficher une boîte de dialogue identique pour toutes les versions.
Nous décidons d'utiliser cette API, en utilisant le code de la FAQ Access de ce lien :
Afficher la boîte de dialogue ouvrir afin de récupérer le nom et le chemin du fichier sélectionné
Voici le code allégé de quelques commentaires et constantes non utilisés :
'Déclaration de l'API
Private
Declare
Sub
PathStripPath Lib
"shlwapi.dll"
Alias "PathStripPathA"
(
ByVal
pszPath As
String
)
Private
Declare
Function
GetOpenFileName Lib
"comdlg32.dll"
Alias _
"GetOpenFileNameA"
(
pOpenfilename As
OPENFILENAME) As
Long
'Structure du fichier
Private
Type
OPENFILENAME
lStructSize As
Long
hwndOwner As
Long
hInstance As
Long
lpstrFilter As
String
lpstrCustomFilter As
String
nMaxCustFilter As
Long
nFilterIndex As
Long
lpstrFile As
String
nMaxFile As
Long
lpstrFileTitle As
String
nMaxFileTitle As
Long
lpstrInitialDir As
String
lpstrTitle As
String
flags As
Long
nFileOffset As
Integer
nFileExtension As
Integer
lpstrDefExt As
String
lCustData As
Long
lpfnHook As
Long
lpTemplateName As
String
End
Type
'Constantes
Private
Const
OFN_HIDEREADONLY =
&
H4
Public
Function
OuvrirUnFichier
(
Handle As
Long
, _
Titre As
String
, _
TypeRetour As
Byte, _
Optional
TitreFiltre As
String
, _
Optional
TypeFichier As
String
, _
Optional
RepParDefaut As
String
) As
String
Dim
StructFile As
OPENFILENAME
Dim
sFiltre As
String
'Construction du filtre en fonction des arguments spécifiés
If
Len
(
TitreFiltre) >
0
And
Len
(
TypeFichier) >
0
Then
sFiltre =
TitreFiltre &
" ("
&
TypeFichier &
")"
&
Chr
$(
0
) &
"*."
&
TypeFichier &
Chr
$(
0
)
End
If
sFiltre =
sFiltre &
"Tous (*.*)"
&
Chr
$(
0
) &
"*.*"
&
Chr
$(
0
)
'Configuration de la boîte de dialogue
With
StructFile
.lStructSize
=
Len
(
StructFile) 'Initialisation de la grosseur de la structure
.hwndOwner
=
Handle 'Identification du handle de la fenêtre
.lpstrFilter
=
sFiltre 'Application du filtre
.lpstrFile
=
String
$(
254
, vbNullChar
) 'Initialisation du fichier '0' x 254
.nMaxFile
=
254
'Taille maximale du fichier
.lpstrFileTitle
=
String
$(
254
, vbNullChar
) 'Initialisation du nom du fichier '0' x 254
.nMaxFileTitle
=
254
'Taille maximale du nom du fichier
.lpstrTitle
=
Titre 'Titre de la boîte de dialogue
.flags
=
OFN_HIDEREADONLY 'Option de la boite de dialogue
If
((
IsNull
(
RepParDefaut)) Or
(
RepParDefaut =
""
)) Then
RepParDefaut =
CurrentDb.Name
PathStripPath (
RepParDefaut)
.lpstrInitialDir
=
Left
(
CurrentDb.Name
, Len
(
CurrentDb.Name
) -
Len
(
Mid
$(
RepParDefaut, 1
, _
InStr
(
1
, RepParDefaut, vbNullChar
) -
1
)))
Else
: .lpstrInitialDir
=
RepParDefaut
End
If
End
With
If
(
GetOpenFileName
(
StructFile)) Then
'Si un fichier est sélectionné
Select
Case
TypeRetour
Case
1
: OuvrirUnFichier =
Trim
$(
Left
(
StructFile.lpstrFile
, InStr
(
1
, StructFile.lpstrFile
, vbNullChar
) -
1
))
Case
2
: OuvrirUnFichier =
Trim
$(
Left
(
StructFile.lpstrFileTitle
, InStr
(
1
, StructFile.lpstrFileTitle
, vbNullChar
) -
1
))
End
Select
End
If
End
Function
Si vous ne ciblez que des versions Office 32 bits, ce code est correct quelle que soit la version (2010 ou antérieure).
Par contre, ce code ne compile pas sur une version 64 bits d'Office!
Les déclarations d'API sont en cause.
Dans le fichier Win32API_PtrSafe.txt, vous trouverez la déclaration de GetOpenFileName pour 64 bits :
Private
Declare
PtrSafe Function
GetOpenFileName Lib
"comdlg32.dll"
_
Alias "GetOpenFileNameA"
(
pOpenfilename As
OPENFILENAME) As
Long
J'ai juste ajouté Private pour réduire la portée de la fonction au module dans lequel elle est déclarée.
Le plus important est l'ajout de PtrSafe : cet attribut indique que l'on cible la version 64 bits.
Pour la déclaration de PathStripPath, il faut se débrouiller tout seul car elle n'apparaît pas dans le fichier précédent.
C'est toutefois assez simple, il suffit d'ajouter PtrSafe à la déclaration.
Il ne peut y avoir d'ambiguïté que sur les types Long, les autres types restant inchangés.
Private
Declare
PtrSafe Sub
PathStripPath Lib
"shlwapi.dll"
_
Alias "PathStripPathA"
(
ByVal
pszPath As
String
)
Utilisons la constante de compilation VBA7 afin de définir les déclarations en fonction de la version.
'Déclaration de l'API
#If VBA7 Then
Private
Declare
PtrSafe Sub
PathStripPath Lib
"shlwapi.dll"
_
Alias "PathStripPathA"
(
ByVal
pszPath As
String
)
Private
Declare
PtrSafe Function
GetOpenFileName Lib
"comdlg32.dll"
_
Alias "GetOpenFileNameA"
(
pOpenfilename As
OPENFILENAME) As
Long
#Else
Private
Declare
Sub
PathStripPath Lib
"shlwapi.dll"
_
Alias "PathStripPathA"
(
ByVal
pszPath As
String
)
Private
Declare
Function
GetOpenFileName Lib
"comdlg32.dll"
_
Alias "GetOpenFileNameA"
(
pOpenfilename As
OPENFILENAME) As
Long
#End If
Ce n'est malheureusement pas tout : on utilise une structure OPENFILENAME qui doit également être adaptée.
Cette structure peut être trouvée également dans le fichier Win32API_PtrSafe.txt :
Type
OPENFILENAME
lStructSize As
Long
hwndOwner As
LongPtr
hInstance As
LongPtr
lpstrFilter As
String
lpstrCustomFilter As
String
nMaxCustFilter As
Long
nFilterIndex As
Long
lpstrFile As
String
nMaxFile As
Long
lpstrFileTitle As
String
nMaxFileTitle As
Long
lpstrInitialDir As
String
lpstrTitle As
String
flags As
Long
nFileOffset As
Integer
nFileExtension As
Integer
lpstrDefExt As
String
lCustData As
LongPtr
lpfnHook As
LongPtr
lpTemplateName As
String
'#if (_WIN32_WINNT >= 0x0500)
pvReserved As
LongPtr
dwReserved As
Long
FlagsEx As
Long
'#endif // (_WIN32_WINNT >= 0x0500)
End
Type
C'est ici que ça se complique!
D'abord, que signifie _WIN32_WINNT ?
C'est une constante de compilation, mais en C++; d'ailleurs la ligne est commentée.
Cela signifie que les trois derniers membres de la structure ne sont valables que pour une certaine version de Windows.
Comme nous n'utilisons pas ces trois derniers membres, le plus sûr est de ne pas les inclure dans la structure.
On pourra éventuellement les laisser et les commenter.
Ensuite on voit que certains membres de la structure sont typés en LongPtr.
Il faut agir à ce niveau.
On ne peut pas laisser un LongPtr qui ne compilerait pas sur une version antérieure à 2010.
Ici encore, utilisons la constante de compilation VBA7.
Private
Type
OPENFILENAME
lStructSize As
Long
#If VBA7 Then
hwndOwner As
LongPtr
hInstance As
LongPtr
#Else
hwndOwner As
Long
hInstance As
Long
#End If
lpstrFilter As
String
lpstrCustomFilter As
String
nMaxCustFilter As
Long
nFilterIndex As
Long
lpstrFile As
String
nMaxFile As
Long
lpstrFileTitle As
String
nMaxFileTitle As
Long
lpstrInitialDir As
String
lpstrTitle As
String
flags As
Long
nFileOffset As
Integer
nFileExtension As
Integer
lpstrDefExt As
String
#If VBA7 Then
lCustData As
LongPtr
lpfnHook As
LongPtr
#Else
lCustData As
Long
lpfnHook As
Long
#End If
lpTemplateName As
String
'#if (_WIN32_WINNT >= 0x0500)
'pvReserved As LongPtr
'dwReserved As Long
'FlagsEx As Long
'#endif // (_WIN32_WINNT >= 0x0500)
End
Type
Seuls les membres typés LongPtr en 64 bits changent selon les versions.
J'ai choisi de ne dupliquer que ces membres ; on aurait également pu dupliquer toute la structure.
Il nous reste encore un peu de travail.
En effet, avec ces déclarations, le code ne compile toujours pas en 64 bits.
Pourquoi ? Tout simplement parce que les types de données utilisés par la fonction OuvrirUnFichier ne sont pas corrects.
Handle est déclaré en Long alors que la version 64 bits du membre hwndOwner de la structure OPENFILENAME attend un LongPtr.
Il faut également modifier le type de données des variables utilisées pour les appels d'API.
Adaptez la fonction OuvrirUnFichier pour accepter un LongPtr en paramètre :
#If VBA7 Then
Public
Function
OuvrirUnFichier
(
Handle As
LongPtr, _
Titre As
String
, _
TypeRetour As
Byte, _
Optional
TitreFiltre As
String
, _
Optional
TypeFichier As
String
, _
Optional
RepParDefaut As
String
) As
String
#Else
Public
Function
OuvrirUnFichier
(
Handle As
Long
, _
Titre As
String
, _
TypeRetour As
Byte, _
Optional
TitreFiltre As
String
, _
Optional
TypeFichier As
String
, _
Optional
RepParDefaut As
String
) As
String
#End If
Et voilà ! Enfin presque…
Testez la fonction avec ce code :
Public
Function
TestDeLaFonction
(
)
MsgBox
OuvrirUnFichier
(
Application.hWndAccessApp
, "Test"
, 1
)
End
Function
Et ça ne fonctionne pas !
Il faut faire attention à une dernière chose :
il est important d'utiliser l'instruction LenB pour calculer la taille d'une structure 64 bits.
LenB fonctionne également dans ce cas pour les versions 32 bits.
Remplacez donc .lStructSize = Len(StructFile) par .lStructSize = LenB(StructFile).
Il faut parfois utiliser Len pour 32 bits et LenB pour 64 bits.
Et voici le code complet, qui fonctionne sur toutes les versions d'Office.
Option
Explicit
'Déclaration de l'API
#If VBA7 Then
Private
Declare
PtrSafe Sub
PathStripPath Lib
"shlwapi.dll"
_
Alias "PathStripPathA"
(
ByVal
pszPath As
String
)
Private
Declare
PtrSafe Function
GetOpenFileName Lib
"comdlg32.dll"
_
Alias "GetOpenFileNameA"
(
pOpenfilename As
OPENFILENAME) As
Long
#Else
Private
Declare
Sub
PathStripPath Lib
"shlwapi.dll"
_
Alias "PathStripPathA"
(
ByVal
pszPath As
String
)
Private
Declare
Function
GetOpenFileName Lib
"comdlg32.dll"
_
Alias "GetOpenFileNameA"
(
pOpenfilename As
OPENFILENAME) As
Long
#End If
Private
Type
OPENFILENAME
lStructSize As
Long
#If VBA7 Then
hwndOwner As
LongPtr
hInstance As
LongPtr
#Else
hwndOwner As
Long
hInstance As
Long
#End If
lpstrFilter As
String
lpstrCustomFilter As
String
nMaxCustFilter As
Long
nFilterIndex As
Long
lpstrFile As
String
nMaxFile As
Long
lpstrFileTitle As
String
nMaxFileTitle As
Long
lpstrInitialDir As
String
lpstrTitle As
String
flags As
Long
nFileOffset As
Integer
nFileExtension As
Integer
lpstrDefExt As
String
#If VBA7 Then
lCustData As
LongPtr
lpfnHook As
LongPtr
#Else
lCustData As
Long
lpfnHook As
Long
#End If
lpTemplateName As
String
'#if (_WIN32_WINNT >= 0x0500)
'pvReserved As LongPtr
'dwReserved As Long
'FlagsEx As Long
'#endif // (_WIN32_WINNT >= 0x0500)
End
Type
'Constantes
Private
Const
OFN_HIDEREADONLY =
&
H4
#If VBA7 Then
Public
Function
OuvrirUnFichier
(
Handle As
LongPtr, _
Titre As
String
, _
TypeRetour As
Byte, _
Optional
TitreFiltre As
String
, _
Optional
TypeFichier As
String
, _
Optional
RepParDefaut As
String
) As
String
#Else
Public
Function
OuvrirUnFichier
(
Handle As
Long
, _
Titre As
String
, _
TypeRetour As
Byte, _
Optional
TitreFiltre As
String
, _
Optional
TypeFichier As
String
, _
Optional
RepParDefaut As
String
) As
String
#End If
Dim
StructFile As
OPENFILENAME
Dim
sFiltre As
String
'Construction du filtre en fonction des arguments spécifiés
If
Len
(
TitreFiltre) >
0
And
Len
(
TypeFichier) >
0
Then
sFiltre =
TitreFiltre &
" ("
&
TypeFichier &
")"
&
Chr
$(
0
) &
"*."
&
TypeFichier &
Chr
$(
0
)
End
If
sFiltre =
sFiltre &
"Tous (*.*)"
&
Chr
$(
0
) &
"*.*"
&
Chr
$(
0
)
'Configuration de la boîte de dialogue
With
StructFile
.lStructSize
=
LenB
(
StructFile) 'Initialisation de la grosseur de la structure
.hwndOwner
=
Handle 'Identification du handle de la fenêtre
.lpstrFilter
=
sFiltre 'Application du filtre
.lpstrFile
=
String
$(
254
, vbNullChar
) 'Initialisation du fichier '0' x 254
.nMaxFile
=
254
'Taille maximale du fichier
.lpstrFileTitle
=
String
$(
254
, vbNullChar
) 'Initialisation du nom du fichier '0' x 254
.nMaxFileTitle
=
254
'Taille maximale du nom du fichier
.lpstrTitle
=
Titre 'Titre de la boîte de dialogue
.flags
=
OFN_HIDEREADONLY 'Option de la boite de dialogue
If
((
IsNull
(
RepParDefaut)) Or
(
RepParDefaut =
""
)) Then
RepParDefaut =
CurrentDb.Name
PathStripPath (
RepParDefaut)
.lpstrInitialDir
=
Left
(
CurrentDb.Name
, Len
(
CurrentDb.Name
) -
Len
(
Mid
$(
RepParDefaut, 1
, _
InStr
(
1
, RepParDefaut, vbNullChar
) -
1
)))
Else
: .lpstrInitialDir
=
RepParDefaut
End
If
End
With
If
(
GetOpenFileName
(
StructFile)) Then
'Si un fichier est sélectionné
Select
Case
TypeRetour
Case
1
: OuvrirUnFichier =
Trim
$(
Left
(
StructFile.lpstrFile
, InStr
(
1
, StructFile.lpstrFile
, vbNullChar
) -
1
))
Case
2
: OuvrirUnFichier =
Trim
$(
Left
(
StructFile.lpstrFileTitle
, InStr
(
1
, StructFile.lpstrFileTitle
, vbNullChar
) -
1
))
End
Select
End
If
End
Function
IV-B. Quand dois-je utiliser PtrLong ?▲
Cela ne vous a sans doute pas échappé : dans la structure OPENFILENAME, certains Long deviennentLongPtr en 64 bits et d'autres restent Long.
En effet, certaines valeurs numériques sont des entiers longs, même en 64 bits.
Seuls les pointeurs utilisent un type LongPtr.
Un identifiant de fenêtre (hwnd) est un pointeur, un contexte d'affichage aussi.
Notez qu'en environnement 64 bits, Me.Hwnd est d'ailleurs de type LongPtr.
IV-C. Autre solution aux constantes de compilation ?▲
Il devient vite pénible de devoir utiliser les constantes de compilation un peu partout dans le code.
Nous allons essayer de limiter leur utilisation aux seules déclarations de procédures et de structures.
Prenons l'exemple de l'API ShellExecute.
Celle-ci permet, par exemple, d'ouvrir un fichier.
En environnement 32 bits, voici son utilisation :
Option
Explicit
Const
SW_SHOWNORMAL =
1
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
' Fonction qui ouvre le fichier "c:\temp\monfichier.txt",
Public
Function
TestShellExecute
(
)
Dim
lRetour As
Long
Dim
lParent As
Long
lParent =
Application.hWndAccessApp
lRetour =
ShellExecute
(
lParent, "open"
, "c:\temp\monfichier.txt"
, ""
, ""
, SW_SHOWNORMAL)
If
lRetour <
32
Then
' Erreur si retour < 32
MsgBox
"Erreur d'ouverture n° "
&
lRetour
End
If
End
Function
La déclaration pour un environnement 64 bits est la suivante :
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
Nous remarquons que l'identifiant de fenêtre parent (hwnd) et le retour de la fonction sont de type LongPtr.
Il faut donc modifier le type de nos variables lRetour et lParent.
Option
Explicit
Const
SW_SHOWNORMAL =
1
#If VBA7 Then
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
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
' Fonction qui ouvre le fichier "c:\temp\monfichier.txt",
Public
Function
TestShellExecute
(
)
#If VBA7 Then
Dim
lRetour As
LongPtr
Dim
lParent As
LongPtr
#Else
Dim
lRetour As
Long
Dim
lParent As
Long
#End If
lParent =
Application.hWndAccessApp
lRetour =
ShellExecute
(
lParent, "open"
, "c:\temp\monfichier.txt"
, ""
, ""
, SW_SHOWNORMAL)
If
lRetour <
32
Then
' Erreur si retour < 32
MsgBox
"Erreur d'ouverture n° "
&
lRetour
End
If
End
Function
Ceci peut vite devenir très lourd si comme moi vous utilisez beaucoup d'API.
Une solution est d'utiliser les instructions DefType.
Ces instructions permettent de définir un type par défaut pour une plage de noms de variables :
- DefLngPtr définit les variables de type LongPtr ;
- DefLng définit les variables de type Long.
Par exemple :
DefLngPtr Z
DefLngPtr A-
Z
Ces instructions sont à écrire en en-tête de chaque module car elles ne s'appliquent qu'au module dans lequel on les écrit.
Attention : si vous utilisez ces instructions, pensez à bien typer chacune de vos variables pour éviter qu'elle ne prenne par erreur le type par défaut.
Il suffit d'utiliser les constantes de compilation pour définir le type de variables par défaut.
On peut par exemple décider que toutes les variables commençant par Z seront de type LongPtr ou Long suivant l'environnement.
Nous appellerons nos variables pointeurs zlRetour et zlParent.
Elles seront typées par défaut, il ne faut donc pas préciser leur type lors de leur déclaration.
' Définition du type de données par défaut
' pour les variables commençant par Z
#If VBA7 Then
DefLngPtr Z
#Else
DefLng Z
#End If
' Déclaration de l'API ShellExecute
Const
SW_SHOWNORMAL =
1
#If VBA7 Then
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
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
' Fonction qui ouvre le fichier "c:\temp\monfichier.txt",
Public
Function
TestShellExecute
(
)
Dim
zlRetour
Dim
zlParent
zlRetour =
Application.hWndAccessApp
zlRetour =
ShellExecute
(
zlParent, "open"
, "c:\temp\monfichier.txt"
, ""
, ""
, SW_SHOWNORMAL)
If
zlRetour <
32
Then
MsgBox
"Erreur d'ouverture n° "
&
zlRetour
End
If
End
Function
De cette manière, on évite de mettre des constantes de compilation partout dans nos fonctions.
Ce n'est pas très visible dans l'exemple, mais ça facilite la vie lors de l'utilisation massive d'API.
Remarque :
Sont typés par défaut avec les instructions DefLng et DefLngPtr :
- les variables ;
- les paramètres de fonction ;
- les retours des fonctions.
Les membres des structures doivent être explicitement typés.
V. Conclusion▲
Mis à part les appels aux API, la migration de code VBA vers la version 2010 64 bits ne devrait pas être très problématique.
Par contre, on trouve beaucoup de code utilisant ces API, souvent copié d'internet sans trop comprendre.
La migration risque, dans ce cas, d'être parfois douloureuse pour un développeur VBA peu expérimenté.
La seule notion de pointeur n'est pas maîtrisée par tous, et quand bien même vous maîtrisez ce domaine, cela n'est pas toujours très simple.
Heureusement, pour l'instant, la version 64 bits d'Office est très peu utilisée.
Si vous avez le choix, suivez le conseil de Microsoft et installez la version 32 bits.
Merci à blade159 et jacques_jean pour leur relecture orthographique.