Etude du script WMI_printer_error.vbs
Le script
WMI_printer_error.vbs nous semble intéressant car il montre assez bien,
à notre avis, l'intérêt de la programmation d'un Error Handler
lorsque celui-ci est capable de gérer des erreurs, d'afficher des
informations sur les erreurs, d'afficher des informations
complémentaires s'il y en a, et surtout d'afficher d'autres détails
s'il se produit une erreur au moment d'aller chercher ces informations
complémentaires.
Le script
WMI_printer_error.vbs est une première manifestation de la raison d'être
de ce site Web : montrer comment trouver facilement et efficacement
toutes les informations que Windows peut transmettre à
l'exploitant pour lui faciliter son travail de chaque jour.
Le script
WMI_printer_error.vbs, destiné à afficher quelques caractéristiques
d'une imprimante locale ou réseau, est utilisé trois fois dans l'exemple
ci-dessous à titre de démonstration du comportement du Error Handler
qu'il contient :
1° on demande les
caractéristiques d'une imprimante inexistante sur un ordinateur inexistant
ou inaccessible
2° on demande les
caractéristiques d'une imprimante inexistante sur l'ordinateur local
(représenté par le ".")
3° on demande les
caractéristiques d'une imprimante existante sur l'ordinateur local, en
utilisant une instruction correcte, puis une instruction incorrecte.
Pour télécharger le fichier
source de wmi_printer_error.vbs,
cliquer ici
(clic droit > enregistrer la cible du lien sous).
Pour afficher à
l'écran, dans une nouvelle fenêtre, le fichier source avec les lignes
numérotées,
cliquer là.
Avant de
commencer, précisons que le lecteur doit être familier avec la programmation
des objets de WMI. Si ce n'est pas le cas, il lui est fortement
recommandé de lire cette page.
Le script
wmi_printer_error.vbs comporte trois parties :
-
deux
fonctions appelées par le programme principal, une pour trouver le nom
de l'ordinateur local si l'utilisateur a entré un "." (point) sur la ligne
de commande lorsque le programme lui a demandé à quel ordinateur
l'imprimante en question est reliée, l'autre pour lire et afficher les
caractéristiques de celle-ci.
Cas n° 1 : imprimante inexistante sur un ordinateur inexistant ou
inaccessible
c:\vbs>wmi_printer_error toto titi
* Bind to WMI provider on computer 'TOTO'...
WMI>> GetObject failed
WSH>> Error occurred
WSH Action : GetObject
WSH Fatal error: 462
WSH Description: Le serveur distant n'existe pas ou n'est pas disponible
WSH Source : Erreur d'exécution Microsoft VBScript
Abort.
|
Voyons donc maintenant
ligne par ligne ce qui se passe lorsque l'utilisateur demande à consulter
les caractéristiques d'une imprimante inexistante sur un ordinateur
inexistant ou inaccessible (cas n° 1)
Remarque :
Tout ce qui suit étant destinée à une information sur la gestion
programmée des erreurs et non à une formation sur la
programmation avec VBScript, seules les lignes de code qui concerne
la gestion des erreurs sont commentées en détails.
Commençons.
Lignes 1 à 33
Le programme
s'initialise et demande les paramètres dont il a besoin pour accomplir son
traitement s'ils n'ont pas été spécifiés sur la ligne de commande. Ces
paramètres sont le nom de l'ordinateur cible et le nom de
l'mprimante à interroger.
Ligne 34
Si l'utilisateur
a entré un point, il indique par là que l'imprimante est connectée à son
ordinateur local (celui sur lequel il a lancé le script
wmi_printer_error.vbs). On fait donc appel à une fonction de recherche
du nom de l'ordinateur local (lignes 103 à 110). Cela uniquement pour
l'esthétique. On peut parfaitement accéder aux paramètres WMI d'un
ordinateur en utilisant le "." pour le désigner.
Ligne 40
On désactive la
gestion d'erreurs par défaut de VBScript qui fait que le script
s'arrête à la première erreur.
Ligne 41
On crée une
instance de l'objet WMI sur l'ordinateur cible.
Ligne 42
On teste le
succès de l'opération. Si l'instance n'a pas été créée, la variable
objWMIService n'est pas devenue un objet, et on affiche un message à
l'utilisateur. Mais on ne sait pas pourquoi l'instanciation a échoué.
Ligne 43
On appelle la
subroutine du Error Handler. Nous avons déjà vu ailleurs que la
programmation d'un Error Handler ne peut se faire de façon
asynchrone, donc l'appel à
celui-ci doit être systématique. Les paramètres passés à la subroutine sont
:
-
un code action
-
un code
sévérité
Le code action
permet à l'opérateur de savoir quelle action a généré une erreur, pour
faciliter le debugging.
Le code
sévérité permet de dire au Error Handler si le programme peut
continuer malgré cette erreur ou s'arrêter.
Dans une version
améliorée de notre Error Handler, on affichera aussi le numéro de la
ligne où s'est produite l'erreur.
Après le Call
ligne 43, on arrive ligne 144.
Lignes 144 à 159
Les codes erreur
peuvent être positifs ou négatifs. S'ils sont négatifs, c'est qu'ils
représentent une valeur hexadécimale codée binaire, donc on convertir la
valeur du code erreur en hexadécimal (ligne 149), puis on initialise
quelques variables avec des valeurs par défaut. Err.Description et
Err.Source sont des propriétés de l'objet Err au même titre que
Err.Number.
Lignes 160 à 183
Si il y a eu une
erreur, la valeur de la variable Err.Number est différente de zéro.
Selon la valeur du paramètre Severity, on peut sortir de la
subroutine sans rien faire (valeurs 0 : pas d'erreur, et 1 :
avertissement). Si Severity égale 2 c'est une erreur non
fatale. Par exemple, on veut écrire dans un fichier inexistant alors
qu'il devrait exister et le programmeur a oublié de tester son existence
avant d'écrire dedans. Le programme peut alors créer ce fichier. Ce n'est
pas une erreur fatale mais c'est une erreur quand-même. On l'affiche (ou on
l'enregistre dans un fichier de log) et on continue. Si Severity
égale 4, c'est une erreur fatale et on s'arrête. Dans le cas qui nous
occupe, l'ordinateur n'existe pas (ou est inaccessible). Le code a été
positionné à la valeur 4 au moment du Call, ce qui veut dire que s'il
y a une erreur au moment de la création de l'instance WMI sur
l'ordinateur cible, point n'est besoin de continuer. On informe et on
s'arrête via le Wscript.Quit 1 de la ligne 177.
Cas n° 2 : imprimante inexistante sur ordinateur existant
c:\vbs>wmi_printer_error . titi
* Bind to WMI provider on computer 'PCDIDIER'...
* Bind successful
* Get printer 'TITI' characteristics by DeviceID
*>> Printer TITI does not exist on computer PCDIDIER
[WMI> GetPrinterDeviceID failed]
WSH>> Error occurred
WSH Action : GetService
WSH Error nr : 80041002
WSH Description: Non trouvé
WSH Source : SWbemServicesEx
WMI>> Error context follows:
[WMI> creating SwbemLastError object]
[WMI> SwbemLastError object created successfully]
WMI Operation : GetObject
WMI Parameter : Win32_Printer.DeviceID="TITI"
WMI Provider : CIMWin32
Abort.
|
Lignes 1 à 160
Les lignes 1 à
160 s'exécutent de la même façon que dans le cas n°1, sauf que cette fois il
n'y a pas eu d'erreur au moment de la connection à l'objet WMI local.
Rappelons en passant que l'objet WMI est instancié par défaut au démarrage
de Windows, et si son instance est détruite, le premier appel à WMI en crée
une nouvelle.
Lignes 182 et 183
Puisque le test
de la ligne 160 est faux, on arrive à la ligne 182 et on sort de la
subroutine à la ligne 183. On se retrouve donc...
Ligne 44
On réinitialise
prudemment les propriétés de l'objet Err avec l'instruction
Err.Clear au cas où celles-ci auraient été impactées dans la subroutine
du Error Handler, ce qui efface entre autres le numéro de la dernière
erreur.
Ligne 48
On crée une
instance de l'imprimante.
Ligne 49
On teste le
succès de l'opération. Si l'instance n'a pas été créée, la variable
objShare n'est pas devenue un objet, et on affiche un message à
l'utilisateur lui disant pourquoi l'instanciation a échoué. On le sait car
la méthode utilisée est Get. Si on a une erreur après un Get,
c'est que l'objet n'existe pas. Ici c'est le cas.
Ligne 50
On informe
l'utilisateur.
Ligne 53
On sauvegarde la
valeur de l'erreur qui vient de se produire.
Ligne 54
On appelle la
subroutine du Error Handler pour gérer cette erreur. Comme le
programmeur sait qu'une erreur d'instanciation de WMI peut comporter
des informations complémentaires via l'objet SwebemLastError, la
sauvegarde du code erreur ligne 53 permet de savoir s'il faut instancier au
retour du Error Handler l'objet WMI_Error ou non (sinon le
message s'afficherait même s'il n'y avait pas d'erreur).
Lignes 55 à 71
Il y a une
erreur, et elle est fatale puisque l'imprimante n'existe pas (sinon son
objet aurait été instancié). On informe et on termine l'exécution du script.
Cas n° 3 : imprimante existante sur ordinateur existant, avec erreur de
programmation
c:\vbs>wmi_printer_error . samsung
* Bind to WMI provider on computer 'PCDIDIER'...
* Bind successful
* Get printer 'SAMSUNG' characteristics by DeviceID
Default
: Vrai
DriverName :
Samsung CLP-310 Series
Horizontal Resolution: 600
Network connection : Faux
Port Name
: USB001
* Get printer 'SAMSUNG' characteristics by Name
WSH>> Error occurred
WSH Action : GetService
WSH Error nr : 8004103A
WSH Description: Chemin de l’objet non valide
WSH Source : SWbemServicesEx
WMI>> Error context follows:
[WMI> creating SwbemLastError object]
WMI>> SwbemLastError CreateObject failed
WSH>> Error occurred
WSH Action : CreateObject
WSH Fatal Error: 80004005
WSH Description: [missing]
WSH Source : [missing]
c:\vbs> |
Ce cas est
particulièrement intéressant car on va voir ici que le Error Handler programmé
dans ce script est aussi capable de gérer d'éventuelles erreurs lors d'une
demande d'affichage d'informations complémentaires sur une erreur qui vient
de se produire.
Lignes 1 à 74
Rien de
particulier, tout va bien, on rentre dans le Error Handler plusieurs
fois et on en ressort aussitôt puisqu'il n'y a pas d'erreurs à traiter.
Lignes 75 à 81
Ca se complique
car la méthode Get n'est pas autorisée pour une imprimante instanciée
via son nom. Cependant, pour une raison qui ne nous est pas encore connue,
la variable objShare devient un objet, donc le test de la ligne 76
est inefficace. Heureusement, fidèles à nos principes, nous appelons
quand-même le Error Handler ligne 81 "au cas où". Et justement, le
"cas où" ! Nous obtenons donc l'affichage de l'erreur sur le GetService
et son explication.
Ligne 82 à 86
Au retour du
Error Handler, comme nous avions sauvegardé ligne 80 le code erreur,
nous savons qu'il y a eu un problème et nous allons donc chercher des
informations complémentaires via l'objet SwebemLastError. Du moins le
pensons-nous.
Ligne 87 à 98
On instancie
l'objet SwebemLastError mais celui-ci n'est pas disponible car
l'instanciation de la ligne 75 a échoué. Le test de la ligne 88 nous en
informe (via la ligne 91), et la ligne 92 nous renvoie une fois de plus à
notre subroutine de gestion d'erreurs, qui cette fois va nous parler de
SwebemLastError. Comme c'est une erreur fatale (parce que le programmeur
l'a décidé en utilisant la constante Sev_Fatal), le Error Handler
traite l'erreur et la procédure s'arrête.
Voilà. |