8. 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'API Windows ;
- 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é.
8-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).
8-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'API Windows.
8-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.
8-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.
8-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.
9. 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.