Développer des applications sous Windows Vista - partie 3

Avec l'arrivée du nouveau système d'exploitation Windows Vista, un grand nombre de fonctionnalités se sont vues 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 possibles d'intégrer ces nouveautés au sein de leurs applications et c'est ce que cet article va tâcher de présenter.

N'hésitez pas à commenter cet article ! Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

Introduction

Après une première et une seconde 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 nouveau système d'exploitation.

1. Créer une application dans le panneau de configuration

Dans un article précédant, j'expliquai comment il était possible de personnaliser le Welcome Center et dans un autre, j'expliquai le développement de widget pour la SideBar. Aujourd'hui, nous allons nous attaquer à quelque chose de pas forcément plus compliqué, moins évident à mettre en pratique, mais qui, j'en suis sûr, pourra trouver une utilité pour certains d'entre vous. Nous allons voir comment personnaliser le panneau de configuration pour y faire apparaitre nos propres éléments.

Depuis de nombreuses années, la personnalisation d'une application ou d'un système d'exploitation fait partie de mes passe-temps favoris. Et alors que je cherchais à comprendre comment marchait Windows 2000 à l'époque, je me rappelle avoir été intrigué par un élément nvidia ajouté à mon panneau de configuration et j'ai cherché à l'enlever, car...l'icône était laide (oui oui). J'ai alors découvert qu'il s'agissait simplement de fichier *.cpl développé et enregistré sur le système.
Pour ceux qui voulaient développer leur propre composant, il leur fallait suivre scrupuleusement les étapes décrites sur la MSDN.

Une chance pour nous, tout ceci a été revu sous Windows Vista et il est devenu très simple de personnaliser le panneau de configuration, peut-être même aussi simple que la personnalisation du Welcome Center.

Voici un exemple simple de ce que vous saurez faire avec cet article :

1.1. Création d'un GUID

Ce petit mini chapitre est presque hors contexte puisqu'il va simplement vous expliquer comment générer un GUID. Un GUID est un Global Unique IDentifier, c'est-à-dire, une chaine de caractères servant d'identifiant unique permettant de désigner un élément, programme ou autre, de façon unique, un peu comme le numéro sur votre carte d'identité. Pratiquement tous les éléments de votre système, que ce soit un dossier système particulier, ou un gestionnaire d'extension et bien d'autres choses, ont leur GUID et notre preview handler, n'échappera pas à la règle. Un GUID est de la forme {CEC124F7-656C-458b-9E7C-43462DE09D01} et en créer un à la main en s'assurant qu'il est unique n'est pas évident. Il faudrait regarder dans votre registre qu'il n'est pas utilisé et si un jour vous deviez utiliser ce GUID sur des postes clients, vous n'auriez pas la certitude de son unicité. Il n'y a donc pas de solution magique et il vous faut utiliser un petit utilitaire fourni par Microsoft qui se nomme GUIDGEN.exe. Pour générer un GUID, rien de tel que Visual Studio et son menu Tools > Generate GUID. Choisissez alors un format registre.

Image non disponible

Si vous avez Visual Studio 2008, alors là, manque de chance, le menu n'existe pas, l'outil n'est plus installé avec Visual Studio par défaut. Vous avez alors deux choix, soit le GUIDGEN.exe a été installé et se trouve alors dans C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\, soit tout simplement, il n'est pas sur votre organisateur, et il faut le télécharger sur le site de Microsoft. Une fois celui-ci téléchargé et placé où bon vous semble, vous devez cliquer sur le menu Tools > External Tools... pour configurer un nouveau menu qui fera appel à l'utilitaire. Et c'est tout. Voilà, c'était une petite parenthèse que je jugeais nécessaire, car je suis tombé sur ce problème au moment de la rédaction de cet article.

Image non disponible

1.2. Création de notre applet

Comme je l'ai dit, vous pourriez avoir besoin de lancer une application développée pour votre entreprise et vous aimeriez la lancer depuis le panneau de configuration. Si par le passé, vous deviez créer une DLL (renommée en .cpl) et implémentant CplApplet, il est maintenant possible, simplement à l'aide de quelques clés registres et d'un fichier XML de rajouter plusieurs actions aux panneaux de configurations.


