Nono40.developpez.com
Le petit coin du web de Nono40
SOURCES TESTS DELPHI WIN32 AUTOMATISMES DELPHI .NET QUICK-REPORT

Réalisation d'un écran de veille avec Delphi

Cet article présente la méthode pour la réalisation d'un écran de veille simple avec Delphi.

Article lu   fois.

L'auteur

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Principe

I-A. Ecran de veille, simple exécutable

Un écran de veille pour Windows est en fait un simple exécutable dont l'extension .EXE est renommée en .SCR.

Bien sur afin que celui-ci fonctionne comme un écran de veille il doit répondre aux demandes de windows passées en paramètres lors de son exécution. Le détail de ces paramètres est donné dans les paragraphes suivants.

Windows passe en premier paramètre le type d'action que l'écran de veille doit réaliser, comme la visualisation, configuration, etc.

Le deuxième paramètre est optionnel et dépend du premier.

I-B. Affichage normal de l'écran de veille

Pour afficher l'écran de veille Windows lance l'application en lui passant -S, /S ou S en premier paramètre.
Le second paramètre est vide dans ce cas.

Sur la commande S il faut afficher l'écran de veille normalement, le mieux est de le faire dans une fenêtre sans bord ( bsNone ), en avant-plan ( fsStayOnTop ) et en plein écran ( wsMaximized ).

C'est à l'écran de veille de gérer la sortie quand on bouge la souris, on appuie sur une touche, etc... De même c'est à l'application de vérifier que l'écran de veille est éventuellement protégé par un mot de passe et de demander celui-ci pour se fermer.

Si l'écran de veille est protégé par mot de passe, la clef HKEY_CURRENT_USER\\Control Panel\Desktop doit contenir une valeur ScreenSaveUsePassword non nulle.

I-C. Configuration de l'écran de veille

Pour afficher la fenêtre de configuration de l'écran de veille, Windows lance l'application avec le paramètre -C, /C ou C.
Le second paramètre est vide dans ce cas.

Sur la commande C il faut afficher la fenêtre de configuration de l'écran de veille. Les valeurs de paramétrage de l'écran de veille peuvent simplement être stockées dans un fichier INI ou dans la base de registre. Vous pouvez prendre la methode que vous préférez. La fenêtre doit lire les infos de configuration, les afficher, et les sauvegarder si l'utilisateur valide les modifications.

Il n'y a pas de spécification particulière sur la fenêtre de configuration.

I-D. Prévisualisation de l'écran de veille

Pour prévisualiser l'écran de veille Windows lance l'application en lui passant -P, /P ou P en premier paramètre.
Le second paramètre est le Handle de la fenêtre dans laquelle doit s'afficher l'écran de veille.

Attention, la prévisualisation est l'affichage dans le petit moniteur de la fenêtre des propriétés d'affichage du bureau. Le bouton "tester" de cette même fenêtre ne fait que lancer l'écran de veille normalement avec la commande S.

Si la fenêtre utilisée par la commande S est définie comme ci-dessus, alors il suffit d'assigner le ParentHandle de cette fenêtre avec la valeur reçue dans le deuxième paramètre.

Il ne faut pas gérer le mot de passe dans ce cas, ni la sortie par les mouvements de souris ou les évènement clavier. Windows se chargera de fermer l'écran de veille en envoyant un message WM_CLOSE à l'application. Rien ne doit donc empêcher sa fermeture en mode prévisualisation.

Vous pouvez vous-aussi afficher dans une fenêtre Delphi n'importe quel écran de veille, voir Prévisualisation d'un écran de veille.

I-E. Modification du mot de passe

Pour modifier le mot de passe de l'écran de veille Windows lance l'application en lui passant -A, /A ou A en premier paramètre.
Le second paramètre est le Handle de la fenêtre pouvant servir de parent à la boite de dialogue de saisie du mot de passe.

