Développer des applications sous Windows Vista - partie 2

Louis-Guillaume MORAND

Avec l'arrivée du nouveau système d'exploitation Windows Vista, un grand nombre de fonctionnalités ont été présentées aux utilisateurs, tant au niveau de la sécurité que d'améliorations graphiques ou interactives. Pour les développeurs, il est alors possible d'intégrer ces nouveautés au sein de leurs applications et c'est ce que cet article va tâcher de présenter. ♪

- Titre : Développer des applications sous Windows Vista - partie 2

- Auteur : Louis-Guillaume MORAND

- Parution : 11 janvier 2008

- Licence : Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.

Sommaire

- Introduction

- I. Travailler avec les adaptateurs réseau

- II. Utiliser la plateforme RSS de Windows Vista

- II-A. Présentation

- II-B. Mise en place

- II-B-1. Chargement de la plateforme dans votre application

- II-B-2. Lecture d'un flux

- II-B-3. Abonnement à un flux

- II-C. Pour aller plus loin

- III. Interagir avec Windows Desktop Search

- IV. Amélioration des interfaces graphiques

- IV-A. Modifier les progressBar

- IV-B. Intégrer le comportement de Vista dans vos treeview

- IV-C. Utilisez le bouton Command Link dans vos applications

Introduction

Après une première partie sur les développements qu'il est possible de faire dans Vista, nous allons continuer à découvrir ce qu'il est possible de faire sous ce système d'exploitation.

I - Travailler avec les adaptateurs réseau

Pour ceux qui connaissent bien WMI (Windows Management Instrumentation), ils doivent savoir qu'il est relativement aisé de lister les adaptateurs réseau de la machine ainsi que les informations sur ces derniers. Dorénavant, sous Vista, il existe une API qui permet de travailler non pas sur les adaptateurs, mais directement sur les connexions. Cela permet entre autres de savoir très facilement si un ordinateur est connecté à Internet sans nécessiter de faire un PING sur un quelconque site web.
J'ai trouvé cette astuce sur le blog de Max Knor qui décrit comment, avec une librairie système, il est possible de rendre son application « network aware ».

Commencez par créer un nouveau projet pour lequel vous ajouterez une référence vers la librairie « Network List Manager 1.0 Type Library » puis ajoutez le namespace correspondant (« NETWORKLIST »).

Créez alors un objet NetworkListManagerClass, puis instanciez-le :

initialisation de notre objet

NetworkListManagerClass _networkListManager;
_networkListManager = new NetworkListManagerClass();

Sur cet objet nouvellement créé, il est déjà possible de connaitre le statut des connexions, pour savoir si par exemple il est possible d'accéder à Internet :

lblReseau.Text = (_networkListManager.IsConnected) ? "Oui" : "Non";
lblInternet.Text = (_networkListManager.IsConnectedToInternet) ? "Oui" : "Non";

Mais, même si cette propriété est très importante puisque pour les applications ayant besoin de faire une mise à jour ou autre cela permet très rapidement de savoir si cela sera possible ou non, d'autres fonctionnalités se cachent au sein de cet objet.
Ainsi, nous allons voir qu'il devient facile de récupérer des informations très facilement sur les connexions de l'ordinateur. Nous allons d'abord les lister et pour cela nous allons itérer sur une collection d'objets InetworkConnection.

Dans mon cas, je stocke les informations qui m'intéressent (le nom et l'id de la connexion) dans une classe interne afin de binder ma collection d'objets sur une combobox (j'aurai besoin de ces infos peu après) :

on liste les connexions actuelles

List<Reseau> malist = new List<Reseau>();
foreach (INetworkConnection c in _networkListManager.GetNetworkConnections())
{
malist.Add(new Reseau(c.GetNetwork().GetName(),c.GetConnectionId()));
}

Enfin, implémenter l'événement qui, une fois une connexion sélectionnée, permet de lister certaines de ses informations :

Listing des informations détaillées

private void getInfo(Guid gu)
{
INetworkConnection c = _networkListManager.GetNetworkConnection(gu);

lblNom.Text = c.GetNetwork().GetName();
lblDesc.Text = c.GetNetwork().GetDescription();
lblType.Text = c.GetNetwork().GetDomainType().ToString();
}

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
getInfo((Guid)comboBox1.SelectedValue);
}