La première étape consiste à générer un GUID comme vu dans le chapitre précédent. Créez ce GUID et notez-le dans un fichier texte. Profitez-en pour créer trois autres GUID que vous copierez aussi dans le fichier texte afin de ne pas les oublier. Durant cet article, et pour que ce soit clair pour tout le monde, j'utiliserai des GUID factices, mais facilement reconnaissables. J'aurais ainsi :
{00000000-0000-0000-0000-000000000000}
{00000000-0000-0000-0000-000000000001}
{00000000-0000-0000-0000-000000000002}
{00000000-0000-0000-0000-000000000003}

Commençons par enregistrer ce GUID dans le registre. Ouvrez Regedit.exe et rendez-vous à HKEY_CLASSES_ROOT\CLSID\ et créez une nouvelle clé nommée avec votre premier GUID. Dans sa clé présente par défaut, mettez la valeur "MonPremierApplet". Cette chaine peut-être n'importe laquelle, elle ne nous sera pas utile dans le cas de cet article.
Créez ensuite quatre autres clés de type chaîne comme le tableau suivant

Nom de la cléValeur que moi j'ai misDescription
InfoTipmon tooltip à moi!Le texte affiché par l'infobulle quand la souris survolera l'applet
System.ApplicationNameDeveloppez.MonAppletLe nom de votre applet. Essayez d'utiliser la forme des espaces de noms, à savoir Entreprise.NomApplet
System.ControlPanel.Category1,8Catégories où apparaitra votre applet
System.Software.TasksFileUrlc:\infos.xmlChemin vers un fichier XML de configuration de l'applet. Créez un fichier xml vide sur votre disque et pointez dessus

Pour les catégories, les valeurs possibles sont les suivantes:

ValeurCatégorie
1Apparence et personnalisation
2Matériel et audio
3Réseau et Internet
4non utilisé...
5Système et maintenance
6Horloge, langue et région
7Options d'ergonomie
8Programmes
9Comptes utilisateurs et protection des utilisateurs
10Sécurité
11Ordinateur Mobile (uniquement visible sur les ordinateurs portables)

Vous devriez avoir quelque chose ressemblant à ceci

Image non disponible

1.3. Enregistrer l'applet

Il reste une étape importante pour utiliser l'applet créé. Pour rappel, nous avons déclaré un GUID et rajouté quelques informations, mais rien ne permet à Windows de savoir que ce GUID est un applet. Nous allons donc nous rendre dans le registre à la clé: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ControlPanel\NameSpace\ et vous allez rajouter une clé avec comme nom, celui de votre premier GUID. Puis dans sa clé par défaut, vous allez taper le nom de votre applet: "MonPremierApplet". Avec cette simple ligne, vous indiquez au système d'aller charger les informations de ce GUID qui est censé représenter un applet du panneau de configuration. Si vous vous amusez à indiquer un mauvais ID, votre applet n'apparaitra pas, mais n'empêchera pas le chargement des autres applets.

1.4. L'ajout des tâches

Maintenant que votre applet est visible dans le panneau de configuration (s'il ne l'est pas, recommencez les étapes depuis le début), nous allons le personnaliser. Vous vous rappelez que nous avons créé un fichier XML vide nommé infos.xml. Ouvrez-le et collez le code suivant :

 
Sélectionnez

<?xml version="1.0" ?>
<applications xmlns="http://schemas.microsoft.com/windows/cpltasks/v1"
              xmlns:sh="http://schemas.microsoft.com/windows/tasks/v1">

  <application id="{00000000-0000-0000-0000-000000000000}">   <!-- id de votre applet -->
  </application>

</applications>

À l'intérieur de celui-ci, vous allez décrire trois tâches (le nombre importe peu, mais évitez d'en mettre plus de quatre ou cinq pour des raisons d'esthétisme. Chaque tâche ressemblera à ceci

 
Sélectionnez
<sh:task id="{00000000-0000-0000-0000-000000000001}">
      <sh:name>Lancer Visual Studio</sh:name>
      <sh:keywords>visual;studio;developpement;dev</sh:keywords>
      <sh:command>C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe</sh:command>
    </sh:task>

