La boîte à Tutoriels de Christopher PECAUD

Top

Utilisation de la bibliothèque de fonctions dynamique OLEPRN.DLL avec C#

Laisser un commentaire

SOMMAIRE

I. INTRODUCTION
II. LE PROTOCOLE SNMP
III. MISE EN OEUVRE DE SNMP avec C#
IV. EXEMPLE DE FONCTIONS
V. CONCLUSION

I Introduction

Au cours de ce tutoriel, je vais vous aider (enfin je l’espère) à concevoir une application permettant d’obtenir des informations sur chacune des imprimantes installées sur votre réseau. Pour ce faire nous allons utiliser la bibliothèque de fonctions dynamique oleprn.dll. Celle-ci renferme des fonctions qui permettent de dialoguer avec vos imprimantes avec le protocole SNMP. Nous allons ainsi pouvoir récupérer un certain nombre d’informations comme l’état de l’imprimante ou encore des consommables.

II Le protocole SNMP

Avant de commencer à coder notre application, je voudrai vous donner quelques informations sur ce protocole.

1. Définition

SNMP (Simple Network Management Protocol) est un protocole permettant de communiquer avec différents périphériques sur un réseau si ceux-ci le prennent en charge. Cela permet donc aux administrateurs réseau de pouvoir diagnostiquer rapidement une faille touchant un de ces éléments sur le réseau. Dans ce tutoriel nous allons nous intéresser seulement aux imprimantes, mais ce protocole permet de mettre en place une surveillance des hubs, des switchs, etc...

On communique avec ces périphériques par l’intermédiaire d’objets gérables qui sont rangés dans une table ordonnée que l’on appelle MIB (« Management Information Base »). La MIB contient donc différents objets renfermant une information spécifique pouvant être lue ou mise à jour apr l’intermédiaire du protocole SNMP via un identifiant que l’on nomme OID.

Pour plus d’informations sur ce protocole je vous renvoie sur la page wiki en anglais qui donne plus d’informations que la versions française : Voir.

2. Activer le protocole SNMP sur les imprimantes

Normalement toutes imprimantes récentes sont compatibles avec ce protocole, mais celui-ci n’est pas forcément activer par défaut, il convient donc de le faire par l’intermédiaire de l’interface de gestion web de l’imprimante.

3. Logiciel de navigation SNMP

Différents logiciels spécialisé existent pour effectuer une navigation de MIBs. Parmi les plus connus on peut citer Nagios, Cacti, etc... Je vous propose un petit logiciel plus simple à utiliser. Il s’agit de MIB Browser édité par la société iReasoning Network et il existe en plusieurs versions dont une gratuite pour un usage personnel qui est la Free Personal Edition. Cette version est téléchargeable à l’adresse suivante : Voir.

Lorsque l’application est démarrée il suffit de renseigner l’adresse ip dans le champ texte suivant :

image montrant la zone de texte permettant de taper l'adresse IP de l'imprimante

Une fois ceci effectué il devient possible de faire afficher les différentes OIDs...

En sélectionnant l’opération « Walk», vous aurez à votre disposition la totalité des OIDs disponibles pour ce périphérique, Voici un aperçu :

image montrant un aperçu des OIDs

Les autres opérations possibles sont :

  • « Get Next » permet de retourner la valeur OID du prochain objet dans l’arbre...
  • « Get » permet de déterminer la valeur d’un objet en donnant en paramètre la valeur de l’OID. Bien entendu l’OID doit exister pour que cette commande aboutisse.
  • « Get Bulk » permet de récupérer une liste de valeurs à a partir d’une liste d’OIDs. C’est une version améliorée de la commande « Get » idéale pour de très grandes MIBs.
  • « Set » permet de modifier la valeur d’une des variable de la MIB.

III Mise en oeuvre de SNMP sous C#

Nous allons maintenant passer aux choses sérieuses en montrant comment accéder aux fonctions de la bibliothèque de fonctions oleprn.dll.

1. Introduction

Dans ce tutoriel nous allons détailler les étapes nécessaires pour récupérer des informations concernant les imprimantes de votre réseau comme celles-ci :

  • Status : permet de récupérer l’état de l’imprimante à un moment donné (information fournie par l’utilisation de notre référence) ;
  • BlackTonerStatus : permet d’obtenir le pourcentage restant pour la cartouche noire de l’imprimante (information fournie par l’utilisation de notre référence) ;
  • MagentaTonerStatus : permet d’obtenir le pourcentage restant pour la cartouche magenta de l’imprimante (information fournie par l’utilisation de notre référence) ;
  • CyanTonerStatus : permet d’obtenir le pourcentage restant pour la cartouche cyan de l’imprimante (information fournie par l’utilisation de notre référence) ;
  • YellowTonerStatus : permet d’obtenir le pourcentage restant pour la cartouche jaune de l’imprimante (information fournie par l’utilisation de notre référence) ;

