VIII. API WinInet▲
Les API sont des fonctions que l'on trouve dans des librairies (fichiers .dll).
Ces fonctions ne sont pas directement utilisables par VBA, il n'y a pas de référence que l'on pourrait ajouter à l'éditeur VBA.
Il faut donc déclarer chacune de ces fonctions, en ciblant le bon fichier dll, et avec les paramètres requis.
Il faut également trouver les valeurs des constantes et déclarer les types.
C'est souvent un travail pénible, et on peut s'aider de sites tels que AllAPI.net
À partir d'Access 2010, une version 64 bits d'Office est disponible et demande une adaptation du code : Développer avec Office 64 bits
Avant de chercher la déclaration pour VB, la bible est MSDN : Windows Internet
MSDN est en anglais mais c'est ici que nous trouverons toute la documentation nécessaire.
Par contre, on n'y trouve rien pour VB...
En plus de fonctions communes, on trouve notamment dans WinInet un découpage en deux parties :
- les sessions HTTP.
- les sessions FTP.
Avant d'aller plus loin, voici quelques liens qui pourraient vous être utiles :
- Article Access : Repousser les limites d'Access - récupérer un fil RSS ;
- FAQ Excel : Comment récupérer le contenu d'un fichier txt placé sur internet ? ;
- Sources Access : Récupérer le code HTML d'une page Web à l'aide de l'APIWindows ;
- Sources Access : Récupérer le code HTML d'une page Web à l'aide de l'API Windows (2e méthode) ;
- Sources Access : Envoi/réception de fichier sur un serveur FTP.
Les codes trouvés dans ces pages sont exploitables quel que soit le produit Office utilisé.
VIII-A. Gestion d'erreurs WinInet▲
Lors de l'appel aux fonctions de l'API, les erreurs ne sont pas des erreurs VBA "classiques" que l'on peut gérer avec On Error.
Il faut vérifier le retour de chaque fonction (voir sur MSDN le retour en cas d'erreur), et en cas d'erreur utiliser Err.LastDllError pour connaître le numéro de l'erreur.
Les erreurs internet sont répertoriées ici : Error Messages.
Ou ici en français : INFO : Codes d'erreur WinInet (12001 à 12156).
VIII-B. Sessions HTTP▲
Cette partie est reprise dans la librairie Microsoft WinHTTP Services.
Si possible, il est beaucoup plus simple d'utiliser cette librairie que les API.
Pour une utilisation de l'API, nous allons avoir besoin de déclarer les fonctions, types, et constantes utilisés.
Ces déclarations doivent être écrites en en-tête de module.
Il faut d'abord trois fonctions pour se connecter à internet :
Private
Declare
Function
InternetOpen Lib
"wininet"
Alias "InternetOpenA"
(
ByVal
sAgent As
String
, _
ByVal
lAccessType As
Long
, ByVal
sProxyName As
String
, ByVal
sProxyBypass As
String
, _
ByVal
lFlags As
Long
) As
Long
Private
Declare
Function
InternetConnect Lib
"wininet"
Alias "InternetConnectA"
(
ByVal
hInternetSession As
Long
, _
ByVal
sServerName As
String
, ByVal
nServerPort As
Integer
, ByVal
sUserName As
String
, _
ByVal
sPassword As
String
, ByVal
lService As
Long
, ByVal
lFlags As
Long
, _
ByVal
lContext As
Long
) As
Long
Private
Declare
Function
InternetCloseHandle Lib
"wininet"
(
ByRef
hInet As
Long
) As
Long
Et voici les constantes dont nous avons besoin :
Private
Const
INTERNET_OPEN_TYPE_PRECONFIG =
0
Private
Const
INTERNET_SERVICE_HTTP =
3
Private
Const
INTERNET_INVALID_PORT_NUMBER =
0
Pour trouver la valeur d'une constante, recherchez dans Google le nom de la constante suivi de Declare.
On trouve alors la plupart du temps la valeur recherchée.
Dans une nouvelle procédure ConnectHTTP, nous allons nous connecter au site www.developpez.com.
Première étape, on se connecte à internet grâce à InternetOpen :
Dim
hOpen As
Long
hOpen =
InternetOpen
(
"SiteHTTP"
, INTERNET_OPEN_TYPE_PRECONFIG, vbNullString
, vbNullString
, 0
)
- Le premier paramètre est un nom libre.
- Le deuxième paramètre définit l'utilisation d'un proxy : INTERNET_OPEN_TYPE_PRECONFIG demande de rechercher le proxy configuré par défaut dans Windows.
- Les troisième et quatrième paramètres définissent des paramètres de proxy que nous n'utilisons pas ici.
- vbNullString est une chaîne de caractères spéciale qui indique qu'aucune valeur n'est passée en paramètre.
- Le cinquième et dernier paramètre est un flag (booléen) qui pourrait définir une exécution asynchrone ou la gestion du cache ; on ne l'utilise pas ici.
La fonction renvoie un identifiant (appelée handle) que nous devons conserver pour la suite.
Si la connexion est effectuée sans erreur, ce handle est différent de zéro.
Deuxième étape : la connexion au site web grâce à la fonction InternetConnect :
Sub
ConnectHTTP
(
)
Dim
hOpen As
Long
, hConnect As
Long
hOpen =
InternetOpen
(
"SiteHTTP"
, INTERNET_OPEN_TYPE_PRECONFIG, vbNullString
, vbNullString
, 0
)
If
hOpen <>
0
Then
hConnect =
InternetConnect
(
hOpen, "www.developpez.com"
, _
INTERNET_INVALID_PORT_NUMBER, vbNullString
, vbNullString
, INTERNET_SERVICE_HTTP, 0
, 0
)
End
If
End
Sub
- On réutilise en premier paramètre l'identifiant retourné par InternetOpen.
- Ensuite on indique l'adresse du site auquel on souhaite se connecter.
- En troisième paramètre on définit le port de connexion : utilisez INTERNET_INVALID_PORT_NUMBER pour le port par défaut en fonction du service défini ensuite.
- Un utilisateur et un mot de passe peuvent être définis si besoin dans les deux paramètres suivants.
- le sixième paramètre spécifie le service utilisé pour la connexion : HTTP ici, on pourrait indiquer FTP par exemple.
- les deux derniers paramètres sont inutilisés pour notre besoin.
La fonction renvoie également un identifiant (handle) que nous devons conserver pour la suite.
Si la connexion au site est effectuée sans erreur, ce handle est différent de zéro.
Il faut, à la fin, penser à fermer les connexions ouvertes avec InternetCloseHandle :
Sub
ConnectHTTP
(
)
Dim
hOpen As
Long
, hConnect As
Long
hOpen =
InternetOpen
(
"SiteHTTP"
, INTERNET_OPEN_TYPE_PRECONFIG, vbNullString
, vbNullString
, 0
)
If
hOpen <>
0
Then
hConnect =
InternetConnect
(
hOpen, "www.developpez.com"
, _
INTERNET_INVALID_PORT_NUMBER, vbNullString
, vbNullString
, INTERNET_SERVICE_HTTP, 0
, 0
)
If
hConnect <>
0
Then
InternetCloseHandle hConnect
End
If
InternetCloseHandle hOpen
End
If
End
Sub
Une fois la connexion établie, nous pouvons envoyer des requêtes à la page comme nous l'avions fait avec la librairie WinHTTP.
C'est toutefois bien plus complexe à coder avec les API.
Je vous invite, pour cette partie, à consulter cette source : Récupérer le code HTML d'une page Web à l'aide de l'API Windows (2e méthode).
Une autre source également intéressante, qui utilise InternetOpenUrl au lieu de InternetConnect :
Récupérer le code HTML d'une page Web à l'aide de l'APIWindows.
VIII-C. Sessions FTP▲
Pour cette partie, il n'y a pas de librairie disponible.
Seules les API nous permettent d'utiliser la partie FTP de WinInet.
VIII-C-1. Sessions FTP sans proxy▲
Un exemple est disponible dans les sources :
- Sources Access : Envoi/réception de fichier sur un serveur FTP.
L'utilisation est similaire à une session HTTP, à l'aide des fonctions : InternetOpen, InternetConnect et InternetCloseHandle.
La différence est la spécification du service FTP à l'appel de InternetConnect.
Il faut, à la place de INTERNET_SERVICE_HTTP, utiliser INTERNET_SERVICE_FTP qui se déclare ainsi :
Private
Const
INTERNET_SERVICE_FTP =
1
Dans l'exemple, la valeur 1 est utilisée directement.
Une fois la connexion établie, on peut utiliser les fonctions WinInet dont le nom commence par FTP.
VIII-C-2. Sessions FTP avec proxy▲
Vous rencontrez des problèmes de connexion si vous êtes derrière un proxy HTTP (de type CERN).
Ces deux articles de MSDN expliquent le principe d'un tel proxy et comment contourner le problème :
- Comment faire du FTP un proxy CERN en utilisant l'API WinInet ;
- Exemple : FTP proxy CERN protégé par mot de passe en utilisant l'API WinInet.
La solution est d'utiliser la fonction InternetOpenUrl.
Le mot de passe pour le FTP sera précisé dans l'adresse.
Voici un exemple :
Option
Explicit
Private
Const
INTERNET_OPEN_TYPE_PRECONFIG =
0
Private
Declare
Function
InternetOpen Lib
"wininet"
Alias "InternetOpenA"
_
(
ByVal
sAgent As
String
, ByVal
lAccessType As
Long
, ByVal
sProxyName As
String
, _
ByVal
sProxyBypass As
String
, ByVal
lFlags As
Long
) As
Long
Private
Declare
Function
InternetConnect Lib
"wininet"
Alias "InternetConnectA"
_
(
ByVal
hInternetSession As
Long
, ByVal
sServerName As
String
, ByVal
nServerPort As
Integer
, _
ByVal
sUserName As
String
, ByVal
sPassword As
String
, ByVal
lService As
Long
, _
ByVal
lFlags As
Long
, ByVal
lContext As
Long
) As
Long
Private
Declare
Function
InternetCloseHandle Lib
"wininet"
(
ByRef
hInet As
Long
) As
Long
Private
Declare
Function
InternetOpenUrl Lib
"wininet"
Alias "InternetOpenUrlA"
_
(
ByVal
hInternetSession As
Long
, ByVal
lpszUrl As
String
, ByVal
lpszHeaders As
String
, _
ByVal
dwHeadersLength As
Long
, ByVal
dwFlags As
Long
, ByVal
dwContext As
Long
) As
Long
Private
Declare
Function
InternetReadFile Lib
"wininet"
(
ByVal
hFile As
Long
, sBuffer As
Any, _
ByVal
lNumBytesToRead As
Long
, lNumberOfBytesRead As
Long
) As
Integer
Function
DownloadFTP
(
)
Dim
hOpen As
Long
Dim
hInternetFile As
Long
Dim
buffer
(
) As
Byte
Dim
lRead As
Long
Dim
f As
Integer
' Connexion internet
hOpen =
InternetOpen
(
"SiteWeb"
, INTERNET_OPEN_TYPE_PRECONFIG, vbNullString
, vbNullString
, 0
)
' Ouverture du fichier par son URL complète
hInternetFile =
InternetOpenUrl
(
hOpen, "ftp://login:pass@monftp.com/monfichier.gif"
, vbNullString
, 0
, 0
, 0
)
' Création du fichier cible sur le PC
f =
FreeFile
Open ThisWorkbook.Path
&
"\monfichier.gif"
For
Binary As
#f
' Lecture du fichier par paquet de 1024 bytes
Do
' Dimensionne le buffer pour accueillir 1024 bytes
ReDim
buffer
(
1
To
1024
)
' Lecture de 1024 bytes du fichier
If
InternetReadFile
(
hInternetFile, buffer
(
1
), 1024
, lRead) Then
If
lRead >
0
Then
' Redimensionne le buffer à la taille réellement lue
' Utilise Preserve pour ne pas effacer le contenu
ReDim
Preserve
buffer
(
1
To
lRead)
' Ecrit le buffer dans le fichier
Put #f, , buffer
(
)
Else
' Plus de données à lire => on sort de la boucle
Exit
Do
End
If
Else
' Erreur de lecture => on sort de la boucle
' Gestion d'erreurs à compléter ici
Exit
Do
End
If
Loop
' Fermeture du fichier
Close #f
' Fermeture de tous les handles
InternetCloseHandle hInternetFile
InternetCloseHandle hOpen
End
Function
On passe donc par HTTP pour télécharger un fichier sur un FTP.
Par contre on ne peut pas faire l'inverse, c'est-à-dire envoyer un fichier sur le serveur.
On verra dans le chapitre Winsock suivant comment envoyer un fichier par FTP en passant par un proxy.
IX. API URL Monikers (URLDownloadToFile)▲
Comme WinInet et Winsock, URL Monikers est une librairie dont nous devons déclarer les fonctions, types et constantes utilisées.
La liste des fonctions de cette API est sur MSDN en anglais : URL Monikers Functions.
Nous allons utiliser une seule fonction de cette API : URLDownloadToFile.
Elle est disponible à partir d'Internet Explorer 3.0 et Windows NT4.0, donc sur pratiquement tous les PC.
Très pratique, cette API va nous permettre de télécharger un fichier en une instruction.
Il faut d'abord déclarer la fonction en en-tête de module :
Private
Declare
Function
URLDownloadToFile Lib
"urlmon"
Alias "URLDownloadToFileA"
_
(
ByVal
pCaller As
Long
, ByVal
szURL As
String
, ByVal
szFileName As
String
, _
ByVal
dwReserved As
Long
, ByVal
lpfnCB As
Long
) As
Long
Ensuite l'appel de cette fonction est très simple :
Function
DownloadUrlMon
(
)
' Téléchargement depuis FTP avec mot de passe
URLDownloadToFile 0
, "ftp://login:pass@monftp.com/monfichier.gif"
, ThisWorkbook.Path
&
"\monfichier.gif"
, 0
, 0
' Téléchargement depuis HTTP
URLDownloadToFile 0
, "http://monsite.com/monfichier.gif"
, ThisWorkbook.Path
&
"\monfichier.gif"
, 0
, 0
End
Function
Je ne l'ai pas vu dans la documentation, mais la fonction utilise apparemment la configuration Windows par défaut du proxy.
Vous avez peut-être vu le dernier paramètre lpfnCB qui devrait permettre de récupérer des événements, notamment de progression du téléchargement.
Sa mise en œuvre est très complexe en VB.
Si vous souhaitez connaître la progression du téléchargement, je vous invite à utiliser WinInet comme vu dans le chapitre précédent.