Les API (DLL)

Les API sont des appels à des routines qui sont contenues dans les .DLL.

J'ai testé : Apparemment, en aucun cas la syntaxe d'appel API n'est case-sensitive

Fichiers DLL les plus usités

Marche à suivre

Il est nécessaire d'observer 2 points, parfois trois :

1. Déclaration de la fonction dans une section de déclaration d'un module

Il est possible de déclarer une sous-procédure ou une sous fonction

Syntaxe de la déclaration de la sous procédure :

Public ou Private Declare Sub NomProcédure Lib"NomDeLaProcédure" Alias "Pseudonyme" (ListeParametres)

Syntaxe de la déclaration de la sous-fonction :

Public ou Private Declare Sub NomFonction Lib"NomDeLaFonction" Alias "Pseudonyme" (ListeParametres) As Type

2. Création d'une routine/enveloppe appelant la routine DLL

3. Appeler la routine DLL

ATTENTION : Les DLLS sont Case-Sensitives

Exemples

Exemple standard

Cet exemple permet simplement de récupérer le nom du dossier de Windows.

Pour commencer, il faut préparer le terrain, et inscrire la définition de l'appel à l'API dans une section de déclaration d'un module :

Declare Function DossierWindows Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long

DossierWindows Nom d'alias : C'est un nom plus sympa que
Lib "kernel32" Nom de la DLL. Attention : S'il y a le chiffre 32, cette librairie ne pourra pas s'exécuter sous Windows 3.1/3.11
Alias "GetWindowsDirectoryA" C'est le nom de la fonction telle qu'elle apparaît dans la DLL. Dans le cas ou on ne définit pas d'Alias, ce serait ce nom de fonction que l'on pourrait utiliser (Je n'ai pas testé de ne pas prendre d'alias). Le A à la fin signifie que la routine est "en version ANSI (je ne comprend pas vraiment).

Ce nom de fonction n'est pas case-sensitive

ByVal On passe ce premier argument par valeur. Ce qui est étrange dans le sens ou l'API va remplir cette chaîne (à cette adresse donc) avec le nom du dossier Windows…
lpBuffer As String Il faudra lui passer une chaine de caractères de longueur 255. Pourquoi 255 ? Parce que c'est la longueur maximale du chemin d'accès Windows. C'est d'ailleurs toujours la longueur d'une chaîne de caractère renvoyée de cette façon, j'imagine. lpBuffer peut être remplacé par n'importe quel autre nom de variable
ByVal nSize As Long Contiendra la longueur effective de la chaîne. Cette longueur sera donc stockée dans la variable de type Long dont on donnera l'adresse en pâture comme 2ème paramètre (Si le dossier est C:\Windows, la variable donnée en pâture à nSize contientra 10).

nSize n'est pas case sensitive, et de toute façon, elle peut être remplacée par n'importe quel autre nom de variable

As Long Retour de la fonction. En l'occurrence, c'est la longueur effective du nom du chemin d'accès au dossier Windows, en l'occurrence 10 (et non pas 1 si la fonction s'est bien déroulée, comme on aurait pu s'y attendre)

Ce qui est surtout intéressamnt de constater, c'est que les paramètres passés à l'API seront réellement remplis par la fonction elle même. Quand on crée une fonction personnelle, sans API, on est pourtant habitué à donner des paramètres qui ne changent pas au cours de la fonction, mais dans le cas des API, le principe est différent.

Par exemple, si on crée une fonction RacineCarree(ByVal Parametre), Parametre est tranquille. D'autant plus tranquille qu'on en passe une copie par valeur… Mais dans notre exemple API, les variables qu'on donne comme lpBuffer sera, elle, bien remplacée par des données (par contre le 2ème paramètre nSize ne changera pas)

' On déclare la chaîne de caractère qui va ensuite contenir "C:\WINDOWS"

Dim ChainePointeurReceptrice As String

' On déclare une variable Long, qui, elle, va contenir la longueur effective de C:\WINDOWS (10)

Dim LongueurEffective As Long

' On prépare la chaîne (ici, on met 20 X, mais en fait, pour être propre, on devrait mettre 255 CHR$(0)) Pourquoi ? parce que les API ne sont pas aussi souples que VBA Access, et la réservation de place pour la chaîne n'est en fait que de 0 caractères si on n'assigne pas effectivement 20 places comme ici, ce qui fait que la chaîne n'aurait pas la place pour recevoir C:\WINDOWS. C'est seulement dans l'environnement de programmation VB ou VBA qu'on peut se permettre d'agrandir ou de réduire les chaînes dynamiquement.

ChainePointeurReceptrice = String$(20, "X")

Et enfin, on appelle la fonction.

LongueurEffective contiendra donc 10

ChainePointeurReceptrice contiendra C:\WINDOWS