Mon application affiche alors le résultat suivant (Note : « pharaonix » est le nom d'une connexion Wi-Fi) :

Pour finir, je tiens à signaler qu'il est possible de modifier soit même les connexions en changeant leur nom, description ou même type (Privé, Public, Bureau). Des méthodes sont là pour ça :

Modification du nom de la connexion

c.GetNetwork().SetName("DVP Rox");

II - Utiliser la plateforme RSS de Windows Vista

II-A - Présentation

Au sein de Windows Vista, Microsoft a décidé d'intégrer une plateforme commune de gestion de flux RSS. Gérant aussi bien les flux RSS au format RSS 2.0 ou même ATOM 1.0, cette plateforme, « invisible », permet de centraliser l'abonnement et l'agrégation de différents flux RSS et vous donne la possibilité de l'intégrer au sein de vos applications comme le fait Internet Explorer 7.
Il est possible de faire énormément de choses avec cette plateforme RSS et vous pouvez l'utiliser de différentes manières et dans différents contextes au sein de vos applications, néanmoins, dans cet article, je me contenterai de ne présenter que les fonctionnalités basiques. Pour plus d'informations, il vous suffira de lire l'article plus complet disponible à cette adresse.

II-B - Mise en place

II-B-1 - Chargement de la plateforme dans votre application

Commencez par ajouter la libraire Microsoft Feeds à votre projet puis importez-la avec :

using Microsoft.Feeds.Interop;

Puis créez un FeedsManager, qui sera le point central de la gestion des flux RSS.

FeedsManager myFMng = new FeedsManager();

II-B-2 - Lecture d'un flux

La fonctionnalité que vous utiliserez à coup sûr sera la lecture d'un flux. Bien sûr, un flux RSS n'est qu'un fichier XML disponible sur Internet et il existe de nombreuses façons de le lire, mais la façon la plus simple de le faire et surtout en gérant d'un coup plusieurs formats RSS, est d'utiliser la plateforme RSS.

Comme nous l'avons vu sur le schéma précédent, l'objet FeedsManager permet de gérer des flux (Feed) qui eux, contiennent des FeedItem. Ce sont donc ces FeedItem que nous allons chercher à récupérer.

Commençons par récupérer le répertoire racine de tous les feeds possibles :

IFeedFolder myRootFld = (IFeedFolder)myFMng.RootFolder;

Nous allons ensuite récupérer le Feed souhaité dans ce dossier (à vous de vérifier qu'il se trouve bien dans le dossier racine) :

IFeed  myF = (IFeed)myRootFld.GetFeed(feed);

Maintenant que nous avons notre flux, il nous suffit de boucler sur ses objets sous-jacents (innertype) :

foreach (IFeedItem fit in (IFeedsEnum)myF.Items)
{
// à vous de mettre le traitement de votre choix sur les items
ListViewItem lvi = new ListViewItem(fit.Title);
lvi.SubItems.Add(fit.Author);
lvi.SubItems.Add(fit.PubDate.ToShortDateString());
listView2.Items.Add(lvi);
listView2.Items[listView2.Items.Count - 1].BackColor =
(listView2.Items.Count % 2 == 0) ? Color.Gainsboro : Color.White;
}

Et c'est tout. Lire des flux RSS d'un site web se résume à trois lignes de code, là où il fallait avant un XMLDocument et des règles de parsing différentes selon le format du flux RSS. Pensez donc à ces quelques lignes de code le jour où vous souhaitez lire un flux RSS.

II-B-3 - Abonnement à un flux

Nous avons vu avant comment lire les billets des flux déjà enregistrés (souvent via Internet Explorer 7), nous allons maintenant voir comment ajouter de nouveaux flux. Pour vous abonner à un flux, rien de plus simple. Tout d'abord, pour éviter une exception de la part de la plateforme, vous allez vérifier que l'URL du flux n'est pas déjà enregistrée.

if (!myFMng.IsSubscribed("http://dotnet.developpez.com/rss.php"))
{
// code d'abonnement
}

Puis, avez une seule ligne de code, vous allez enregistrer votre flux :

(myRootFld.CreateFeed("rubrique Dotnet", "http://dotnet.developpez.com/rss.php");

Avec cette simple ligne de code, vous vous assurez que le flux est bien gardé dans la plateforme et que celle-ci sera en mesure de vous indiquer quand ce flux a été mis à jour. Elle fait tout, toute seule.

II-C - Pour aller plus loin

Si vous souhaitez avoir un article plus complet sur l'intégration des RSS au sein de vos applications .Net alors vous pouvez visiter le lien suivant.

III - Interagir avec Windows Desktop Search

Windows Desktop Search est le système d'indexation de Microsoft qui, une fois intégré au système permet de retrouver rapidement tout type de fichier. Si Windows Desktop Search existe sous plusieurs versions, il est surtout par défaut installé sur Windows Vista. Il peut alors être très intéressant d'interroger l'index au sein de vos applications et de l'utiliser sous la forme qui vous arrange le plus.

La méthode la plus simple pour interroger une source de données en .Net reste l'utilisation d'ADO.Net. C'est non seulement la plus simple, mais aussi la plus couramment utilisée. Avec Windows Desktop Search, nous ne dérogerons pas à la règle et nous n'aurons que deux petites choses sur lesquelles faire attention.
Tout d'abord en choisissant un provider adapté : il s'agit du provider OleDb, et ensuite en spécifiant une chaine de connexion particulière pour nous permettre d'interroger le gestionnaire de l'indexation de Windows Desktop Search. La chaine de connexion est particulière à WDS et reste simple : « Provider=Search.CollatorDSO;Extended Properties='Application=Windows'; »

Commençons par créer notre connexion puis par l'ouvrir

OleDbConnection connection = new OleDbConnection("Provider=Search.CollatorDSO;Extended Properties='Application=Windows';");
connection.Open();

Puis déclarons notre objet OleDbCommand qui représentera notre requête auprès de l'index

var command = new OleDbCommand {Connection = connection, CommandText = "ma requete"};

Note : notez que le code précédent provient de C# 3.0 et utilise le mot-clé var ainsi que les nouveaux initialiseurs d'objets. En 2.0, il correspondrait à :

OleDbCommand co = new OleDbCommand();
co.Connection = connection;
co.CommandText = "ma requete";

Et enfin le code de lecture du résultat :

OleDbDataReader reader = command.ExecuteReader();
while (reader.Read())
{
// traitement de votre choix sur les résultats retournés
// exemple MessageBox.Show(reader.GetString(0));
}
reader.Close();

Cela n'est pas plus complexe que cela, et il est ainsi possible d'afficher très rapidement les informations de fichiers retrouvés via WDS à condition bien entendu que la requête soit correcte.

Windows Desktop Search est tout sauf bavard et en cas d'exception ne vous attendez pas à trouver rapidement la source du problème. Par exemple, si l'une des informations demandées (nom de colonne) était erronée, il vous renverrait une exception avec pour seul texte : E_FAIL(0x80004005). Pensez donc à vérifier les noms des colonnes lorsque vous avez cette erreur. La difficulté étant de connaitre ces noms de colonnes puisque malheureusement, d'une version à l'autre de Windows Desktop Search, celles-ci changent…

Voici donc un exemple complet de recherche :

OleDbConnection connection = new OleDbConnection("Provider=Search.CollatorDSO;Extended Properties='Application=Windows';");
connection.Open();
var command = new OleDbCommand { Connection = connection,
CommandText = String.Format("SELECT Top 5  System.ItemUrle, System.ItemName,System.Title
FROM systemindex WHERE CONTAINS(\"System.FileName\", '\"*{0}*\"')", "plage") };
OleDbDataReader reader = command.ExecuteReader();
lsvSearch1.Items.Clear();
while (reader.Read())
{
lsvSearch1.Items.Add(new ListViewItem(new[] { reader.GetString(0) }));
}
reader.Close();

Il ne s'agit ici que d'une explication rapide de l'utilisation de Windows Desktop Search. Si vous voulez plus d'informations, lisez l'article suivant.

IV - Amélioration des interfaces graphiques

Comme pour la première partie, nous allons finir par présenter des améliorations graphiques qu'il est possible d'ajouter à vos applications.

IV-A - Modifier les progressBar

C'est en trainant sur des forums anglophones que je suis tombé sur un thread où l'une des personnes disait qu'il existait des progressbar de plusieurs couleurs sous Windows Vista. C'est en fouillant sur la MSDN que j'ai trouvé qu'il était possible de définir trois états à une progressbar. Sur ce lien, il y est justement expliqué comment, à l'aide de l'API SendMessage, il était possible d'envoyer un état à une progressbar.
Suivons alors les instructions pour importer la méthode SendMessage http://msdn2.microsoft.com/en-us/library/bb760850.aspx http://www.codeproject.com/vista/themedvistacontrols.asp

Import de la méthode SendMessage

DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern uint SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);

Plaçons alors trois progressBar sur un formulaire de test. Puis en cherchant en peu sur Internet, nous trouvons les valeurs des constantes nécessaires. En effet, ces valeurs se trouvent normalement dans le fichier commctrl.h qui peut être trouvé dans le SDK de Vista

Envoi de message au contrôle progressBar

const int WM_USER = 0x400;
const int PBM_SETSTATE = WM_USER + 16;
const int PBST_NORMAL = 0x0001;
const int PBST_ERROR = 0x0002;
const int PBST_PAUSED = 0x0003;
SendMessage(progressBar2.Handle,
PBM_SETSTATE,
PBST_PAUSED, // pause
0);

SendMessage(progressBar3.Handle,
PBM_SETSTATE,
PBST_ERROR, // erreur
0);

Dans le code précédent, nous mettons notre deuxième progressBar en pause tandis que nous envoyons le statut erreur à la troisième progressBar. Ceci nous donne alors trois progressBar dont les deux dernières sont immobiles, mais surtout d'une couleur différente.

Ainsi donc, il est possible d'avoir des progressBar de différentes couleurs, mais avec ces méthodes, il s'agit surtout de représenter l'état d'une action de votre application via la couleur de la progressBar.

IV-B - Intégrer le comportement de Vista dans vos treeview

Il est ici d'une modification fonctionnelle du Treeview plus qu'une modification visuelle. En effet, si vous avez déjà regardé le treeview de l'explorateur Windows de Vista, vous auriez remarqué deux choses :
- le thème Vista : surlignement bleuté, petites flèches en lieu et place des + et – habituels ;
- un scrolling horizontal automatique. Lorsque vous choisissez un nœud enfant dont le nom n'apparait pas complètement, le treeview scroll vers la droite pour aligne le début du nœud.

Il est donc ici une fois de plus question d'amélioration de « l'expérience utilisateur » et de rendre votre application encore un peu plus facile d'utilisation

Explorateur Vista

Commençons par importer l'API SendMessage :

Méthode SendMessage

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern uint SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);

Nous allons devoir utiliser deux commandes différentes pour gérer à la fois le scroll automatique, mais également le thème Vista.

Ajout du scroll automatique

const int TVM_SETEXTENDEDSTYLE = TV_FIRST + 44;
const int TVS_EX_AUTOHSCROLL = 0x0020;
SendMessage(treeView1.Handle, TVM_SETEXTENDEDSTYLE, 0, TVS_EX_AUTOHSCROLL);

Et pour le style Vista :

Ajout du thème Vista

SetWindowTheme(treeView1.Handle, "explorer", null);

Ce genre de petite amélioration peut sembler superflue à première vue, mais un bon développeur ne doit pas perdre de vue que c'est en rajoutant de petites améliorations qu'il rendra son application plus « parfaite » aux yeux des utilisateurs.
Voici la différence entre un composant TreeView avec le thème Vista (gauche) et le composant ne l'ayant pas.

IV-C - Utilisez le bouton Command Link dans vos applications

Après avoir vu comment ajouter un bouclier sur vos boutons dans la première partie, nous allons voir comment implémenter les « Command link » boutons que vous pouvez trouver au sein de Windows Vista. En voici un exemple.

Un bouton « Command link » se distingue par trois choses :
- une image d'une flèche ;
- un texte principal ;
- un second texte plus petit se trouvant sous le texte principal.

À l'inverse des autres modifications de composants, il est nécessaire ici de recréer une classe complète héritant du contrôle Bouton et dans laquelle nous devrons surcharger et redéfinir certaines méthodes par exemple la méthode CreateParams. Plutôt que vous embêtez à coder cette classe, j'ai déniché sur le net une classe toute faite, écrite par Max Knor et qui publie le code a cette adresse. Importez donc cette classe dans votre application puis créez le code qui ajoutera un bouton à l'endroit voulu.
Dans mon exemple, je vais créer deux commandLink buttons que je placerai dans l'un des onglets de mon application de démonstration

CommandLink btn = new CommandLink();
btn.Note = "sa description";
btn.Text = "ma commande";
tabControl1.TabPages[2].Controls.Add(btn);
btn.Top = 10;
btn.Left = 30;
btn.Cursor = Cursors.Hand;

CommandLink btn2 = new CommandLink();
btn2.Note = "test";
btn2.Text = "ma commande2";
tabControl1.TabPages[2].Controls.Add(btn2);
btn2.Top = 80;
btn2.Left = 30;
btn2.Cursor = Cursors.Hand;

Ce petit bout de code, aussi simple que si vous utilisiez un composant normal, vous permet de placer le bouton puis d'éditer ses propriétés en mode Design.