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 :

  • le programme principal, dont l'objectif est d'afficher via WMI quelques caractéristiques d'une imprimante connectée à un ordinateur local ou en réseau.

  • 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.

  • une subroutine de gestion des erreurs, le Error Handler.

 

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à.