2. Préliminaires

Pour pouvoir utiliser les fonctions de cette bibliothèque, il faut ajouter la référence à celle-ci dans votre projet, via le menu contextuel habituel dans l'onglet OLE...

Pour les utiliser, n’oubliez de référencer celle-ci dans la partie import de votre fichier :

using OLEPRNLib;

3. Accès à l'imprimante via SNMP

L'accès aux fonctions de bibliothèque se fait très simplement de cette manière :
snmp = new SNMP();
snmp.Open(ipAdress, CommunityString, retries, TimeoutInMS); 

Avec :

  • ipAdress : l'adresse IP de l'imprimante;
  • CommunityString : La chaîne permettant de sécuriser l'accès SNMP par défaut "public";
  • retries : le nombre de d'essais de connexion (en cas d'échec);
  • TimeoutInMS : Nombre de millisecondes imparti pour tester l'accès à l'imprimante

Si la connexion s'est faite avec succès nous pouvons maintenant interrogé la MIB en sélectionnant un OID précis...

4. Obtenir une valeur précise en sélectionnant un OID

Nous avons deux fonctions qui nous permettent d'obtenir des valeurs qui sont :

  • Get : qui retourne un objet de type Object;
  • GetAsByte : qui retourne un objet de type entier;

Voici un exemple pour la fonction Get :

currentlevel = Convert.ToUInt32(snmp.Get(".1.3.6.1.2.1.43.11.1.1.9.1." + 
                                     tonerNumberDell.ToString()));
Cet exemple montre comment récupérer la valeur du niveau actuel d'un des toner de l'imprimante...

Voici un exemple pour la fonction GetAsByte :

uint WarningErrorBits = snmp.GetAsByte(String.Format("25.3.5.1.2.{0}", 
                                       DeviceId));

Cet exemple permet de récupérer une valeur sur un octet correspondant à l'objet hrPrinterDetectedErrorState. Nous verrons dans les annexes comment testé cette valeur pour obtenir l'état complet de l'imprimante.

5. Fermeture de l'accès

Après avoir obtenu les informations souhaitées il est nécessaire de fermer la connexion. ceci se fait grâce à la ligne de code suivante :

snmp.Close();
Maintenant nous avons toutes les informations nécessaires. Je vous propose maintenant les deux exemples de code qui permettent de récupérer l'état de l'imprimante et ensuite le niveau des toners de celle-ci.

IV Exemples de fonctions

1. Fonction de récupération de l'état de l'imprimante

Nous allons détailer maintenant la fonction qui nous permet de déterminer l'état du périphérique. Passons sans plus tarder à l’explication de la méthode de classe getStatus, dont voici le code :

public string getStatus(string ipAdress) {
SNMP snmp; 
int DeviceId = 1; 
int retries = 1; 
int TimeoutInMS = 2000; 
string Result1Str; string status; 
try {
string[] ErrorMessageText = new string[8];
ErrorMessageText[0] = "service recquis"; 
ErrorMessageText[1] = "Eteinte"; 
ErrorMessageText[2] = "Bourrage papier"; 
ErrorMessageText[3] = "porte ouverte"; 
ErrorMessageText[4] = "pas de toner"; 
ErrorMessageText[5] = "niveau toner bas"; 
ErrorMessageText[6] = "plus de papier"; 
ErrorMessageText[7] = "niveau de papier bas";

snmp = new SNMP();
snmp.Open(ipAdress, CommunityString, retries, TimeoutInMS); 
uint WarningErrorBits = snmp.GetAsByte(String.Format("25.3.5.1.2.{0}", 
                                       DeviceId));
uint statusResult =snmp.GetAsByte(String.Format("25.3.2.1.5.{0}", 
                                  DeviceId));

switch (statusResult)
{
case 2: Result1Str = "OK"; 
        break;
case 3: Result1Str = "Avertissement: "; 
        break;
case 4: Result1Str = "Test: "; 
        break;
case 5: Result1Str = "Hors de fonctionnement: "; 
        break;
default: Result1Str = "Code Inconnu: " + statusResult; 
         break;
}
string Str = ""; 

if ((statusResult == 3 || statusResult == 5)) {
   int Mask = 1; 
   int NumMsg = 0; 
   for (int i = 0; i < 8; i++) {
      if ((WarningErrorBits & Mask) == Mask) {
         if (Str.Length > 0) 
            Str += ", ";
         Str += ErrorMessageText[i]; 
         NumMsg = NumMsg + 1;
      }
      Mask = Mask * 2;
   } 
   }
  status = Result1Str + Str; 
  snmp.Close();
} 
catch (Exception) {
status = "Informations non disponibles...";
} 
return status;
}