Faites donc de même pour créer deux tâches de plus, l'une lançant une page web et l'autre un fichier de votre disque dur.

 
Sélectionnez

<sh:task id="{00000000-0000-0000-0000-000000000002}">
      <sh:name>Visiter Developpez.com</sh:name>
      <sh:keywords>developpez;lgmorand;</sh:keywords>
      <sh:command>http://www.developpez.com</sh:command>
    </sh:task>
	<sh:task id="{00000000-0000-0000-0000-000000000003}">
      <sh:name>Ouvrir un fichier</sh:name>
      <sh:keywords>fichier;aide;</sh:keywords>
      <sh:command>C:\test.txt</sh:command>
    </sh:task>

Dans le registre, nous avons précisé que l'applet, apparaitrait dans deux catégories (la 1 et la 8), nous allons alors créer une catégorie dans le XML tel que suit:

 
Sélectionnez

<category id="1">
    <sh:task idref="{00000000-0000-0000-0000-000000000001}"/> 
    <sh:task idref="{00000000-0000-0000-0000-000000000002}"/>
    <sh:task idref="{00000000-0000-0000-0000-000000000003}"/>
  </category>
  <category id="8">
    <sh:task idref="{00000000-0000-0000-0000-000000000003}"/>
    <sh:task idref="{00000000-0000-0000-0000-000000000002}"/>
  </category>

Vous noterez que l'une n'a que deux tâches, et surtout elle ne les a pas dans le même ordre. Ceci a pour but de permettre de créer UN SEUL applet, mais qui sera affiché sous différentes formes et affichant différentes tâches selon la catégorie dans laquelle il est chargé.

Voici le résultat final:

Image non disponible

1.5. Pour aller un peu plus loin

1.3.1. Changer l'icône de l'applet

Il est possible de configurer l'icône de l'applet qui apparaitra. Dans le registre, dans CLSID, sous la clé de votre applet, rajoutez la clé DefaultIcon et dans sa sous-clé par défaut, tapez le chemin d'une image PNG.
C'est tout!

Image non disponible

1.3.2. Faire apparaître le bouclier de l'UAC à côté des tâches critiques

Les recommandations de Microsoft pour le développement sur Windows Vista requièrent qu'une icône particulière apparaisse à côté des applications lançant une tâche nécessitant une élévation de privilèges.
Pour cela, rien de bien compliqué, il suffit de rajouter l'attribut needsElevation sur la tâche de votre choix

 
Sélectionnez

<sh:task id="{00000000-0000-0000-0000-000000000001}" needsElevation="true">
Image non disponible

1.4.3. Lancer une application à partir du titre de l'applet

Nous avons vu comment ajouter des tâches et lancer des applications à partir de celle-ci. Nous allons voir qu'il est possible de lancer une application depuis le titre de l'applet ou si vous préférez, avoir un applet fonctionnel, sans avoir à déclarer des tâches.
Pour cela, rendez-vous dans le registre dans CLSID/votre_guid, puis ajoutez une sous-clé Shell contenant une sous-clé Open et enfin une sous-clé Command, dont la valeur par défaut contiendra le chemin vers l'application que vous souhaitez lancer. Exemple:

Image non disponible

1.6. Conclusion et liens complémentaires

Vous avez donc vu, comment très facilement, il était possible au sein d'une entreprise ou même simplement chez vous, de personnaliser

Si vous voulez creuser un peu plus sur la création d'élément du panneau de configuration, je vous conseille les deux liens suivants:
The Windows Vista and Windows Server 2008 Developer Story: Developing for Control Panel
Guidelines about Control Panels

2. Amélioration des interfaces graphiques

Pour continuer sur la lancée, je finis les articles sur le développement sur Windows Vista par un chapitre sur la création de contrôles "à la Vista". Nous allons donc voir comment créer ces contrôles. Il n'y a bien sûr aucune magie là-dessous et il n'est pas question de recoder un contrôle de zéro, mais simplement de vous présenter des API non ou peu documentées que vous pourriez trouver en fouillant allègrement la MSDN comme ici.

2.1. La textBox améliorée

Améliorer une textBox? Que peut-on rajouter à un simple champ de saisie? Un filtre? Le framework 2.0 contient déjà les MaskedEditBox. Pourquoi pas un message d'aide à la saisie.

