SUPINFO International University

SUPINFO Institute of Information Technology
Laboratoire Microsoft




Tous les Articles du Laboratoire Microsoft

Programmation sur Tablet PC : Réalisation d’un outil de recherche de notes.
Accueil > Articles > Matériels
Auteurs 
Julien BAKMEZDJIAN



 Tous les articles de cet auteur

4,8/5

Très Bien


27140
83/401

Introduction

 

Voici le troisième article consacré au développement d’applications pour TabletPC. Nous avons vu les bases du SDK TabletPC qui permet de gérer l’interface et l’encre numérique (voir articles 1 et 2). Comme promis (!), nous allons maintenant commencer notre projet de réalisation d’un outil de recherche de notes. Le but sera de permettre à un utilisateur de rechercher une note dans un dossier. Les fichiers de notes seront des fichiers Office (.doc, .xls ou .ppt), texte (.txt), HTML, ou Windows Journal (.jnt). Les critères de recherche seront la date, la taille, le nom du fichier bien sûr, mais ils permettront également de rechercher des mots dans le fichier. C’est là que résidera d’ailleurs la plus grosse difficulté puisqu’il faudra tenir compte du formatage du fichier, ou même réaliser la reconnaissance de caractères pour les fichiers .jnt.

 

Présentation de l’application

 

Notre intention est de réaliser un outil de recherche permettant de retrouver une note rédigée par l’utilisateur ou l’un de ses collaborateurs. Lorsque Paul et Virginie participent à une réunion de projet, chacun prend des notes sur son TabletPC à l’aide du Windows Journal. Des rapports ont été rédigés, des fichiers textes saisis, des tableaux Excel enregistrés. Paul et Virginie vont en fait enregistrer leurs documents et notes dans un dossier partagé sur un ‘serveur’ central. Lorsqu’il souhaitera retrouver une note, Paul lancera une recherche sur ce dossier et accédera ainsi à toutes les notes prises par lui-même ou Virginie. On va même faire mieux : Paul pourra accéder à ce répertoire offline : dans le train, Paul recherchera une note dans un dossier local, copie exacte du dossier partagé. Pour lui tout se fera de manière transparente : lorsque Paul est déconnecté du réseau, une copie est réalisée, et lorsqu’il tente d’accéder au dossier partagé, il y accède comme si de rien n’était, avec le même chemin réseau… S’il modifie, ajoute ou supprime un fichier, ou si une modification a lieu sur le serveur, une synchronisation aura lieu à son retour au bureau.

Nous allons donc tout d’abord voir comment réaliser ce partage et cette synchronisation automatique. Ensuite, nous allons réaliser un moteur de recherche de fichiers dans un dossier. Ce moteur recherchera les documents dans le dossier partagé, que l’utilisateur soit connecté au réseau ou pas.

Notre moteur va filtrer les fichiers présents dans le dossier spécifié (et éventuellement les sous-dossiers) correspondant aux critères sélectionnés par l’utilisateur : date, taille, nom. Une fois cette recherche effectuée, le contenu des fichiers sera analysé, et si les mots recherchés s’y trouvent, le score du fichier sera augmenté. Le résultat de la recherche sera donc une liste de fichiers, à chacun étant associé un score de pertinence en fonction de son contenu.

Le point important de ce moteur sera la recherche dans le contenu. Il faudra en effet tenir compte du formatage du fichier, et notamment permettre la recherche dans le contenu des fichiers encre numérique du Windows Journal (.jnt).

 

Configuration de la synchronisation de fichiers

 

Il faut tout d’abord créer un dossier partagé sur un serveur accessible par tous les collaborateurs du projet. C’est directement sur ce dossier qu’ils créeront leurs fichiers, qu’ils soient connectés ou pas au réseau. Pour cela, il faut que chaque utilisateur configure sur son poste la synchronisation des fichiers. Pour synchroniser un dossier réseau, il suffit de le sélectionner dans l’explorateur et de faire ‘Fichier à Rendre disponible hors connexion’. Si c’est la première fois que vous utilisez les fichiers hors connexion, une boîte de dialogue apparaît vous invitant à configurer la synchronisation. Suivez les étapes :

 

 

 

Le dossier est maintenant disponible hors connexion, et sa synchronisation est automatique !

Pour plus de détails sur la synchronisation des fichiers, voir :

http://www.laboratoire-microsoft.org/articles/network/xp_sync/

 

 

Recherche dans tout type de fichiers

 