Tout d’abord définissons les ressources dont nous avons besoin dans la MIB pour récupérer l’état complet de notre imprimante :

  • L’état de l’imprimante ;
  • Et en fonction de l’état de l’imprimante récupérer l’erreur ou l’avertissement.

L’état de l’imprimante est récupérable via les ressources respectives suivantes :

  • hrDeviceStatus dont l’OID est 1.3.6.1.2.1.25.3.2.1.5 ;
  • hrPrinterDetectedErrorState dont l’OID est 1.3.6.1.2.1.25.3.5.1.2 .

Ces ressources sont censées être des standard donc c’est pour cette raison que ces ressources ont des noms bien définis.

La première ressource nous renvoie un nombre entre 1 et 5 dont voici les significations :

  • 1 : erreur inconnu ;
  • 2 : OK en état de fonctionnement ;
  • 3 : avertissement : l’imprimante peut fonctionner mais un seuil d’alerte a été transmis ;
  • 4:est en test;
  • 5 : Hors de fonctionnnement l’état le plus critique.

Pour que la ressource hrPrinterdetectedErrorState nous renvoie une valeur il faut donc que que hrDeviceStatus nous renvoie une valeur égale à 3 ou 5. Cette valeur est codée sur un octet. La valeur dépend donc du bit dont la valeur est à 1, les autres étant positionnés à la valeur 0 :

  • Si bit 0 (valeur renvoyée 1) : service recquis ;
  • Si bit 1 (valeur renvoyée 2) : Eteiente ;
  • Si bit 2 (valeur renvoyée 4) : Bourrage Papier ;
  • Si bit 3 (valeur renvoyée 8) : porte ouverte ;
  • Si bit 4 (valeur renvoyée 16) : plus de toner ;
  • Si bit 5 (valeur renvoyée 32) : niveau toner bas ;
  • Si bit 6 (valeur renvoyée 64) : plus de papier ;
  • Si bit 7 (valeur renvoyée 128) : niveau de papier bas.

C’est pour cette raison que nous avons déclaré le tableau de chaîne de caractères ErrorMessageText.

Donc maintenant que nous savons ce que nous devons récupérer il faut mettre en place un accès SNMP. Rien de plus simple il suffit de créé une instance de l’objet SNMP et d’ouvrir la connexion grâce à la fonction Open qui prend en argument l’adresse IP du périphérique, la CommunityString qui permet d’assurer un niveau de sécurité étendu, puis ensuite nous avons le nombre d’essais de connexion voulu dans notre cas, on essayera de se connecter une seule fois, et le nombre de milisecondes demandées pour la tentative de connexion. Dans notre cas, et c’est le cas par défaut notre CommunityString est fixée à « public ». En effet dans ce petit projet nous nous connectons aue pour obtenir des informations. Si vous voulez aller plus loin il est nécessaire de mettre en place un niveau de sécurité avancé en définissant un accès SNMP v2 ou v3... Une fois que la communication avec l’imprimante est établie (si elle l’est pas on renvoie la chaîne de caractère « informations non disponible » que l’on gère par l’intermédiaire d’un bloc try...catch... pour éviter tout plantage) nous devons donc récupérer les valeurs définies précédemment.

Pour cela nous avons une fonction bien utile qui est GetAsByte prenant en paramètre l’OID que nous avons défini précédemment...

Donc nous récupérons les valeurs voulus respectivement dans les variables WarningErrorsBits et statusResult...

En fonction de la valeur stockée dans statusResult nous commençons à assigner à notre variable de type chaîne de caractère (Result1Str). L’étape suivante consiste à tester la valeur de statusResult pour savoir si elle est égale à 3 ou 5 auquel cas nous devons extraire le type d’erreur ou le type d’avertissement...

L’étape suivante consiste à créé un masque nous permettant de récupérer le bit qui est à 1 dans l’octet reccueilli. Il nous permet donc de compléter notre chaîne de retour avec le tableau ErrorMessageText en lui attribuant comme index le numéro de bit trouvé par le masque...

Il suffit ensuite de fermer la connexion avec la fonction Close().

2. Fonction de récupération du niveau des toners

Voyons maintenant comment récupérer l’état des consommables (toners).