Il s'agirait d'un texte qui serait affiché dans la textbox tant que l'utilisateur n'a pas saisi de texte. Cela peut se faire en envoyant un message particulier à une textbox ainsi que le texte à afficher.

Voici ce à quoi ça ressemblerait :

Image non disponible

Et bien les API systèmes le permettent, notamment grâce à l'envoi d'un message particulier au contrôle : le message EM_SETCUEBANNER. L'implémentation n'est pas complexe, il suffit d'envoyer ce message ainsi que le texte à afficher, au contrôle que l'on souhaite voir afficher le texte.

Voici un custom control pour lequel vous pouvez en mode design, définir le texte à afficher :

Contrôle MaTextBox
Sélectionnez

public class MaTextbox : TextBox
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern Int32 SendMessage(IntPtr hWnd, int msg,
        int wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);

    private const int EM_SETCUEBANNER = 0x1501;
    private string _cueText = String.Empty;

    [Category("Custom"),
     Description("Texte affiché comme conseil"),
    ] 
    public string CueText
    {
        get { return _cueText; }
        set
        {
            _cueText = value;
            
            SendMessage(this.Handle, EM_SETCUEBANNER, 0, _cueText);
        }
    }
}

2.2. Le SplitButton

Le SplitButton est un nouveau contrôle apparu sous Windows Vista qui permet de mixer un bouton avec un contextMenu. Le bouton ne permet pas simplement d'afficher un contextMenu lorsqu'on clique dessus puisque cela, nous pouvions déjà le faire avec un bouton normal. Non, il s'agit d'un bouton "normal" proposant également une petite flèche permettant d'afficher un menu contextuel comme le mon la capture suivante :