Le problème majeur rencontré lors de l’élaboration de notre moteur de recherche est, comme nous l’avons déjà fait remarquer, la recherche dans le contenu. La première solution à laquelle nous avons pensé est l’utilisation de l’automation.

 

Automation

 

L’automation consiste à ‘piloter’ via une interface COM une autre application. Cela se fait très simplement et permet par exemple d’ouvrir un document Word, de l’enregistrer dans un autre format (texte par exemple) puis de fermer Word. Voici le code C# correspondant :

 

      void DocToHtml(string docPath,string htmlPath)

      {

                  // ouverture de Word

            Word.Application app=new Word.Application();

                  // on le cache !

            app.Visible=false;

                  // pour les paramètres qu’on ne va pas fournir :

            object o=Missing.Value;

            object docFile=docPath; // chemin du doc avec transtypage

                  // Ouverture du document :

            _Document doc=app.Documents.Open(ref docFile,ref o,ref o,

                  ref o, ref o, ref o, ref o, ref o, ref o, ref o, ref o,

                  ref o, ref o, ref o, ref o, ref o);

            object fileName=htmlPath; // Chemin de destination

            object format=Word.WdSaveFormat.wdFormatText;//Txt

                  // On enregistre le doc au format texte :

            doc.SaveAs(ref fileName,ref format,ref o,ref o,ref o,ref o,

                  ref o,ref o,ref o,ref o,ref o, ref o, ref o,

                  ref o, ref o, ref o);

            object t=true;

                  // On quitte en évitant les messages de fermeture

            app.Quit(ref t,ref o,ref o);

      }

 

Pour l’utiliser, il suffit de rajouter la référence COM Microsoft Word x.xx Object Library ainsi que la directive using Word;. Notez également que pour éviter la confusion lors de la compilation entre Word.Application et System.Windows.Forms.Application, vous devez bien préciser le nom d’espace à chaque mention  de Application : par exemple System.Windows.Forms.Application.Run().

Par ce moyen d’automation, il devrait être possible d’enregistrer en format texte tous les documents sur lesquels on effectue la recherche puis d’ouvrir ces fichiers texte et de les lire afin d’effectuer la recherche. Cela permet de réaliser une recherche sur des formats propriétaires.

Un premier inconvénient est la lenteur de cette méthode : utiliser une liaison Automation est extrêmement lent, et si l’on doit répéter la méthode sur des centaines de fichiers, l’utilisateur risque vite de s’impatienter… Autre problème de la méthode, toutes les applications ne présentent pas une interface OLE Automation. Windows Journal notamment ne présente pas cette interface…

Nous devons donc envisager une autre méthode qui soit plus rapide et surtout plus ‘universelle’…

 

IFilter

 