Nous avons besoin de récupérer les valeurs fournies par les OIDs suivantes :

  • pour le toner noir .1.3.6.1.2.1.43.11.1.1.9.1.1 pour récupérer le niveau actuel et .1.3.6.1.2.1.43.11.1.1.8.1.1 pour récupérer le niveau maximal ;
  • pour le toner jaune .1.3.6.1.2.1.43.11.1.1.9.1.2 pour récupérer le niveau actuel et .1.3.6.1.2.1.43.11.1.1.8.1.2 pour récupérer le niveau maximal;
  • pour le toner cyan .1.3.6.1.2.1.43.11.1.1.9.1.3 pour récupérer le niveau actuel et .1.3.6.1.2.1.43.11.1.1.8.1.3 pour récupérer le niveau maximal ;
  • pour le toner magenta .1.3.6.1.2.1.43.11.1.1.9.1.4 pour récupérer le niveau actuel
  • et .1.3.6.1.2.1.43.11.1.1.9.1.4 pour récupérer le niveau maximal.

Attention ces valeurs devraient être standard mais ne le sont pas en pratique, c’est pour cette raison que j’ai effectué une conversion pour les imprimante Dell de la série 3010cn, cela devient donc :

  • pour le toner cyan .1.3.6.1.2.1.43.11.1.1.9.1.1 donc même traitement pour récupérer le niveau maximal;
  • pour le toner magenta.1.3.6.1.2.1.43.11.1.1.9.1.2 donc même traitement pour récupérer le niveau maximal;
  • pour le toner jaune.1.3.6.1.2.1.43.11.1.1.9.1.3 donc même traitement pour récupérer le niveau maximal;
  • pour le toner noir .1.3.6.1.2.1.43.11.1.1.9.1.4 donc même traitement pour récupérer le niveau maximal.

Donc reportez-vous à la notice du fabricant pour récupérer les bons OIDs...

Voyons maintenant comment ceci est mis en œuvre.

public string getTonerStatus(string ipAdress, string printerName, 
                                  int tonerNumber)
{
int DeviceId = 1; 
int retries = 1; 
int TimeoutInMS = 2000; 
int tonerNumberDell = 0; 
string status; 
try {
SNMP snmp = new SNMP(); 
snmp.Open(ipAdress, CommunityString, retries, TimeoutInMS);
switch (tonerNumber) {
   case 1: tonerNumberDell = 4; 
           break;
   case 2: tonerNumberDell = 3; 
           break;
   case 3: tonerNumberDell = 1; 
           break;
   case 4: tonerNumberDell = 2; 
           break;
}
switch (printerName) {
   case "Dell 3010 cn": currentlevel =
         Convert.ToUInt32(snmp.Get(".1.3.6.1.2.1.43.11.1.1.9.1." + 
                          tonerNumberDell.ToString()));
                        maxlevel = 
         Convert.ToUInt32(snmp.Get(".1.3.6.1.2.1.43.11.1.1.8.1."+
                          tonerNumberDell.ToString())); 
                        break;
   default: currentlevel =
         Convert.ToUInt32(snmp.Get(".1.3.6.1.2.1.43.11.1.1.9.1." + 
                          tonerNumber.ToString()));
            maxlevel = 
         Convert.ToUInt32(snmp.Get(".1.3.6.1.2.1.43.11.1.1.8.1." +
                          tonerNumber.ToString())); 
            break;
}
uint remaininglevel = (currentlevel * 100 / maxlevel); 
status = remaininglevel.ToString(); 
snmp.Close();
}

catch (Exception) {
status = "Informations non disponibles..."; 
}
return status;
}

Comme vous pouvez le constater nous avons besoin que d’une seule méthode générique getTonerStatus car les OIDs se ressemblent...

Il suffit d’indiquer en paramètres de la fonction le numéro (1, 2, 3 ou 4) pour récupérer les valeurs des OIDs correspondants...

La connexion SNMP se fait de la même façon que précédemment. Pour récupérer les valeurs des OIDs voulus nous allons utiliser une autre fonction qui est Get qui prend en argument la chaîne de caractère correspondant à l’OID demandé. Elle renvoie une valeur de type Object qu’il est nécessaire de convertir en type Uint32.

currentlevel = Convert.ToUInt32(snmp.Get(".1.3.6.1.2.1.43.11.1.1.9.1." + 
                                     tonerNumber.ToString()));

Lorsqu’on a récupéré les deux valeurs il suffit de réaliser l’opération qui va nous donner le pourcentage d’encre restant :

uint remaininglevel = (currentlevel * 100 / maxlevel);

V Conclusion

Nous avons vu comment réaliser une petite application simple permettant de scruter l’état de nos imprimantes installées en réseau en utilisant la bibliothèque de fonctions oleprn.dll. Nous avons vu qu’il est simple de récupérer des données sur des imprimantes grâce au protocole SNMP. Mais attention certains constructeurs ne respectent pas les standards, il faut donc réaliser un petit travail de recherche. Je vous propose au format pdf une version plus complète vous permettant de créer une petite application. Vous pourrez voir ainsi comment utiliser un fichier xml pour alimenter un composant de type propertyGrid.