le 20 correspond simplement à la place qu'on accepte de laisser à l'API pour stocker la chaîne. C'est donc le même ' chiffre que lors du remplissage préparatoire de la chaîne (ChainePointeurReceptrice = String$(20, "X")). Par contre, dans les exemples, on voit toujours que la chaîne est remplie avec des codes ASCII 0 (à la place du X de l'exemple di dessus). Ca ne me paraît pas judicieux, car ensuite la chaîne réceptrice va toujours être de 255 caractères : La fonction TRIM qui enlève les espaces de gauche et de droite reste inopérante. Je préconise donc plutôt ChainePointeurReceptrice = String$(20, 32), ou 32 est le code ASCII de l'espace, et qui, lui, est retirable grâce à la fonction Trim.

LongueurEffective = DossierWindows(ChainePointeurReceptrice, 20)

Exemple simple 1

Cet exemple utilise une fonction API des plus simples. Elle permet de voir ou non le curseur de la souris. (x = ShowCursor(False) la cache, et x = ShowCursor(True) la montre)

Private Declare Function ShowCursor Lib "user32" (ByVal bshow As Long) As Long
Private Sub Détail_Click()
Dim x
x = ShowCursor(False)
MsgBox "Plus de souris..."
x = ShowCursor(True)
End Sub

Exemple simple 2

Dans la section déclaration du module

Attention : Le Declare [Sub|Function] DOIT se trouver dans la section déclaration d'un module indépendant. Si on le place dans la section déclaration d'un module de formulaire, ça ne marche pas (J'ai testé)

Declare Function wu_GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long

Dans un module

Function ap_GetWindowsDir() As Variant
Dim strWindowsDir As String
Dim lngLength As Long
Dim lngResult As Long
'-- Set up buffer.
strWindowsDir = String$(255, 0)
lngLength = 255
'-- Make the call.
lngResult = wu_GetWindowsDirectory(strWindowsDir, lngLength)
'-- Clean up and assign the value.
ap_GetWindowsDir = Left(strWindowsDir, InStr(1, strWindowsDir, Chr(0)) - 1)
End Function

Appel de la foncion personnalisée

Il suffit ensuite d'appeler la fonction personnalisée ap_GetWindowsDir() pour avoir en retour la chaîne de caractères contenant le path de Windows.

Fonctions API intéressantes

Calculer un temps d’exécution d’un programme

La fonction API GetTickCount de kernel32 permet de connaître le temps en millisecondes depuis que Windows (ou l’ordinateur) est allumé.

Comme cette valeur change toutes les millisecondes, il faut bien sûr l’appeler plusieurs fois, la stocker dans des variables temporaires, etc...

Pourquoi pas aussi utiliser cette fonction pour déterminer des nombres aléatoires

Déclaration

Declare Function GetTickCount Lib "kernel32" () As Long

Utilisation

MsgBox GetTickCount

Jouer un fichier WAV (Avec et sans Alias)

Fonctionne uniquement en 32 bits (Windows 95). Dans cette fonction, on appelle directement l'API, sans passer pas une fonction personnalisée (cf nom de l'utilisateur courant)

Déclaration

Declare Function mciExecute Lib "winmm.dll" (ByVal lpstrcommand As String) As Long

Utilisation

Sub Test()
Dim x
x = mciExecute("Play C:\windows\msremind.wav")
End Sub

Le même exemple AVEC alias

Déclaration

Declare Function JouerUnSon Lib "winmm.dll" Alias "mciExecute" (ByVal lpstrcommand As String) As Long

Utilisation

Sub Test()
Dim x
x = JouerUnSon("Play C:\windows\msremind.wav")
End Sub

Utilisation de la carte sound-blaster

Access 2 seulement

Il faut 2 choses : Installer la déclaration de la fonction d'appel dans un module quelconque :

Declare Function sndPlaySound Lib "mmsystem" (ByVal lpszSoundName As String, ByVal fuOptions As Integer) As Integer

Appeler cette routine avec une syntaxe correcte depuis n'importe oú :

VariableQuelconque = sndPlaySound("C:\chemin\fichier.wav", 1)

Récupérer les emplacements de Windows, system et Temp

Ces 3 fonctions sont issues de Kernel32.DLL. Attention toutefois é la fonction DossierTemp qui, d'une part s'appelle à l'envers par rapport aux 2 autres, et qui contient en plus un backslash à la fin

Déclarations

Declare Function DossierWindows Lib "Kernel32.dll" Alias "GetWindowsDirectoryA" (ByVal Pointeur As String, ByVal Longueur As Long) As Long

Declare Function DossierSystem Lib "Kernel32.dll" Alias "GetSystemDirectoryA" (ByVal Pointeur As String, ByVal Longueur As Long) As Long

Declare Function DossierTemp Lib "Kernel32.dll" Alias "GetTempPathA" (ByVal Longueur As Long, ByVal Pointeur As String) As Long

Utilisations

Sub test()
Dim Resultat As Long
Dim PointeurChaine As String
PointeurChaine = String$(255, 32)
Resultat = DossierWindows(PointeurChaine, 255)
MsgBox PointeurChaine
Resultat = DossierSystem(PointeurChaine, 255)
MsgBox PointeurChaine
Resultat = DossierTemp(255, PointeurChaine)
MsgBox PointeurChaine
End Sub

Récupérer le nom de l'ordinateur courant

Déclaration

Declare Function RecupNomOrdinateur Lib "Kernel32.dll" Alias "GetComputerNameA" (ByVal lpbuffer As String, nsize As Long) As Long

Utilisation

Dim NomOrdinateur As String
Dim Resultat As Long
NomOrdinateur = String$(255, 32)
Resultat = RecupNomOrdinateur(NomOrdinateur, 255)
MsgBox NomOrdinateur

Récupérer le nom de l'utilisateur courant

Cette fonction permet de récupérer non pas l'utilisateur Access (que l'on peut simplement obtenir avec CurrentUser), mais bien le nom d'utilisateur que l'on rentre lorsqu'on arrive dans Windows :

Déclaration

Declare Function RecupNomUtilisateur Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long

Implémentation

Function NomUtilisateur() As String
Dim StrNomUtilisateur As String
Dim Resultat As Long ' Contiendra simplement 1 si l'appel s'est bien déroulé
StrNomUtilisateur = String$(255, 0)
Resultat = RecupNomUtilisateur(StrNomUtilisateur, 255)
If Resultat = 1 Then
NomUtilisateur = StrNomUtilisateur
Else
NomUtilisateur = "UTILISATEUR INCONNU"
End If
End Function

Exemple d'utilisation

Sub Test()
MsgBox NomUtilisateur
End Sub