La seule solution qui existe pour accéder au contenu des fichiers Windows Journal (.jnt) est l’utilisation de IFilter. (Pour des détails sur IFilter : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/indexsrv/html/ixrefint_9sfm.asp). IFilter est une interface qui possède des méthodes permettant d’extraire les données d’un fichier au format propriétaire. Un format de fichier peut implémenter cette interface, dans une dll qui contient les opérations d’extraction. Plusieurs de ces dll sont pré-installées dans Windows : pour les fichiers HTML, Word, Excel, PowerPoint, texte simple, fichiers binaires. Pour d’autres formats, la dll implémentant IFilter peut être installé et enregistré dans la registry (voir http://msdn.microsoft.com/library/default.asp?url=/library/en-us/indexsrv/html/ixufilt_56yb.asp). Dans le cas des TabletPC, le format Windows Journal est également supporté par défaut (pour le Windows Journal, l’implémentation de IFilter est faite dans JNTFiltr.dll)

Pour utiliser IFilter, nous allons redéfinir les constantes, structures et énumérations dont nous avons besoin, puis nous allons déclarer l’interface IFilter ainsi que la méthode LoadIFilter incluse dans la dll query.dll. C’est en effet LoadIFilter qui va charger pour chaque fichier l’implémentation du IFilter correspondant.

Nous allons donc créer un RunTime Callable Wrapper qui va nous permettre d’utiliser IFilter et LoadIFilter depuis le monde .Net. Voici le code correspondant aux déclarations de IFilter et de LoadIFilter :

 

using System.Runtime.InteropServices;

//...

//...

      /// <summary>

      /// Interface IFilter

      /// </sumary>

      // Cette interface est exposée à COM puisqu’elle est utilisée par

            LoadIFilter

      [ComVisible(true),

       Guid("89BCB740-6119-101A-BCB7-00DD010655AF"), // ID de IFilter

       CLSCompliant(false),        // Code non CLS

            // Interface IUnknown lorsque visible de COM :

       InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

      protected interface IFilter

      {

            /// <summary>

            /// Intialisation du IFilter

            /// </sumary>

            [PreserveSig] // L’interface est la même pour .Net et pour COM

            uint Init(

                  [MarshalAs(UnmanagedType.U4)] IFILTER_INIT grfFlags,

                  uint cAttributes,

                  [MarshalAs(UnmanagedType.LPArray)] FULLPROPSPEC[] aAttributes,

                  out IntPtr pdwFlags

                  );

 

            /// <summary>

            /// Récupération d'un Chunk

            /// </sumary>

            [PreserveSig] // L’interface est la même pour .Net et pour COM

            uint GetChunk(

                  [MarshalAs(UnmanagedType.Struct)] out STAT_CHUNK pStat

                  );

 

            /// <summary>

            /// Récupération d'une portion de Chunk

            /// </sumary>

            [PreserveSig] // L’interface est la même pour .Net et pour COM

            uint GetText(ref int pcwcBuffer, IntPtr awcBuffer);

      }

 

 

      /// <summary>

      /// Charge un IFilter

      /// </sumary>

      [DllImport("query.dll")]

      protected static extern int LoadIFilter(

                  [MarshalAs(UnmanagedType.LPWStr)] string pwcsPath,

                  IntPtr pUnkOuter,

                  [MarshalAs(UnmanagedType.Interface)] out IFilter ppIUnk

                  );

 

La définition de toutes les constantes liées à l’utilisation de IFilter est visible dans la première partie du code téléchargeable ici. Nous pouvons maintenant effectuer des recherches dans des fichiers au format propriétaire, y compris dans l’encre numérique des fichiers Windows Journal. Pour cela, il faut tout d’abord charger un IFilter :

 

IFilter filter;

LoadIFilter(file.FullName, new IntPtr(0), out filter);

 

On initialise ensuite notre filter :

 

      IntPtr uflags;

filter.Init(IFILTER_INIT.IFILTER_INIT_APPLY_INDEX_ATTRIBUTES,

                             0, null, out uflags);

 

Nous allons maintenant pouvoir lire notre fichier. Pour cela, il existe deux méthodes de IFilter : GetText() et GetChunk(). GetChunk renvoie le contenu du fichier morceau par morceau (chunk par chunk) au fur et à mesure de ses appels. Ensuite, pour chaque morceau, la méthode GetText() renvoie une partie du texte du chunk, au fur et à mesure de ses appels également. Pour savoir si GetChunk bute sur la fin du fichier ou si GetText bute sur la fin du chunk, il suffit de regarder leur valeur de retour. GetChunk renvoie 0 si tout est OK (s’il n’a pas rencontré la fin du fichier) et GetText peut renvoyer (entre autres) :

                        - 0 si pas de problème

                        - FILTER_S_LAST_TEXT si le texte renvoyé est le dernier

                        - FILTER_E_NO_MORE_TEXT s’il n’y a plus de texte

Voici donc le code permettant d’accéder à un fichier via IFilter :

 

uint retGT; // Valeur de retour du GetText

uint retGC = 0;   // Valeur de retour du GetChunk

IntPtr buff;      // buffer pour GetText

int buffSize;     // Taille du buffer pour le GetText

Char[] data = null;     // Tableau de caractères extraits

STAT_CHUNK statChunk;

string extractedData = ""; // Nouvelle string extraite du Chunk

while(retGC == IFILTER_RETURNED_VALUES.FILTER_OK)

{

            // On récupère un nouveau Chunk :

      retGC = filter.GetChunk(out statChunk);

            // On alloue le buffer :

      buff = Marshal.AllocHGlobal(2 * BuffSizeForChunk.BuffSize);            try

      {

                  // Initialisation de la taille du buffer :

            buffSize = BuffSizeForChunk.BuffSize; // Const à déclarer !!    

                  // Récupération de la nouvelle portion de texte :

            retGT = filter.GetText(ref buffSize, buff);   

                  // Tant qu'il y a du texte

            while((retGT == IFILTER_RETURNED_VALUES.FILTER_OK)

                  || (retGT == IFILTER_RETURNED_VALUES.FILTER_S_LAST_TEXT))

            {

                        // Allocation du tableau de caractères :

                  data = new Char[buffSize];                          

                        // Remplissage du tableau de caractères :

                  Marshal.Copy(buff, data, 0, buffSize) ;

                        // Recopie du tableau de caractères dans une string

                  extractedData = new string(data,0,buffSize);

                 

                  // Traitement sur la chaîne extraite

                  //…

                  //…

 

                        // Initialisation de la taille du buffer :

                  buffSize =  BuffSizeForChunk.BuffSize; // Const à

                                                        // déclarer !!

                        // Récupération de la nouvelle portion de texte :

                  retGT = filter.GetText(ref buffSize, buff);

            } // fin de la boucle sur un texte

      }

      catch

      {

      }

      finally

      {

            Marshal.FreeHGlobal(buff); // Libération du buffer

      }

} // fin de la boucle sur les Chunks

 

Nous allons maintenant écrire le corps de notre moteur de recherche. Notre objectif est de réaliser une dll qui permettra de lancer une recherche en précisant plusieurs paramètres (taille, dates, nom, recherche dans le contenu, respect de la casse, recherche dans les sous-dossiers…).

 

dll du moteur de recherche

 

Notre dll sera donc construite autour de IFilter et LoadIFilter. Nous allons présenter la dll classe par classe. Le code complet est disponible ici.

 

Détail des classes de la dll

 

SearchInFile

Cette classe est celle qui permet d’effectuer une recherche dans un fichier via IFilter. Elle ne contient qu’une seule méthode publique (et statique) : Run().

 

àIFILTER_INIT

                                   àCHUNK_BREAKTYPE

                                   àCHUNKSTATE

àPROPSPEC    

àFULLPROPSPEC

àSTAT_CHUNK

                                   àIFILTER_RETURNED_VALUES

Il s’agit d’énumérations, de structures et de classes protégées qui contiennent les paramètres utilisés par IFilter.

 

àLoadIFilter()

Cette déclaration est celle de la méthode LoadIFilter implémentée dans query.dll. On indique donc le nom de la dll ainsi que le mot clé extern. Les paramètres sont marshallés pour correspondre à ceux de la dll. Nous en rappelons le code :

 

 

      // Charge un IFilter

      [DllImport("query.dll")]

      protected static extern int LoadIFilter(

                  [MarshalAs(UnmanagedType.LPWStr)] string pwcsPath,

                  IntPtr pUnkOuter,

                  [MarshalAs(UnmanagedType.Interface)] out IFilter ppIUnk

                  );

 

                                   àIFilter

C’est la déclaration de l’interface. Reportez-vous à la partie précédente de cet article pour en voir le code.

 

                                   àRun()

Voici enfin la seule méthode exposée par SearchInFile. C’est cette méthode (statique) qui peut être appelée pour lancer une recherche dans un fichier. Son prototype est :

 

public static int Run(FileInfo file, ArrayList wordsList, bool caseSensitive)

 

Le premier paramètre est le chemin complet du fichier. Le second est le tableau contenant la liste des mots (ou expressions) à rechercher dans le fichier. Enfin, le troisième paramètre précise si la recherche doit respecter la casse.

Au début de la méthode, on transforme la liste des mots à rechercher en une hashtable : la hashtable contient un booléen qui nous permettra de savoir si un mot a déjà été rencontré ou pas (cette information sera utilisée pour le calcul du score).

Comme dit plus haut, on effectue ensuite deux boucles : l’une sur les chunks, l’autre sur les parties de texte de chaque chunk. Au cœur de ces deux boucles, on analyse le texte extrait : pour chaque mot de la hashtable, on parcourt la chaîne extraite et on compte le nombre de fois où le mot apparaît. On incrémente alors un compteur : si c’est la première fois que l’on rencontre le mot (on le sait par la valeur dans la hashtable), on augmente fortement le score. Sinon, on ajoute un nombre de points plus faible. Cela permet d’éviter qu’un fichier soit bien noté alors qu’une seule des expressions recherchées apparaît plusieurs fois, par rapport à un fichier où toutes les expressions n’apparaissent qu’à une seule reprise.

Comme le GetText() peut couper un mot n’importe où, et qu’une des expressions recherchées peut être à cheval sur chacune des coupures, il est important de reprendre une partie du GetText() précédent. On ne va cependant pas reprendre tout le texte précédent, mais seulement la fin, le nombre de caractères recopiés étant déterminé par la taille de la plus grande expression recherchée. C’est ce que l’on fait ici à l’aide des variables string oldData, string newData, int indexOfNewData, int MaxWordSize et de la méthode MaxLength() :

 

      int MaxWordSize = MaxLength(h); // h est la liste des expressions à rechercher

// …

// …

// Recopie du tableau de caractères dans une string :

      newData = new string(data,0,buffSize);

      // Calcul du nombre de caractères qu’il faut recopier :

      indexOfNewData = System.Math.Min(oldData.Length, MaxWordSize);

      // Concaténation de ces caractères avec la nouvelle chaîne :

      newData = oldData.Substring(oldData.Length - indexOfNewData) + newData;

 

      // Si on ne tient pas compte de la casse :

      if(!caseSensitive) newData = newData.ToUpper();

      // On lance la recherche dans la nouvelle string :

      score += SearchKeyWords(newData,h,indexOfNewData);

      // La nouvelle devient l’ancienne en fin de boucle :

      oldData = newData;

  

àInitHashtable()

Cette méthode initialise une hashtable en fonction de l'ArrayList passé. Au passage, les doublons sont éliminés. La hashtable rendue contiendra pour chaque expression de la liste un booléen initialisé à false. Ce booléen précise si l’expression a déjà été rencontrée dans le fichier en cours d’analyse. Lorsque l’expression est rencontrée pour la première fois, le score du fichier augmente fortement. Aux prochaines occurrences du mot, le score sera plus faiblement augmenté.

  

àSearchKeyWords()

Cette méthode recherche une liste d’expressions dans une string et renvoie un score.

 

à MaxLength()

Renvoie la taille de l’expression la plus longue de la liste passée en paramètre.

 

SearchInDirectory

            Cette classe présente une seule méthode publique (et statique) Run() qui permet de lancer la recherche dans un répertoire en précisant tous les paramètres de la recherche. C’est la principale méthode de notre dll, celle qui est appelée de l’extérieur lorsque l’on souhaite effectuer une recherche.

 

            àRun()

Cette méthode établit d’abord la liste des fichiers à partir des filtres sur le nom par appel à ListFiles(). Ensuite, les fichiers trouvés sont filtrés en fonction des autres critères de la recherche (taille, dates). Enfin, la méthode va associer un score à chaque fichier en faisant appel à SearchInFile.Run(). Le résultat de cette méthode est un tableau de ScoredFileInfo (pour une description de ce type, voir plus loin).

 

            àListFiles()

C’est une méthode privée qui liste tous les fichiers correspondant aux filtres sur le nom spécifiés. A noter que les filtres de la liste sont coordonnés par des ‘ou’ : si au moins un des filtres de la liste apparaît dans le nom du fichier, celui-ci est sélectionné. Des appels récursifs permettent de scanner les sous-dossiers le cas échéant.

 

 

SearchAttributes

Cette classe contient tous les paramètres possibles d’une recherche. Elle contient donc une liste d’attributs privés avec leurs propriétés publiques respectives. On trouve :

 

ArrayList filters;// Liste de filtres sur l'extension

bool subdirectories = false;// Inclure la recherche dans les sous-dossiers

string directoryPath = "";// Répertoire de recherche

ArrayList fileName;// Liste des mots pour la recherche sur le nom de fichier

ArrayList fileContent;// Liste des mots pour la recherche sur le contenu

System.DateTime startTime;// Date de début pour la recherche sur date

System.DateTime endTime;// Date de fin pour la recherche sur date

DateTypeSearch dateSearch = DateTypeSearch.Without;// Type de la recherche sur date

long minSize = 0;// Taille mini pour la recherche sur taille

long maxSize;// Taille maxi pour la recherche sur taille

bool sizeSearch = false;// Recherche sur la taille ?

bool caseSensitive = false;// Respect de la casse ?

 

• ScoredFileInfo

ScoredFileInfo est une classe contenant un membre FileInfo de type System.IO.FileInfo et un membre Score de type int (ce sont en réalité les propriétés des attributs fileInfo et score). On associe ainsi un score à un fichier : FileInfo contient toutes les informations sur le fichier et Score et le résultat de la recherche dans le contenu du fichier. Il aurait été ici plus adéquat de dériver la classe FileInfo, mais cela est malheureusement impossible puisque cette classe est scellée.

Nous avons redéfini la méthode Equals() avec deux surcharges afin de pouvoir comparer un ScoredFileInfo avec un FileInfo ou avec un autre ScoredFileInfo. La comparaison ne s’effectue que sur le FullName (on ne compare pas par exemple LastAccessTime car deux FileInfo du même fichier peuvent ne pas avoir le même…) :

 

            public bool Equals(FileInfo fi)

            {

                  // Comparaison du chemin des deux fichiers

                  return (this.FileInfo.FullName == fi.FullName);

            }

     

            public bool Equals(ScoredFileInfo fi)

            {

                  // Comparaison du chemin des deux fichiers

                  return (this.FileInfo.FullName == fi.FileInfo.FullName);

            }

 

• Bonus et BuffSizeForChunk

            Ces deux classes contiennent des membres int qui sont déclarés en const. Ces membres tiennent en fait lieu de constantes : en C#, la seule manière de faire un #define est de créer un membre const dans une classe… Vous pouvez donc en lieu et place des #define créer une classe qui contiendra toutes les constantes de votre programme.

 

• ExtendedArrayList

            Cette classe dérive de ArrayList. Elle ajoute une surcharge pour la méthode Contains(). Contains() permet maintenant de tester l’appartenance d’un ScoredFileInfo ou d’un FileInfo à la liste.

 

• DateTypeSearch

            Il s’agit d’une énumération contenant les différents types de recherche sur la date :

 

                  public enum DateTypeSearch : int

                  {

                        Without = 0,

                        Modification = 1,

                        Creation = 2

                  }

 

 

Création d’une dll en .Net

 

Il n’y a rien de plus simple : il suffit de  créer un projet bibliothèque de classes :

 

 

Ensuite, on crée ses propres classes dans le namespace.

Utilisation de la dll

 

Pour utiliser la dll dans un projet, il faut tout d’abord ajouter une référence vers cette dll. Pour cela, aller dans ‘ProjetàAjouter une référence’ et faites ‘Parcourir’. Sélectionnez la dll et validez. Pour l’utiliser plus facilement, vous pouvez ajouter en tête de votre code la directive : using SearchFiles;.

            Pour lancer une recherche sur des fichiers, il suffit de créer un objet SearchAttributes sa, de remplir tous ses champs dossier, date, taille, respect de la casse (les champs ont des valeurs par défaut, il n’est pas nécessaire de tous les saisir) et de remplir les listes de filtres sur le nom (Filters) et les expressions à rechercher dans le contenu (FileContent). Ensuite, on fait un appel à la méthode statique :

 

SearchInDirectory.Run(sa);

 

Le code d’une petite interface de test est disponible ici. Cette interface, extrêmement sommaire (elle ne contient d’ailleurs pas tous les paramètres possibles et la recherche ne s’effectue que sur une seule expression) permet de tester rapidement la dll. En outre, tous les résultats sont affichés sans tri et de façon un peu brute.

 

Conclusion

 

Nous avons réalisé une dll .Net permettant de rechercher des fichiers dans un dossier. La recherche s’effectue sur les nom, date et taille. Notre moteur de recherche permet également de préciser des expressions à rechercher dans le contenu du fichier. La recherche dans le contenu s’effectue en tenant compte du format du fichier (.doc, .html, .xls… et surtout .jnt). Le résultat de la recherche est une liste de fichiers correspondant aux critères de base (nom, taille, date), à chaque fichier étant associé un score correspondant à la pertinence de son contenu par rapport aux expressions recherchées.

 

Le code de la dll est disponible ici.

Le code de l’exe de test est disponible ici.

La dll est téléchargeable ici.

L’exe est téléchargeable ici.

 

Le code proposé est un code de base, qui peut être encore largement amélioré. Il serait par exemple pratique de pouvoir spécifier plusieurs répertoires de recherche. Un autre problème de la dll présentée est que le résultat de la recherche est rendu à la fin de toute la recherche : si la recherche est longue, la liste des fichiers n’apparaît qu’au bout de plusieurs dizaines de secondes. Il faudrait pouvoir envoyer au client la liste des fichiers au fur et à mesure que ceux-ci sont trouvés. Une autre amélioration possible serait la création d’une barre de progression de la recherche. Ces améliorations sont possibles en créant des événements.

 

Nous allons maintenant nous attacher à la réalisation d’une interface exploitant notre moteur. Cette interface contiendra plusieurs éléments orientés TabletPC (voir le premier article de cette série).




En Savoir Plus 
Evaluez cet article 


Pour afficher ou poster un commentaire, cliquez sur ce lien : Forum-Microsoft



Retrouvez ci-dessous les autres sections du Laboratoire Microsoft