Là encore, tout n'est question que d'envoyer un message (BS_SPLITBUTTON) et d'utiliser un second (BCM_SETDROPDOWNSTATE). Néanmoins, si faire apparaitre un SplitButton est facile, pour le rendre parfaitement fonctionnel, et utiliser un contextmenu (pas un contextmenustrip), cela devient une autre paire de manches. Plutôt que réinventer la roue, je vous donne ici une classe que j'ai repris d'un certain Nicholas Kwan et que j'ai corrigée (même s'il reste des bugs) :

Classe SplitButton
Sélectionnez

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

/*************************
 *  modifié depuis un contrÃ&#180;le fait par Nicholas Kwan
 *  http://www.tevine.com
 * *********************/

namespace developpez.com.vista.controls
{ //This control now supports dropdowns.
    public delegate void DropDownClicked();

    public class SplitButton : Button
    {
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        private static extern IntPtr SendMessage(HandleRef hWnd, UInt32 Msg, IntPtr wParam, string lParam);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage
                    (IntPtr hWnd, int msg, int wParam, int lParam);

        public const int BCM_FIRST = 0x00001600;
        public const int BCM_SETDROPDOWNSTATE = BCM_FIRST + 0x0006;
        public const int BS_SPLITBUTTON = 0x0000000C;
        public const int WM_KILLFOCUS = 0x08;
        public const int WM_LBUTTONDOWN = 0x201;
        public const int WM_LBUTTONUP = 0x202;
        public const int WM_MOUSELEAVE = 0x2A3;
        public const int WM_PAINT = 0x0F;
        public const int WM_USER = 0x400;
       
        private ContextMenu ddm_ = new ContextMenu();
        public int dropdownpushed;

        public int isatdropdown;
        public int isbumped;
        public int ismousedown;

        public SplitButton()
        {
            FlatStyle = FlatStyle.System;
            DropDown_Clicked += launchmenu;
            ddm_.Collapse += CloseMenuDropdown;
        }

        //Set the theme
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cParams = base.CreateParams;
                cParams.Style |= BS_SPLITBUTTON;
                return cParams;
            }
        }

        public ContextMenu Dropdownmenu
        {
            get { return ddm_; }
            set
            {
                ddm_ = value;
                this.ddm_.Collapse += new EventHandler(this.CloseMenuDropdown);
            }
        }

       


        protected override void WndProc(ref Message m)
        {
            // Listen for operating system messages; Filter out a lot of messages here
            //The dropdown glyph changes:
            //Mousedown (at dropdown area) => Dropdown Event fired => Glyph changes => MouseUp => Glyph Changes
            switch (m.Msg)
            {
                case (BCM_SETDROPDOWNSTATE):
                    //PROBLEM: other buttons also have would encounter this message
                    if (m.HWnd == Handle)
                    {
                        ////This message seems to occur when the drop down is clicked; 
						////Occures several times, but one of them have the value of 1 in WParams
                        if (m.WParam.ToString() == "1")
                        {
                            if (dropdownpushed == 0)
                            {
                                //One time-initiation per mouse press
                                dropdownpushed = 1;
                                DropDown_Clicked();
                            }
                        }
                        if (ismousedown == 1)
                        {
                            isatdropdown = 1;
                        }
                    }
                    break;
                case (WM_PAINT):
                    //Paints the control to have the dropdown when needed
                    if (dropdownpushed == 1)
                    {
                        SetDropDownState(1);
                    }
                    break;
                case (WM_LBUTTONDOWN):
                    ismousedown = 1;
                    break;
                case (WM_MOUSELEAVE):
                    if (isatdropdown == 1)
                    {
                        SetDropDownState(0);
                        isatdropdown = 0;
                        ismousedown = 0;
                    }
                    break;
                case (WM_LBUTTONUP):
                    if (isatdropdown == 1)
                    {
                        SetDropDownState(0);
                        isatdropdown = 0;
                        ismousedown = 0;
                    }
                    break;
                case (WM_KILLFOCUS):
                    if (isatdropdown == 1)
                    {
                        SetDropDownState(0);
                        isatdropdown = 0;
                        ismousedown = 0;
                    }
                    break;
            }
            base.WndProc(ref m);
        }

        public void SetDropDownState(int Pushed)
        {
            if (Pushed == 0)
            {
                dropdownpushed = 0; //Removes dropdown pushed state
            }
            SendMessage(this.Handle, BCM_SETDROPDOWNSTATE, Pushed, 0);
        }

        public event DropDownClicked DropDown_Clicked;
            //The event which would be fired whenever the drop-down is clicked on.

        private void InitializeComponent()
        {
            SuspendLayout();
            ResumeLayout(false);
        }

        public void launchmenu()
        {
            if (ddm_.MenuItems.Count != 0)
            {
                ddm_.Show(this, new Point(Width, Height), LeftRightAlignment.Left);
            }
        }

        public void CloseMenuDropdown(object sender, EventArgs e)
        {
            //Hmm... contextmenu "collapse" state doesn't seem to fire up when a menuitem is clicked. Does not work here yet.
            SetDropDownState(0);
        }
    }
}

Voici le résultat obtenu :

Image non disponible

2.3. Sélection semi-transparente sur les listViews

Certains ne le savent peut-être pas, mais l'explorateur Windows n'est principalement composé que d'une listView améliorée dans laquelle apparaissent les fichiers et les dossiers de votre disque dur. Lorsque vous sélectionnez des fichiers, un carré semi-transparent bleu apparait. Nous allons voir qu'il est très simple d'inclure cette sélection au sein de nos listViews.

Il suffit pour cela d'envoyer simplement le code du double-buffering LVS_EX_DOUBLEBUFFER, qui sert normalement à éviter le scintillement des contrôles.

 
Sélectionnez
const int LVS_EX_DOUBLEBUFFER = 0x00010000;
SendMessage(listView1.Handle, 0x1000 + 54, LVS_EX_DOUBLEBUFFER, LVS_EX_DOUBLEBUFFER);

Conclusion

Et voilà que se termine déjà la troisième partie du développement d'applications sous Windows Vista. Il se peut fort que ce soit le dernier de la série. En effet, depuis octobre, je tourne exclusivement sous Windows Seven et celui-ci permet de nouvelles choses encore plus intéressantes. Il est donc fort possible que je m'oriente vers la réécriture plus complète et plus structurée du développement d'applications, mais cette fois-ci, appliqué au futur système d'exploitation de Microsoft.

4. Remerciements

Je tiens à remercier ram-0000 pour ses corrections et conseils apportés à l'article

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

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.