Vous pouvez gérer vous-même les fenêtres de saisie de mot de passe, mais le mieux est d'utiliser celles de Windows.

Pour appeler la fenêtre de modification du mot de passe de l'écran de veille il faut utiliser la fonction PwdChangePasswordA de la librairie MPR.DLL.
Pour appeler la fenêtre de vérification du mot de passe ( pour sortir de l'écran de veille ) il faut utiliser la fonction VerifyScreenSavePwd de la librairie PASSWORD.CPL.
L'appel de ces deux fonctions sera détaillé un peu plus loin.

I-F. Signaler au système qu'il est en veille

L'écran de veille, quand il est en mode normal, ( commande S ) doit signaler au système qu'il est en veille. Pour cela il faut utiliser la fonction SystemParametersInfo avec le paramètre SPI_SCREENSAVERRUNNING.

Au délà du fait que le système sait qu'il est en mode veille, ceci simplifie beaucoup la gestion des accès externes. En effet en mode veille Alt-TAB, Ctrl-ESC, etc sont désactivés. Il n'y donc plus aucune gestion à faire pour bloquer le basculement de tâche quand l'écran de veille est lancé.

I-G. Application mono-instance, quoi-que...

Une application SCR doit être une application mono-instance, il faut s'en assurer par l'utilisation d'un mutex, voir Instancier une seule fois l'application.

Mais bien sur... Il y a une exception à la règle. Dans le cas de la modification du mot de passe, Windows ne ferme pas l'instance en cours de prévisualisation. Donc pour la modification du mot de passe il faut pouvoir lancer une deuxième instance de l'application. Ceci peut ce faire facilement dans le source du projet comme nous allons le voir plus loin.

II. Réalisation

Pour présenter la réalisation des principes proposés précédemment nous allons réaliser un simple écran de veille ou une petite image rebondi sur les bords de l'écran. C'est bien sur simpliste, mais permet de ne garder dans le code que les principes de base d'un écran de veille.

Cet écran de veille aura un seul paramètre de configuration : la vitesse de déplacement de l'image.

II-A. Données globales

Ajouter une unité au projet afin d'y stocker les variables globales et les procédures de lecture/écriture des paramètres.

Le mode de stockage sera ici un fichier INI situé là où est l'exécutable. C'est la méthode la plus simple dans ce cas.

Le source de cette unité est le suivant :

 
Sélectionnez

unit Declare;

interface

Type TssMode = ( ssAffiche , ssConfig , ssMotDePasse , ssPrevisu );

Var
  // Mode de fonctionnement de l'application
  ssMode      : TssMode = ssAffiche;

  // Valeur des paramètres passés au programme
  Param1      : String;
  Param2      : String;

  // Valeur de déplacement de l'image
  DecX        : Integer = 3;
  DecY        : Integer = 3;

  // Option contenant la vitesse en cours.
  optVitesse  : Integer = 100;

Procedure LitIni;
Procedure EcritIni;

implementation

Uses IniFiles,SysUtils;

Procedure LitIni;
Var Ini:TInifile;
Begin
  Ini:=TIniFile.Create(ExtractFilePath(ParamStr(0))+'CONFIG.INI');
  Try
    optVitesse := Ini.ReadInteger('ECRAN','Vitesse',optVitesse);
  Finally
    Ini.Free;
  End;
End;

Procedure EcritIni;
Var Ini:TInifile;
Begin
  Ini:=TIniFile.Create(ExtractFilePath(ParamStr(0))+'CONFIG.INI');
  Try
    Ini.WriteInteger('ECRAN','Vitesse',optVitesse);
  Finally
    Ini.Free;
  End;
End;

end.

II-B. Fenêtre de visualisation de l'écran de veille

Ajouter une fenêtre à votre projet servant d'affichage de l'écran de veille. Sur celle-ci définissez les propriétés suivantes :

  • BorderStyle : bsNone ( obligatoire )
  • FormStyle : fsStayOnTop ( obligatoire )
  • WindowState : wsMaximized ( obligatoire )
  • Color : clBlack

Dans cette fenêtre placez en haut à gauche un TImage dont la propriété AutoSize est à True. Chargez une image de petite taille ( car elle doit rebondir aussi dans la petite fenêtre de prévisualisation ).
Placer aussi un TTimer sur la fiche pour gérer le déplacement de l'image.

Dans le code de création de la fiche, il faut lire le fichier INI et utiliser les valeurs qu'il contient.

 
Sélectionnez

procedure TFenEcran.FormCreate(Sender: TObject);
begin
  // Lecture des paramètres de configuration
  LitIni;
  Timer.Interval := optVitesse;
  // Suppression du curseur
  cursor:=crNone;
end;

A l'affichage de la fenêtre, on masque l'application dans la barre des tâches et on signale au système que l'écran de veille est actif.
La fonction SystemParametersInfo attend quatre paramètres :

  • uiAction : Identificateur du paramètre à modifier, ici SPI_SCREENSAVERRUNNING
  • uiParam : Valeur du paramètre : 1 si l'écran de veille est actif, 0 sinon
  • pvParam : Pointeur vers un entier ( inutilisé dans ce cas )
  • fWinIni : Mettre 1 pour modifier le fichier WinIni, dans notre cas il faut mettre 0
 
Sélectionnez

procedure TFenEcran.FormShow(Sender: TObject);
Var i:Integer;
begin
  // On masque l'application dans la barre des tâches
  ShowWindow(Application.Handle,SW_HIDE);
  // On dit au système que l'on est en mode veille
  SystemParametersInfo(SPI_SCREENSAVERRUNNING,1,@i,0);
end;

Le code du timer est le suivant ( c'est simpliste, je sais... )

 
Sélectionnez

procedure TFenEcran.TimerTimer(Sender: TObject);
begin
  // Code de déplacement de l'image
  Image.Left := Image.Left + DecX;
  Image.Top := Image.Top + DecY;
  If (Image.Left + Image.Width)>=ClientWidth Then DecX := -3;
  If (Image.Top + Image.Height)>=ClientHeight Then DecY := -3;
  If Image.Left <= 0 Then DecX := 3;
  If Image.Top  <= 0 Then DecY := 3;
end;

L'écran de veille doit gérer les causes de sa fermeture, ici nous allons simplement gérer le click de la souris. Mais d'autres évènements peuvent facilement être ajoutés.

 
Sélectionnez

procedure TFenEcran.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  // Sur un click on ferme l'écran de veille
  Close;
end;

Lors de la fermeture de la fiche il faut dire aussi au système que l'on sort de l'écran de veille :

 
Sélectionnez

procedure TFenEcran.FormClose(Sender: TObject; var Action: TCloseAction);
Var i:Integer;
begin
  // On dit au système qu'il n'est plus en mode veille
  SystemParametersInfo(SPI_SCREENSAVERRUNNING,0,@i,0);
end;

II-C. Modification du source du projet

La gestion des paramètres sera effectuée dans le source du projet. C'est de loin la méthode la plus simple pour gérer le nombre d'instances et la création de différentes fenêtres suivant les commandes.

A ce stade le code du projet est le suivant :

 
Sélectionnez

program Project1;

uses
  Windows,
  Forms,
  SysUtils,
  Declare in 'Declare.pas',
  UEcran in 'UEcran.pas' {FenEcran};

// Modification de l'extension
{$E SCR}
{$R *.res}
// Déclaration du nom de l'écran de veille
{$D SCRNSAVE Ecran de veille de Nono}

begin
  // On commence par prendre les paramètres passés au programme
  Param1 := Copy(UpperCase(ParamStr(1)),1,2);
  Param2 := UpperCase(ParamStr(2));

  // On filtre le premier afin de ne garder que la lettre
  If (Length(Param1)>0)And Not (Param1[1] In ['A'..'Z']) Then
    Param1 := Copy(Param1,2,1);

  // On détermine ce qu'il faut faire en fonction de Param1
  If Param1='P' Then ssMode := ssPrevisu;
  If Param1='C' Then ssMode := ssConfig;
  If Param1='S' Then ssMode := ssAffiche;
  If Param1='A' Then ssMode := ssMotDePasse;

  // Une application écran de veille doit être mono-instance
  SetLastError(NO_ERROR);
  CreateMutex (nil, False, 'MONSCREENSAVER');
  if GetLastError = ERROR_ALREADY_EXISTS Then Exit;

  // Traitement en fonction des cas
  Case ssMode Of
    ssAffiche,ssPrevisu:
    Begin
      Application.Initialize;
      Application.CreateForm(TFenEcran, FenEcran);
      if ssMode=ssPrevisu Then
        FenEcran.ParentWindow := StrToInt(Param2);
      Application.Run;
    End;
  End;
end.

On notera l'utilisation de la directive $E afin de modifier l'extension du fichier exécutable en .SCR. Ceci est important afin que Windows le reconnaise en tant que tel.

Le début du code ne fait que lire et stocker les paramètres passés au programme.
Ensuite, la vérification de la mono-instance de l'application est effectuée.
Enfin l'écran de veille est affiché.

Vous noterez que la différence entre l'affichage normal et la prévisualisation est minime. Dans le cas de la prévisualisation une simple affectation de ParentWindow permet à la fenêtre de l'écran de veille de se loger dans le petit moniteur. C'est pour cela que dans le code de l'écran de veille on utilise ClientWidth/ClientHeight au lieu de Screen.Width et Screen.Height. La fenêtre prenant d'elle-même les dimensions de la fenêtre parente ( Merci Delphi ).

A ce stade, l'écran de veille est fonctionnel. Compilez le projet, puis effectuez un clic droit dans l'explorateur afin d'installer l'écran de veille. Cette methode permet de le tester sans avoir à le copier dans le répertoire de base de Windows.

Image non disponible

L'écran de veille doit alors apparaître en prévisualisation :

Image non disponible

Le bouton "Aperçu" permet de le voir en plein écran, comme en veille normale.

II-D. Ajout d'une fenêtre de configuration

L'ajout d'une fenêtre de configuration est très simple.
Ajoutez une nouvelle fenêtre au projet et donnez lui l'aspect suivant :

Image non disponible

Ajouter le code suivant dans le OnShow :

 
Sélectionnez

procedure TFenConfig.FormShow(Sender: TObject);
begin
  // Lecture et affichage des paramètres
  LitIni;
  seTimer.Value := optVitesse;
  // On masque l'application dans la barre des tâches
  ShowWindow(Application.Handle,SW_HIDE);
end;

Et le code suivant sur les boutons :

 
Sélectionnez

procedure TFenConfig.btnAnnulerClick(Sender: TObject);
begin
  // Pour annuler, on ferme simplement...
  Close;
end;

procedure TFenConfig.btnOKClick(Sender: TObject);
begin
  // En cas de validation il faut sauver les paramtres
  optVitesse := seTimer.Value;
  EcritIni;
  // Puis fermer la fenêtre
  Close;
end;

Il ne reste plus qu'a modifier le source du projet pour appeler la fenêtre de configuration quand Windows le demande :

 
Sélectionnez

  // Traitement en fonction des cas
  Case ssMode Of
    ssAffiche,ssPrevisu:
    Begin
      Application.Initialize;
      Application.CreateForm(TFenEcran, FenEcran);
      if ssMode=ssPrevisu Then
        FenEcran.ParentWindow := StrToInt(Param2);
      Application.Run;
    End;
    ssConfig:
    Begin
      Application.CreateForm(TFenConfig,FenConfig);
      Application.Initialize;
      Application.Run;
    End;
  End;

Et voila, quand vous cliquez sur le bouton "Paramètres" dans les propriétés d'affichage, votre fenêtre de configuration s'affiche.

II-E. Gestion du mot de passe

Pour ajouter la gestion du mot de passe il faut ajouter deux parties dans le code :
- Répondre à la commande A de modification du mot de passe.
- Tester le mot de passe dans l'écran de veille.

Pour modifier le mot de passe, comme énoncé plus haut nous allons utiliser les procédures de Windows. Il faut noter aussi que la demande de modification du mot de passe peut être demandée même si l'écran de veille est déjà en prévisualisation. Il faut donc gérer la modification du mot de passe avant la gestion du nombre d'instances. Le source du projet devient :

 
Sélectionnez

  // Traitement en fonction des cas
  Case ssMode Of
    ssMotDePasse:Begin
      MdpLib := LoadLibrary('MPR.DLL');
      If MdpLib <> 0 Then
      Begin
        MdpFunc := GetProcAddress(MdpLib,'PwdChangePasswordA');
        If Assigned(MdpFunc) Then
          MdpFunc('SCRSAVE',StrToInt(Param2),0,0);
        FreeLibrary(MdpLib);
      End;
      Exit;
    End;
  End;

  // Une application écran de veille doit être mono-instance
  SetLastError(NO_ERROR);
  CreateMutex (nil, False, 'MONSCREENSAVER');
  if GetLastError = ERROR_ALREADY_EXISTS Then Exit;

  // Traitement en fonction des cas
  ...

Pour gérer le mot de passe, nous allons simplement utiliser l'évènement OnCloseQuery de la fiche de visualisation :

 
Sélectionnez

procedure TFenEcran.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
Var Reg:TRegistry;
    MdpFunc   : function (Parent : THandle) : Boolean; stdcall;
    MdpLib  : THandle;

begin
  // On teste le mot de passe éventuel dans le cas de demande de fermeture de la fiche
  CanClose := True;
  If ssMode=ssAffiche Then
  Try
    // Test seulement en affichage normal
    Reg := TRegistry.Create;
    Try
      // Lecture de la clef
      Reg.RootKey := HKEY_CURRENT_USER;
      If Reg.OpenKey('Control Panel\Desktop',False) Then
        If Reg.ReadInteger('ScreenSaveUsePassword') <> 0 Then
        Begin
          MdpLib := LoadLibrary('PASSWORD.CPL');
          If MdpLib <> 0 Then
          Begin
            // Appel de la procédure de demande de mot de passe
            MdpFunc := GetProcAddress(MdpLib,'VerifyScreenSavePwd');
            CanClose := MdpFunc(Handle);
            FreeLibrary(MdpLib);
          End;
        End;
    Finally
      Reg.Free;
    End;
  Except
    // Sur erreur, par défaut on ferme.
    CanClose:=True;
  End;
end;

A noter que par défaut ( erreur de lecture BDR etc... ) il ne faut pas gérer le mot de passe, sous peine d'avoir à rebooter votre PC.
Notez également que dans le cas de la prévisualisation il ne faut pas demander le mot de passe, car l'écran de veille doit se fermer dés que Windows le demande ( fermeture de la fenêtre des propriétés d'affichage ).

Sous Windows XP la clef n'existe pas. La gestion du mot de passe est effectuée par Windows directement en affichant la fenêtre d'ouverture de session.

III. Conclusion

La gestion d'un écran de veille n'est donc pas si compliquée que ça, libre à vous maintenant de créer des écrans plus compliqués.

Ici l'écran de prévisualisation est le même que l'écran final, mais ce n'est pas obligatoirement le cas.

Téléchargez ici le source complet du projet : Source0084.zip

Lien : Prévisualisation d'un écran de veille

Merci à Pierre Castelain pour la correction orthographique.

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

  

Copyright © 2004 Bruno Guérangé. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.