IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ DelphiConsultez toutes les FAQ

Nombre d'auteurs : 124, nombre de questions : 929, dernière mise à jour : 31 décembre 2023  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums Delphi et Delphi et bases de données de www.developpez.com et de l'expérience personnelle des auteurs.

Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose soient correctes. Les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous souhaitez y apporter des corrections ou la compléter, contactez un responsable (lien au bas de cette page).

Nous espérons que cette FAQ saura répondre à vos attentes. Nous vous en souhaitons une bonne lecture.

L'équipe Delphi de Developpez.com.

SommaireInterface utilisateurGestion exécution (26)
précédent sommaire suivant
 

Un splash screen est un écran qui apparaît pendant le chargement d'une application. Pour réaliser un tel écran, il suffit de faire apparaître la fenêtre voulue dès l'initialisation de l'application et ce jusqu'à l'affichage de la fenêtre principale, c'est-à-dire jusqu'au chargement complet de l'application.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
begin 
  Application.Initialize; 
  SplashScreen := TSplashScreen.Create(Application); { Création la fenêtre de Splash               } 
  SplashScreen.Show;                                 { Affichage de cette fenêtre                  } 
  SplashScreen.Update;                               { forçage de l'affichage de la fenêtre        } 
    { sinon elle n'apparaît que partiellement     } 
  Application.CreateForm(TForm1, Form1);             { Création des autres fiches de l'application } 
  SplashScreen.Close;                                { Fermeture la fenêtre de Splash              } 
  SplashScreen.Release;                              { Destruction de la fenêtre                   } 
  Application.Run; 
end.

Mis à jour le 25 janvier 2014 hachesse

La première chose à faire consiste à créer un splash screen (voir le lien ci-dessous).

Pour ajouter la transparence, il suffit de passer à true la propriété Transparent de la fenêtre faisant office de splash screen et de positionner la propriété BorderStyle à bsNone.
Sur les systèmes antérieurs à Windows ME, la propriété Transparent n'a pas d'effet. Dans ce cas, il suffit de remplacer le fond de la fenêtre par l'image de l'écran. Ainsi, la fenêtre n'est pas réellement transparente, mais elle donne l'illusion de la transparence. Voici le code de la fenêtre faisant office de splash screen :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
{...} 
type 
  TSplashForm = class(TForm) 
    {...} // Les composants de votre form 
    procedure FormCreate(Sender: TObject); 
    procedure FormPaint(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    {...} 
  private 
    FImageDeFond : TBitmap; 
  {...} 
  end; 
  
var 
  SplashForm: TSplashForm; 
  
implementation 
  
{$R *.dfm} 
  
{...} 
  
procedure TSplashForm.FormCreate(Sender: TObject); 
begin 
  //Pour connaître la version de Windows, il faut utiliser Win32MajorVersion et Win32MinorVersion 
  //Dans ce cas, il suffit d'utiliser Win32MajorVersion Win95, 98 et ME ont tous pour version majeure 4 
  if Win32MajorVersion = 4 then 
    begin 
      FImageDeFond := TBitmap.Create; 
      FImageDeFond.width := Screen.width; 
      FImageDeFond.height := Screen.height; 
      FImageDeFond.canvas.CopyRect(ClientRect, Canvas, ClientRect); 
    end; 
end; 
  
procedure TSplashForm.FormPaint(Sender: TObject); 
begin 
  //Remplacement du fond de la fenêtre par l'image capturée 
  if Win32MajorVersion = 4 then 
      4 : canvas.CopyRect(ClientRect, FImageDeFond.Canvas, ClientRect); 
end; 
  
procedure TSplashForm.FormDestroy(Sender: TObject); 
begin 
  //TOUJOURS détruire ses objets 
  if Win32MajorVersion = 4 then 
    FImageDeFond.Free; 
end; 
{...}

Mis à jour le 17 septembre 2013 MD Software

Il existe de nombreuses méthodes pour n'autoriser qu'une seule instance d'un même programme. La plus élégante étant sans aucun doute l'utilisation des Mutex.
Les Mutex sont en fait des variables globales qui génèrent un message d'erreur lorsque l'on tente de les instancier alors que cela a déjà été fait. Pour interdire de lancer deux fois une même application, il suffit donc de tester si une erreur est produite lors de la création d'un Mutex pour notre application.
Cela se fait dès le lancement de l'application, c'est-à-dire dans le code de base du projet accessible par le menu Projet|Voir la source.
Le code source d'un nouveau projet étant :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
program Project1; 
  
uses 
  Forms, 
  Unit1 in 'Unit1.pas' {Form1}; 
  
{$R *.RES} 
  
begin 
  Application.Initialize; 
  Application.CreateForm(TForm1, Form1); 
  Application.Run; 
end.
Toutes les fonctions relatives aux Mutex se trouvant dans l'unité Windows, il est donc nécessaire de l'ajouter dans la clause uses.
Afin d'être totalement sûr qu'une autre erreur ne vienne perturber le lancement de notre programme, il est préférable d'effacer toute trace de la dernière erreur survenue dans le système. On utilise pour cela la commande SetLastError(NO_ERROR).
Il est à présent temps de créer le Mutex pour l'application. On utilise pour ce faire la commande CreateMutex(lpMutexAttributes: PSecurityAttributes, bInitialOwner: LongBool, lpName: PChar): Cardinal où les paramètres correspondent respectivement aux attributs de sécurité du Mutex, au thread qui en est le propriétaire et au nom du Mutex. Si le Mutex existe déjà, l'erreur ERROR_ALREADY_EXISTS ou ERROR_ACCESS_DENIED sera alors déclenchée. Il faut donc tester la dernière erreur intervenue dans le système et lancer ou non une instance de l'application.

Le code de base du projet étant donc :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
program Project1; 
  
uses 
  Windows, Forms, 
  Unit1 in 'Unit1.pas' {Form1}; 
  
{$R *.RES} 
var 
H : THandle; 
Erreur: Integer; 
begin 
  SetLastError(NO_ERROR); 
  H := CreateMutex (nil, False, 'Nom de l application'); 
  Erreur := GetLastError; 
  if ( Erreur = ERROR_ALREADY_EXISTS ) or ( Erreur = ERROR_ACCESS_DENIED ) 
    then Exit; 
  Application.Initialize; 
  Application.CreateForm(TForm1, Form1); 
  Application.Run; 
  CloseHandle(H); 
end.
ERROR_ACCESS_DENIED implique l'existence du Mutex mais avec un accès interdit (session windows différente, service tournant sous un autre login utilisateur...).
L'important, dans notre cas, est qu'il existe et donc que le programme (ou service) est bien actif et a verrouillé le Mutex.

Mis à jour le 13 octobre 2013 hachesse

1ère méthode : en utilisant le nom de la classe.

L'idée est de chercher une fenêtre de même classe que TApplication avec le même titre. Et de mettre en avant plan une telle fenêtre si elle existe.
Le code du projet ( .DPR ) devient le suivant :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
begin  
  if IsPrevInstance = 0 then  
  begin  
    Application.Initialize;  
    Application.CreateForm(TMDIForm, MDIForm);  
//[...]  
    Application.Run;  
  end  
  else  
    AfficherInstance(IsPrevInstance);  
end.
Les deux fonctions IsPrevInstance et AfficherInstance peuvent être mises directement dans le code du projet ou dans une autre unité. Leur implémentation est la suivante :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function IsPrevInstance: HWND;  
var  
  ClassName: array[0..255] of char;  
  Title: string;  
begin  
  Title := Application.Title;  
  Application.Title := '';  
  { On change le titre, car on trouverait toujours une application lancée, (la notre). } 
  try  
    GetClassName(Application.Handle, ClassName, 255);  
    { Met dans ClassName le nom de la classe de l'application. } 
    Result := FindWindow(ClassName, PChar(Title));  
    { Renvoie le Handle de la 1ère fenêtre de Class (Type) ClassName, et le titre de l'application. } 
  finally  
    Application.Title := Title; { Restauration du vrai titre. } 
  end;  
end;  
  
procedure AfficherInstance(InstHandle: HWND); 
begin 
  { Restaurer l'application si minimisée } 
  ShowWindow(InstHandle, SW_RESTORE); 
  { Mettre la première instance en premier plan : } 
  SetForegroundWindow(InstHandle); 
  { Fin de la deuxième instance } 
  Application.Terminate; 
end;

2ème méthode : en utilisant la base de registre.

La première chose à faire est de tester si l'application est déjà instanciée. Pour ce faire, on utilise les Mutex comme décrits ici. Ce test amène donc à deux cas de figures :

- L'application n'est pas lancée.

Si l'application n'est pas instanciée, il faut le faire ; pour cela, le déroulement classique du lancement d'une programme suffit. Il faudra tout de même récupérer certaines informations sur l'application. Ces informations serviront à faire repasser l'application au premier plan dans le cas d'un second lancement du programme. Pour cela, nous avons besoins de deux handles : celui du programme lui-même et celui de la form principale.
Ces deux valeurs, qui devront être accessibles en dehors du programme, seront stockées dans la base de registres de Windows sous la clé HKEY_CLASSES_ROOT\software\nom_de_la_clé et sous les noms FirstApplicationHandle et FirstFormHandle.
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Application.Initialize; 
Application.CreateForm(TForm1, Form1); 
  
Registre := TRegistry.Create; 
try 
  Registre.RootKey := HKEY_CLASSES_ROOT; 
  Registre.OpenKey('\Software\nom_de_la_clé', True); 
  Registre.WriteInteger('FirstApplicationHandle', Application.Handle); 
  Registre.WriteInteger('FirstFormHandle', Form1.Handle); 
  Registre.CloseKey; 
  Registre.Free; 
except 
  MessageDlg('Une erreur est survenue lors de l''écriture dans la base de registre.', 
    mtError, [mbOk], 0); 
  Registre.Free; 
end; 
  
Application.Run;

- L'application est déjà lancée.

Si l'application est déjà lancée, rien ne sert de le faire une seconde fois, c'est-à-dire que le chargement de l'application sera tout simplement stoppé. Mais avant de quitter le lancement de l'application, il faut rendre le focus à la première instance du programme. C'est là que les données qu'il aura déposées dans la base de registre seront utiles pour l'identifier.
La première chose à faire est donc d'aller chercher les deux handles voulus dans la base de registre. Une fois que le programme aura le handle de l'application et celui de la fenêtre principale, il pourra donner le focus à cette dernière. Cela se fait grâce à deux fonctions de l'API Windows : ShowWindow(hWnd: HWND; nCmdShow: Integer): BOOL et SetForegroundWindow(hWnd: HWND): BOOL.
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Registre := TRegistry.Create; 
try 
  Registre.RootKey := HKEY_CLASSES_ROOT; 
  Registre.OpenKey('\Software\nom_de_la_clé', True); 
  FirstApplicationHandle := Registre.ReadInteger('FirstApplicationHandle'); 
  FirstFormHandle := Registre.ReadInteger('FirstFormHandle'); 
  ShowWindow(FirstApplicationHandle, SW_NORMAL); 
  SetForegroundWindow(FirstFormHandle); 
  Registre.CloseKey; 
  Registre.Free; 
except 
  MessageDlg('Une erreur est survenue lors de la lecture dans la base de registre.', 
    mtError, [mbOk], 0); 
  Registre.Free; 
end;

Il est préférable de nettoyer la base de registre à la fin de l'exécution du programme.

Mis à jour le 13 octobre 2013 hachesse

Il existe deux manières pour faire cela :

1. La méthode Sleep :

Il suffit de mettre Application.Sleep(duree_voulue)duree_voulue est exprimée en millisecondes. Cette méthode présente le désavantage de ne pas traiter les messages.

2. La méthode GetTickCount :

La procédure GetTickCount nous informe sur le nombre de millisecondes écoulées depuis l'allumage du PC. Le problème est que cette quantité est stockée sur un DWord et que forcément un jour (49,7 jours après l'allumage du PC), elle va revenir à zéro. Pour corriger ce problème, nous allons donc utiliser des cardinaux.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
  
var 
  Tc: Cardinal; 
begin 
  Tc := GetTickCount; 
  repeat 
    Application.ProcessMessages; 
  until Cardinal(GetTickCount - Tc) > {Temps d'attente en ms}; 
end;
Cette méthode est à préférer, car elle ne bloque pas la distribution des messages extérieurs.

Mis à jour le 13 octobre 2013 Al-Yazdi

C'est un problème courant dans de grand traitements en boucle, les fenêtres des applications ne peuvent être rafraîchies par Windows tant que le traitement est en cours. La solution est d'appeler la méthode Application.ProcessMessages régulièrement afin que les messages de mise à jour de Windows puissent être traités. Ceci permet aussi de programmer un bouton "Stop" sur le traitement sans en venir au Alt-Ctrl-Suppr.

Dans le code ci-dessous, la variable Stop indique que le bouton "Stop" à été appuyé et que la procédure doit être stoppée. L'appel de Application.ProcessMessages permet de mettre à jour normalement la fenêtre pendant l'exécution de la boucle.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
type 
  TForm1 = class(TForm) 
    ... 
  private 
    { Déclarations privées } 
    Stop : Boolean; 
    ... 
  end; 
... 
  
procedure TForm1.BoutonMarcheClick(Sender: TObject); 
Var i:Integer; 
begin 
  { Mise à faux de l'arrêt } 
  Stop := False; 
  I    := 0; 
  { Traitement long } 
  Repeat 
    Inc(i); 
    Label1.Caption := IntToStr(i); 
    { Mise à jour des évènements en attente } 
    Application.ProcessMessages; 
  Until (i>=100000000)Or Stop; 
end; 
  
procedure TForm1.BoutonStopClick(Sender: TObject); 
begin 
  { Demande d'arrêt de la boucle } 
  Stop:=True; 
end;

Mis à jour le 13 octobre 2013 Nono40

Delphi possède dans ce but deux fonctions : ParamCount: Integer et ParamStr(Index: Integer): String.

La première nous indique combien de paramètres on été passés au programme, et la seconde nous indique lesquels ils sont. Ainsi ParamStr(0) nous renseigne sur le nom du programme et son chemin, ParamStr(1) nous donne le premier paramètre reçu et ainsi de suite.

Exemple : On a lancé notre application en faisant glisser des fichiers sur l'icône. On va remplir une ListBox des chemins de tous les fichiers.

Code delphi : Sélectionner tout
1
2
3
4
5
6
var 
  i: Integer; 
begin 
  for i := 1 to ParamCount do 
    MyListBox.Items.Append(ParamStr(i)); 
end;

Mis à jour le 13 octobre 2013 Al-Yazdi

Pour exécuter une application extérieure au programme, il suffit d'utiliser la fonction suivante de l'API :

Code delphi : Sélectionner tout
1
2
function ShellExecute(hWnd: HWND; Operation, FileName, Parameters, 
Directory: PChar; ShowCmd: Integer): HINST; stdcall;
Il faut ajouter l'unité ShellApi dans la clause uses de l'unité contenant la fonction. Par exemple :
Code delphi : Sélectionner tout
uses [...], ShellApi;
Tous les paramètres chaînes doivent être des PAnsiChar ou PChar.

Rappel : Pour les versions 1 à 4 de Delphi, il faut toujours transtyper explicitement les chaînes constantes :
Code delphi : Sélectionner tout
ShellExecute(0,PChar('open'),...)
À partir de Delphi 5, le transtypage est inutile :
Code delphi : Sélectionner tout
ShellExecute(0,'open',...)

Détail des paramètres :
  • hwnd : handle de la fenêtre qui servira de parent pour les messagesbox de l'application. Toujours passer Application.Handle en cas de doute, 0 sinon.
  • Operation : type d'opération effectuée sur le fichier, a moins de savoir ce que l'on fait, passer 'open'.
    Ce paramètre peut prendre les valeurs suivantes :
    • 'OPEN' ouvrir un document, ou exécuter une application ;
    • 'PRINT' pour imprimer un document ;
    • 'EXPLORE' pour utiliser l'explorateur Windows en utilisant le chemin donné par FileName ;
    • 'FIND' pour appeler la fenêtre de recherche en utilisant le chemin donné par FileName.
  • FileName : nom de l'application à lancer, du document à ouvrir/imprimer, du répertoire à explorer, etc. Chemin complet requis, sauf si Directory est correctement renseigné.
  • Parameters : liste des paramètres dans le cas ou FileName désigne une application. Pour un document ou dans le cas où il n'y a pas de paramètres, mettre Nil.
  • Directory : répertoire par défaut utilisé dans le cas où FileName désigne une application. Correspond en général au chemin de l'élément exécuté, ou nil si le chemin est absolu ou si le chemin de démarrage n'a pas d'importance.
  • ShowCmd : décrit comment la nouvelle fenêtre doit être ouverte. Les plus utiles sont :
    • SW_SHOW pour afficher l'élément exécuté ;
    • SW_SHOWMINIMIZED pour l'exécuter en fenêtre réduite ;
    • SW_HIDE pour cacher la fenêtre d'exécution.

    Voir l'aide en ligne pour plus d'informations.

Quelques exemples d'utilisations

Lancer une application simplement :
Code delphi : Sélectionner tout
ShellExecute(0,'OPEN','Wordpad.exe', Nil, Nil, SW_SHOW);

Lancer une application avec des paramètres :
Code delphi : Sélectionner tout
1
2
3
4
ShellExecute(0,'OPEN','Wordpad.exe','C:\temp\essai.txt',Nil, SW_SHOW); 
  
// Exécution de la commande système "ipconfig /all" 
ShellExecute(Application.Handle,'open','ipconfig','/all',nil,SW_SHOW);

Lancer l'explorateur sur un répertoire précis :
Code delphi : Sélectionner tout
ShellExecute(0,'EXPLORE','C:\MonRépertoire\', Nil, Nil, SW_SHOW);

Ouvrir un document :
Code delphi : Sélectionner tout
ShellExecute(0,'OPEN','C:\Temp\Monfichier.txt', Nil, Nil, SW_SHOW);

Imprimer un document :
Code delphi : Sélectionner tout
ShellExecute(0,'PRINT','C:\Temp\Monfichier.doc', Nil, Nil, SW_SHOW);

Appeler la fenêtre de recherche de Windows :
Code delphi : Sélectionner tout
ShellExecute(Application.handle, 'find', 'c:\temp', Nil, Nil, SW_SHOWNORMAL);

Exécuter un fichier Batch :

Pour exécuter un fichier Batch, il faut passer le nom du fichier à l'interpréteur de commande. Pour ceci, le paramètre FileName doit être égal à PChar(GetEnvironmentVariable('ComSpec')), et le paramètre Parameters doit être égal à '/C FichierBatch.bat ParamètresDuBatch'. Cette méthode permet d'exécuter un batch sans erreurs, de Windows 95 à Windows XP.
Exécution du batch "C:\bin\batch.bat", ayant les paramètres "-param1 -param2" :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
ShellExecute( 
Application.Handle, 
'open', 
PChar(GetEnvironmentVariable('ComSpec')), 
'/C batch.bat -param1 -param2', 
'c:\bin', 
SW_SHOW);

Exécution d'un batch "c:\bin\batch.bat" comme s'il était exécuté depuis le répertoire "c:\travail", avec les paramètres "-param1" :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
ShellExecute( 
Application.Handle, 
'open', 
PChar(GetEnvironmentVariable('ComSpec')), 
'/C c:\bin\batch.bat -param1', 
'c:\travail', 
SW_SHOW);

Récupération et conversion des informations d'un raccourci Windows :
- Clic droit sur le raccourci, puis "Propriétés".
- Pour la commande ShellExecute, les paramètres seront :
hwnd : Application.HandleOperation : 'open'FileName : Le contenu de la ligne "Cible".Parameters : S'il y a des paramètres après l'exécutable dans "Cible", mettez-les ici et pas dans FileName.Directory : Le contenu de la ligne "Démarrer dans".ShowCmd : Suivant la liste "Exécuter" :
  • Fenêtre normale : mettre SW_SHOW.
  • Réduite : mettre SW_SHOWMINIMIZED.
  • Agrandie : mettre SW_SHOWMAXIMIZED.

Exemple de raccourci :
Cible = "C:\Program Files\Microsoft IntelliPoint\dplaunch.exe" Mouse CPL
Démarrer dans = "C:\Program Files\Microsoft IntelliPoint\"
Exécuter : Fenêtre normale
L'appel sera :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
ShellExecute( 
Application.Handle, 
'open', 
'C:\Program Files\Microsoft IntelliPoint\dplaunch.exe', 
'Mouse CPL', 
'C:\Program Files\Microsoft IntelliPoint\', 
SW_SHOW);

Exécuter un programme console en utilisant les redirections :
Code delphi : Sélectionner tout
ShellExecute(0,nil, PChar(GetEnvironmentVariable('ComSpec')), PChar('/C Net View > Resultat.txt'), nil, 0);

Le résultat de la fonction ShellExecute est un entier. S'il est inférieur ou égal à 32, l'exécution a échoué. S'il est strictement supérieur à 32, le processus a été lancé correctement. Pour surveiller la fin du processus engendré, il est conseillé d'utiliser CreateProcess au lieu de ShellExecute.
Les codes d'erreur de ShellExecute sont symboliques. Ils correspondent à ceci sur une cible Win32 :
  • 0 : Erreur critique (mauvais paramètres en général, les vérifier tous). Si les paramètres sont corrects, un crash système est imminent.
  • ERROR_BAD_FORMAT : Le fichier n'est pas un exécutable (vérifier FileName).
  • SE_ERR_ACCESSDENIED : Accès au fichier refusé (vérifier les droits de l'utilisateur).
  • SE_ERR_ASSOCINCOMPLETE : Le type de document n'est pas correctement géré (vérifier Filename ou réinstaller l'application gérant le document).
  • SE_ERR_DDEBUSY : Serveur DDE occupé. Réessayer plus tard.
  • SE_ERR_DDEFAIL : La transaction DDE a échoué. Demander s'il faut refaire un essai ou pas.
  • SE_ERR_DDETIMEOUT : La transaction DDE a été trop longue. Demander s'il faut refaire un essai ou pas.
  • SE_ERR_DLLNOTFOUND : Une DLL requise n'a pas été trouvée (vérifier FileName et Directory).
  • SE_ERR_FNF : Le fichier n'a pas été trouvé (vérifier FileName et Directory).
  • SE_ERR_NOASSOC : L'extension du fichier n'est pas gérée (il manque une application à l'utilisateur, lui demander de l'installer).
  • SE_ERR_OOM : Plus assez de mémoire pour effectuer l'opération (demander à l'utilisateur de fermer des applications, ou libérer de la mémoire).
  • SE_ERR_PNF : Chemin non-trouvé (vérifier Directory, parfois aussi FileName).
  • SE_ERR_SHARE : Une erreur de partage s'est produite (le fichier est utilisé par quelqu'un d'autre, ou par un autre programme, en mode exclusif).


On peut tester directement le code d'erreur :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Var 
Code : Cardinal ; 
Begin 
// On appelle ShellExecute "normalement". 
Code := ShellExecute (.....) ; 
  
// Ensuite, on vérifie si l'exécution a été correcte : 
// Deux méthodes possibles : avec ou sans exceptions. 
If (Code<=32) Then 
// Affichage du message d'erreur "propre", sans exceptions. 
// Le résultat de SysErrorMessage est une chaîne normale, dans la langue de l'OS. 
ShowMessage(SysErrorMessage(Code)); 
  
If (Code<=32) Then 
// Affichage du message d'erreur "hard", AVEC levée d'exception. 
// Remplacer par RaiseLastWin32Error sur les anciennes versions de Delphi. 
RaiseLastOSError; 
End;

La fonction WinExec ne doit plus être utilisée, elle n'est présente que pour des raisons de compatibilité.

Mis à jour le 13 octobre 2013 Laurent Dardenne Mac LAK Nono40

Pour lancer une application tout en récupérant son handle de process, il faut utiliser la fonction API CreateProcess. Cette fonction permet d'exécuter une ligne de commande avec un grand nombre d'options. Elles ne seront pas décrites ici car ce n'est pas le but de cette QR. Cette fonction retourne aussi les handles des process et threads principaux de l'application lancée. Cette particularité va être utilisée pour garder un contrôle sur l'application.

La ligne de commande passée à CreateProcess ne doit pas contenir d'espace dans les noms de fichiers, ou alors il faut que les noms de fichiers soient entre " ". Par défaut, il est donc conseillé de mettre les " " systématiquement pour limiter les erreurs.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
procedure TForm1.Button1Click(Sender: TObject); 
var 
  StartupInfo: TStartupInfo; 
  ProcessInfo: TProcessInformation; 
  CommandLine: {$IFDEF UNICODE}WideString{$ELSE}string{$ENDIF}; 
  
begin 
  CommandLine := '"Notepad.exe"'; 
  
  ZeroMemory(@StartupInfo, SizeOf(StartupInfo)); 
  StartupInfo.cb := SizeOf(StartupInfo); 
  
  if CreateProcess(nil, PChar(CommandLine), nil, nil, FALSE, 0, nil, nil, StartupInfo, ProcessInfo) then 
  begin 
    repeat 
      Application.ProcessMessages; 
    until WaitForSingleObject(ProcessInfo.hProcess, 200) <> WAIT_TIMEOUT; 
  
    CloseHandle(ProcessInfo.hProcess); 
    CloseHandle(ProcessInfo.hThread); 
  
    ShowMessage('Terminé'); 
  end 
  else RaiseLastOSError; 
end;

Ici l'exemple ne fait qu'attendre la fin de l'application, mais le handle retourné dans ProcessInfo.hProcess peut être utilisé dans toutes les fonctions API sur les process.
Pour lancer une application avec des paramètres, il faut les insérer dans la ligne de commande :

Code delphi : Sélectionner tout
  CommandLine := '"Notepad.exe" "C:\temp\essai.txt"';

CreateProcess recherche l'exécutable dans le répertoire en cours puis les répertoires par défaut de Windows, mais il est possible de spécifier le répertoire :

Code delphi : Sélectionner tout
  CommandLine := '"C:\MesProg\MonAppli.exe"';

Mis à jour le 13 octobre 2013 Nono40

Pour pouvoir fermer une application extérieure (par exemple la calculatrice de Windows), nous avons besoin dans un premier temps de connaître son Handle de fenêtre. Pour cela nous allons utiliser la fonction FindWindow.
Ensuite une fois que l'on connaît le handle de cette fenêtre, il ne nous reste plus qu'à lui envoyer le message WM_CLOSE par le biais de la procédure SendMessage.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
var 
  monhandle : THandle; 
Begin 
  //Le second paramètre de FindWindow est le titre de la fenêtre! 
  monhandle := FindWindow(nil,'Calculatrice'); 
  SendMessage(monhandle,WM_CLOSE,0,0); 
end;

Mis à jour le 13 octobre 2013 atlantis

Par défaut, le titre de l'application dans la barre des tâches est le nom de l'exécutable. Il est cependant possible de le modifier.

À la conception :

Aller dans le menu Projet | Options... puis dans l'onglet Application, modifier la valeur de "titre".

À l'exécution :

Modifier simplement la valeur de Application.Title.

Mis à jour le 13 octobre 2013 Nono40

Si vous souhaitez exécuter une application particulière au démarrage d'une session utilisateur, ajoutez une entrée dans la clé \Software\Microsoft\Windows\CurrentVersion\Run de la base de registre.

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
procedure RegWriteRunApp(Path: string);  
var  
Reg: TRegistry;  
begin  
Reg := TRegistry.Create;  
try  
  with Reg do begin  
  RootKey := HKEY_CURRENT_USER; // A l'ouverture d'une session d'un utilisateur 
  // RootKey := HKEY_LOCAL_MACHINE; // A l'ouverture d'une session de chaque utilisateurs 
  if OpenKey('\Software\Microsoft\Windows\CurrentVersion\Run', False) 
  then WriteString('MonAppli', Path);  
  end;  
finally  
  Reg.Free;  
end;  
end;
La clé Run est persistante, à la différence de la clef RunOnce, qui peut être employée pour indiquer les commandes que le système exécutera une fois et puis supprimera.

Mis à jour le 17 septembre 2013 Laurent Dardenne

Pour retrouver le nom d'une application en cours d'exécution, on utilisera la fonction CreateToolhelp32Snapshot, qui renvoie la liste des process.
Ensuite, on parcourra cette liste en utilisant la fonction Process32Next, qui renvoie les informations d'un process dans un enregistrement de type TProcessentry32 :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
tagPROCESSENTRY32 = packed record 
    dwSize: DWORD;               // taille de l'enregistrement 
    cntUsage: DWORD;             // Compteur de référence du process, si zéro le process se termine. 
    th32ProcessID: DWORD;        // Identifiant du process 
    th32DefaultHeapID: DWORD;    // Identifiant de la pile par défaut du process 
    th32ModuleID: DWORD;         // Identifiant du module du process 
    cntThreads: DWORD;           // Nombre de thread du process 
    th32ParentProcessID: DWORD;  // Identifiant du process parent ( 'son créateur' ) 
    pcPriClassBase: Longint; // Priorité de base des threads crée par ce process 
    dwFlags: DWORD;              // Réservé 
    szExeFile: array[0..MAX_PATH - 1] of Char; // le nom de l'exécutable. 
  end;
Vous devez ajouter l'unité TLHelp32 dans la clause uses.
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
uses TLHelp32; 
  
function ExeRunning(NomApplication : string; StopProcess:Boolean):Boolean; 
// Teste si une application est en cours d'exécution 
// StopProcess indique si on termine l'application 'NomApplication' 
  
// Code proposé par Thunder_nico 
  
var 
  ProcListExec : TProcessentry32; 
  PrhListExec : Thandle; 
  Continu : Boolean; 
  isStarted : Boolean; 
  HandleProcessCourant : Cardinal;    
  PathProcessCourant : string; 
  ProcessCourant :String; 
  
begin 
  // Liste des applications en cours d'exécution 
  // Initialisation des variables et récuperation de la liste des process 
  ProcListExec.dwSize:=sizeof(ProcListExec); 
  Continu := True; 
  isStarted := False; 
  
Try 
  // Récupére la liste des process en cours d'éxécution au moment de l'appel 
  PrhListExec:=CreateToolhelp32Snapshot(TH32CS_SNAPALL,0); 
  if (PrhListExec <> INVALID_HANDLE_VALUE) 
    then 
      begin 
        //On se place sur le premier process 
        Process32First(PrhListExec,ProcListExec); 
  
        // Tant que le process recherché n'est pas trouvé et qu'il reste 
        // des process dans la liste, on parcourt et analyse la liste 
        while Continu do 
          begin 
            ProcessCourant := Uppercase(ExtractFileName(ProcListExec.szExeFile)); 
            ProcessCourant := ChangeFileExt(ProcessCourant,''); 
            isStarted := (ProcessCourant = Uppercase(NomApplication)); 
            if isStarted then 
              begin 
                HandleProcessCourant := ProcListExec.th32ProcessID; 
                PathProcessCourant := ExtractFilepath(ProcListExec.szExeFile); 
                Continu := False; 
              end 
            else // Recherche le process suivant dans la liste 
              Continu := Process32Next(PrhListExec,ProcListExec); 
      end; 
  
    if StopProcess 
      then 
        if isStarted then 
          begin  // Termine le process en indiquant le code de sortie zéro 
            TerminateProcess(OpenProcess(PROCESS_TERMINATE,False,HandleProcessCourant),0); 
            Sleep(500); // Laisse le temps au process en cours de suppression de s'arrêter 
          end; 
  end; 
Finally 
  CloseHandle(PrhListExec); // Libère les ressources 
  Result := isStarted; 
end; 
  
end;

Mis à jour le 17 septembre 2013 Laurent Dardenne

Solution proposée par Keke des iles.

Dans certain cas, la mise en veille de la machine peut rendre impossible l'exécution d'un traitement programmé. Il convient donc dans ce cas d'empêcher le système de se mettre en veille.
Lorsque le système se charge de placer la machine en veille, il envoie le message WM_POWERBROADCAST à toutes les applications actives ; ces applications pouvant ou non traiter ce message.

Voici sa mise en oeuvre :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  
type  
  TForm1 = class(TForm)  
  private  
    { Déclarations privées }  
  public  
    procedure WMPowerBroadcast(var Msg: TMessage); message WM_POWERBROADCAST;  
  end;  
  
var  
  Form1: TForm1;  
  
implementation  
  
{$R *.dfm}  
  
procedure TForm1.WMPowerBroadcast(var Msg: TMessage);  
const  
  PBT_APMQUERYSUSPEND = $0000;  
begin  
  if Msg.wParam = PBT_APMQUERYSUSPEND then  
    Msg.Result := BROADCAST_QUERY_DENY;  
end;  
  
end.
Ainsi, dès que votre application reçoit le message WM_POWERBROADCAST, la procédure WMPowerBroadcast est appelée et informe le système de ne pas placer la machine en veille. Le système réitérera cette demande de mise en veille ultérieurement.

Mis à jour le 17 septembre 2013 Laurent Dardenne

La fonction SetForeGroundWindow permet de mettre une fiche en avant-plan directement. Mais depuis Windows 98 et Windows 2000, elle ne place plus la fenêtre en avant-plan mais se contente de la faire clignoter dans la barre des tâches.
Windows limite la possibilité de passer la fenêtre en avant-plan. Tant que l'application n'est pas elle-même en avant-plan, il n'est pas possible de mettre une fenêtre en avant-plan, ce qui en limite beaucoup l'intérêt.
La solution proposée par la MSDN est de changer la base de registre afin de supprimer cette limitation. Ce n'est pas la meilleure méthode à mon avis.
Une autre méthode est d'attacher très provisoirement l'application au processus actuellement en avant-plan. Ainsi, Windows va croire que notre application est en avant-plan et autoriser d'y mettre la fenêtre.

Ceci peut se faire en quelques lignes :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
procedure TForm1.Devant; 
Var Proc,Nous:Integer; 
begin 
  Proc:=GetWindowThreadProcessId(GetForeGroundWindow); 
  Nous:=GetCurrentThreadID; 
  If Proc<>Nous Then 
  Begin 
    // Nous ne sommes pas l'application en premier plan 
    AttachThreadInput(Nous,Proc,True); 
    SetForeGroundWindow(Handle); 
    AttachThreadInput(Nous,Proc,False); 
    Application.BringToFront; 
  End Else 
  Begin 
    // Nous sommes déjà en premier plan 
    SetForeGroundWindow(Handle); 
  End; 
end;

Mis à jour le 17 septembre 2013 Nono40

Il existe une fonction de l'API Win32, OutputDebugString, permettant d'envoyer du texte vers le debugger de Delphi, ces messages étant visibles dans le "Journal d'événements" (menu "Voir -> Fenêtres de débogage -> Journal d'événements" ou Ctrl+Alt+V).
Cependant, cette fonction n'est pas très pratique à utiliser, car elle n'autorise que l'envoi d'une chaîne PAnsiChar « telle quelle ». Une petite fonction de formatage s'avère rapidement nécessaire :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
//La syntaxe de la fonction est strictement identique à celle de la procédure "Format". 
  
Procedure DebugPrintFmt ( Const FmtString : String ; Const Args : Array Of Const ) ; 
Begin 
  OutputDebugString(PAnsiChar(Format(FmtString,Args))); 
End;
À noter qu'il existe de nombreux utilitaires capables d'afficher ces chaînes, et ceci même si le programme n'est pas en cours de debug avec Delphi. Un des plus connus est le freeware DebugView.
D'autres debuggers, comme OllyDbg ou Win32DASM, sont également capables d'afficher ces chaînes.

Ne fonctionne qu'avec des applications Win32.

Mis à jour le 17 septembre 2013 Mac LAK

Il est tout à fait possible de tuer un processus directement à partir de son nom de fichier exécutable (par exemple, notepad.exe). Pour cela, il suffit d'utiliser cette procédure (il faut rajouter les unités Windows, SysUtils et TlHelp32 à la clause uses) :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function KillProcess(const ProcessName : string) : boolean; 
var ProcessEntry32 : TProcessEntry32; 
    HSnapShot : THandle; 
    HProcess : THandle; 
begin 
  Result := False; 
  
  HSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
  if HSnapShot = 0 then exit; 
  
  ProcessEntry32.dwSize := sizeof(ProcessEntry32); 
  if Process32First(HSnapShot, ProcessEntry32) then 
  repeat 
    if CompareText(ProcessEntry32.szExeFile, ProcessName) = 0 then 
    begin 
      HProcess := OpenProcess(PROCESS_TERMINATE, False, ProcessEntry32.th32ProcessID); 
      if HProcess <> 0 then 
      begin 
        Result := TerminateProcess(HProcess, 0); 
        CloseHandle(HProcess); 
      end; 
      Break; 
    end; 
  until not Process32Next(HSnapShot, ProcessEntry32); 
  
  CloseHandle(HSnapshot); 
end;
Cette fonction renvoie True si elle a réussi, et False dans le cas contraire.

Tout d'abord, on appelle l'API CreateToolhelp32Snapshot pour dresser une liste des processus. Le paramètre TH32CS_SNAPPROCESS indique qu'il faut récupérer tous les processus. Le second paramètre 0 est ignoré : il est utilisé avec d'autres valeurs du premier paramètre.
Le handle ainsi renvoyé pourra être passé aux routines Process32First et Process32Next. Ensuite, il faudra le libérer avec CloseHandle.

Puis, au moyen de Process32First et Process32Next, on énumère tous les processus du snapshot en plaçant leurs informations dans la variable ProcessEntry32.

Pour chaque processus, on teste son nom (nom du fichier exécutable) : s'il est identique, à la casse près, au paramètre ProcessName, alors il faut le tuer.

Pour ce faire, on ouvre un handle de processus avec les droits de terminaison (PROCESS_TERMINATE).
On passe ce handle à la routine TerminateProcess pour tuer le processus. Ensuite, on le libère avec CloseHandle.

Cette version de la routine ne termine que le premier processus dont le nom est passé en paramètre. Une variante peut être écrite pour tuer tous les processus portant ce nom. Il suffit de modifier un peu le contenu de la boucle, en supprimant le Break et en s'assurant que Result n'est pas remis à False après avoir déjà tué un processus mais ne pas avoir pu tuer un autre.
Dans ce cas, la fonction retourne True si elle a tué au moins un processus.

Code Delphi : Sélectionner tout
1
2
3
4
5
6
HProcess := OpenProcess(PROCESS_TERMINATE, False, ProcessEntry32.th32ProcessID); 
if HProcess <> 0 then 
begin 
  Result := TerminateProcess(HProcess, 0) or Result; 
  CloseHandle(HProcess); 
end;
Il est impératif de placer le or Result après l'appel à TerminateProcess, sinon l'optimisation de l'évaluation des or va éviter l'appel à TerminateProcess !

La version dans le zip ci-dessous accepte un paramètre All de type boolean indiquant s'il faut tuer tous les processus trouvés ou seulement le premier.

Mis à jour le 17 septembre 2013 sjrd

Il est très fréquent d'avoir à lancer une application en tant qu'un autre utilisateur. Généralement, on utilise (pour les versions de Windows supérieures à Windows ME) le menu contextuel permettant « d'exécuter en tant que... ».
Nous allons ici présenter une solution qui permet de faire de même mais cette fois directement à partir de Delphi.
Avant tout, il faut définir les constantes suivantes :

Code Delphi : Sélectionner tout
1
2
3
const 
  LOGON_WITH_PROFILE = 1; 
  LOGON_NETCREDENTIALS_ONLY = 2;
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
procedure runas(sUser, sDomain, sPassword : WideString); 
var 
  wUsername, wDomain, wPassword, wApplicationName: WideString; 
  pwUsername, pwDomain, pwPassword, pwApplicationName: PWideChar; 
  StartupInfo: TStartupInfo; 
  ProcessInfo: TProcessInformation; 
begin 
  wUsername := sUser ; 
  wDomain := sDomain; 
  wPassword := Spassword; 
  wApplicationName := sExecutable ; 
  pwUsername := Addr(wUsername[1]); 
  pwDomain := Addr(wDomain[1]); 
  pwPassword := Addr(wPassword[1]); 
  pwApplicationName := Addr(wApplicationName[1]); 
  
  FillChar(StartupInfo, SizeOf(StartupInfo), 0); 
  StartupInfo.cb := SizeOf(StartupInfo); 
  try 
  if not CreateProcessWithLogon(pwUsername,pwDomain,pwPassword,LOGON_NETCREDENTIALS_ONLY, 
nil,pwApplicationName,CREATE_DEFAULT_ERROR_MODE, 
nil,nil,StartupInfo,ProcessInfo) then 
    RaiseLastOSError; //En cas d'erreur, donne des détails sur l'erreur 
end;
La fonction CreateProcessWithLogon est définie dans advapi32.dll. Il faudra donc, pour l'utiliser, la déclarer par :
Code Delphi : Sélectionner tout
function CreateProcessWithLogon; external 'advapi32.dll' name 'CreateProcessWithLogonW';

Mis à jour le 17 septembre 2013 chavers

Il faut noter tout d'abord que l'action à effectuer dépend de la version de Windows. Nous allons donc au préalable utiliser une fonction pour déterminer celle-ci :

Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  
(******************************************************************************) 
(* Fonction pour determiner la version de Windows                             *) 
(* Renvoi True si version Windows NT,2000,XP, sinon renvoit False             *) 
(******************************************************************************) 
  
Function DetermineVersionWindows: Boolean;  
begin 
//Fonctionne pour les versions de Windows autre que 95, 98 et Millenium 
Result := True; 
case Win32MajorVersion of 
//   3: Microsoft Windows NT 3.51 
    4: case Win32MinorVersion of 
0:  case Win32Platform of 
  //   1: Microsoft Windows 95 ou Microsoft Windows 95 OSR2 
      2: Result:= True; 
    else 
      Result:= False; 
    end; 
10, 90: Result := False;          
      else 
Result:= False; 
      end; 
    5: case Win32MinorVersion of //2000, XP et 2003 
0, 1, 2:  Result:= True; 
      else 
Result:= False; 
      end; 
  else 
    Result:= False; 
  end; 
end;
À présent, suivant la valeur du paramètre Desactiver, nous allons désactiver ou activer le gestionnaire de tâches :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  
(******************************************************************************) 
(* Fonction pour désactiver ou activer le gestionnaire de tâches lors de       *) 
(* l'appui sur CTRL + ALT + SUPPR                                              *) 
(* Passer TRUE dans le paramètre Desactiver pour désactiver le gestionnaire   *) 
(* de tâches et sinon passer FALSE pour le réactiver                           *) 
(******************************************************************************) 
  
procedure ActiverDesactiverTaskManager(Desactiver: Boolean); 
var 
  OldVal : Longint; 
  Reg    : Tregistry; 
begin 
  if Desactiver = True then 
  // Désactiver le gestionnaire de tache 
  begin 
    if DetermineVersionWindows then 
    // Cas des versions Windows NT,2000,XP 
    begin 
      reg := TRegistry.Create; 
      reg.RootKey := HKEY_CURRENT_USER; 
      // Test pour savoir si la clé de l'utilisateur courant existe 
      if reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Policies\System', False) then 
      begin 
reg.WriteString('DisableTaskMgr', '1'); 
      end 
      else 
      // Sinon création dans la clé Machine. 
      begin 
reg.RootKey := HKEY_CURRENT_USER; 
reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Policies\System', True); 
reg.WriteString('DisableTaskMgr', '1'); 
      end; 
      reg.CloseKey; 
    end 
    else 
    // Cas des versions Windows 95,98,Me 
    begin 
      SystemParametersInfo(SPI_SCREENSAVERRUNNING, word(True), @OldVal, 0); 
    end; 
  end 
  else 
  // Réactiver le gestionnaire de tache 
  begin 
    if DetermineVersionWindows then 
    // Cas des versions Windows NT,2000,XP 
    begin 
      reg := TRegistry.Create; 
      reg.RootKey := HKEY_CURRENT_USER; 
      // Test pour savoir si la clé de l'utilisateur courant existe 
      if reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Policies\System', False) then 
      begin 
reg.DeleteValue('DisableTaskMgr'); 
      end 
      else 
      // Sinon création dans la clé Machine. 
      begin 
reg.RootKey := HKEY_CURRENT_USER; 
reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Policies\System', True); 
reg.DeleteValue('DisableTaskMgr'); 
      end; 
      reg.CloseKey; 
    end 
    else 
    // Cas des versions Windows 95,98,Me 
    begin 
      SystemParametersInfo(SPI_SCREENSAVERRUNNING, word(False), @OldVal, 0); 
    end; 
  end; 
end;

Mis à jour le 17 septembre 2013 Thierry Laborde

Lorsqu'on affiche une fiche contenue dans une dll, un second bouton de l'application apparaît dans la barre des tâches.
Une astuce pour l'éviter consiste à transmettre le Handle de l'application à la dll.

Dans l'exe : sélectionnez

Code Delphi : Sélectionner tout
1
2
  
AfficheForm(Application.Handle);

Dans la dll : sélectionnez
Code Delphi : Sélectionner tout
1
2
3
4
5
6
  
procedure AfficheForm(AppHandle: THandle); 
begin 
  Application.Handle := AppHandle; 
  { Code de la procédure } 
end;

Mis à jour le 17 septembre 2013 Smortex

On utilise pour ce faire l'option Position de la form, à laquelle on peut mettre plusieurs valeurs :

  • poDesigned : la fenêtre apparaît avec la même taille et la même position que lors de sa conception ;
  • poDefault : c'est le système d'exploitation qui définit la taille et la positon de la fenêtre ;
  • poDefaultPosOnly : la fenêtre apparaît avec la taille de sa conception, mais c'est le système d'exploitation qui définit sa position ;
  • poDefaultSizeOnly : la fenêtre apparaît avec la position définie lors de la conception, mais c'est le système d'exploitation qui définit la taille ;
  • poScreenCenter : la fenêtre apparaît avec la taille de sa conception et est placée au centre de l'écran. Un ajustement peut se faire dans le cas d'utilisation de plusieurs écrans, suivant les paramètres indiqués ;
  • poDesktopCenter : la fenêtre apparaît avec la taille de sa conception et est placée au centre de l'écran. Aucun ajustement ne se fait lors de l'utilisation du plusieurs écrans à la fois ;
  • poMainFormCenter : la fenêtre apparaît avec la taille de sa conception et est centrée suivant la fenêtre principale de l'application ;
  • poOwnerFormCenter : la fenêtre apparaît avec la taille de sa conception et est centrée sur la fenêtre que l'on choisit.

Code Delphi : Sélectionner tout
1
2
3
4
procedure TForm1.FormCreate(Sender: TObject); 
begin 
  Form1.Position := poScreenCenter; 
end;

On peut aussi utiliser la fonction suivante pour centrer une fenêtre avec uniquement son Handle :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
procedure CenterWnd(const Wnd: HWND);  
var  
  R: TRect;  
  SW, SH, W, H: Integer;  
begin  
  SW := GetSystemMetrics(SM_CXSCREEN);  
  SH := GetSystemMetrics(SM_CYSCREEN);  
  GetWindowRect(Wnd, R);  
  W := R.Right - R.Left;  
  H := R.Bottom - R.Top;  
  R.Left := (SW - W) div 2;  
  if R.Left < 0 then R.Left := 0;  
  R.Top := (SH - H) div 2;  
  if R.Top < 0 then R.Top := 0;  
  MoveWindow(Wnd, R.Left, R.Top, W, H, True);  
end;

De même, on peut faire varier l'apparition de la fenêtre avec l'option WindowState, pour laquelle il existe aussi quelques variantes :
  • wsMaximized : agrandit la fenêtre au maximum ;
  • wsMinimized : réduit la fenêtre ;
  • wsNormal : la fenêtre a les mêmes dimensions et la même position que lors de sa conception.

Code Delphi : Sélectionner tout
1
2
3
4
procedure TForm1.FormCreate(Sender: TObject); 
begin 
  Form1.WindowState := wsMaximized; 
end;

Mis à jour le 17 septembre 2013 smyley xenos

Pour connaître l'état des touches, on peut utiliser les fonctions GetKeyState et/ou GetAsyncKeyState.

Le code suivant permet à l'aide de GetKeyState de savoir si le clavier est en mode majuscule (CAPS LOCK activé) :

Code Delphi : Sélectionner tout
1
2
3
4
5
  
if (GetKeyState(VK_CAPITAL) and 1) = 0 then  
begin  
  //Traitement...  
end;
Vous pouvez avoir un exemple pratique d'utilisation de GetAsyncKeyState dans le source de Nono40 ci-dessous.

Mis à jour le 17 septembre 2013 Bloon

Pour imprimer un fichier PDF, on peut passer par la fonction ShellExecute comme cela est montré dans le code ci-dessous :

Code Delphi : Sélectionner tout
IF ShellExecute(Handle,'print','MON_FICHER.PDF',nil,nil,SW_HIDE) <=32 THEN ShowMessage(SysErrorMessage(GetLastError));

Il faudra installer Acrobat au préalable.
Windows imprimera avec le programme rattaché aux extension .pdf. (Donc Acrobat).
Pour les utilisateurs d'Acrobat Reader, il faut plutôt utiliser le code suivant (si, par exemple, nous souhaitons imprimer le fichier D:\DOCUMENTATIONS\fortran.pdf) :
Code Delphi : Sélectionner tout
1
2
IF ShellExecute(Handle, nil,'acrord32.exe', '/t "D:\DOCUMENTATIONS\fortran.pdf"',nil,SW_HIDE) <= 32 THEN  
    ShowMessage(SysErrorMessage(GetLastError));

Mis à jour le 17 septembre 2013 Bestiol Eric.H

Pour ce faire, il faut trouver le handle du contrôle de l'application tierce et lui envoyer un message.
La procédure ci-dessous intercepte les coordonnées de la souris en utilisant l'API GetCursorPos, quelle que soit l'application qui se trouve sous le curseur, exceptés le bureau et la barre des tâches.
L'API WindowFromPoint retourne le handle du contrôle qui se trouve aux coordonnées interceptées.
La combinaison des touches "Shift" + "Bouton gauche" de la souris stocke le handle du contrôle dans une listBox.

Les handles selectionnés sont valides tant que l'application tierce n'est pas fermée.

Identification des variables :

  • KeyIndex : état des touches (enfoncées ou relâchées) ;
  • NewMousePos,MousePos : coordonnées souris ;
  • HD : handle du controle actif ;
  • P : variable de boucle ;
  • Capt : détermine que la touche de la souris a été relâchée et autorise une nouvelle capture ;
  • Fin : variable globale de contrôle de la boucle de traitement.


Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  
procedure TForm1.CapteInfoControl; 
var WText,ClassName      : Array[0..255] of Char; 
    KeyIndex             : array [0..255] of boolean; 
    NewMousePos,MousePos : Tpoint; 
    HD                   : Hwnd; 
    P                    : Integer; 
    Capt                 : boolean; 
  
begin 
// initialisation 
Fin:=false; 
Capt:=true; 
for P:=0 to 255 do KeyIndex[P]:=false; 
  // boucle de traitement 
repeat 
    // récupération des coordonnées souris 
  if (GetCursorPos(NewMousePos)) and 
      ((NewMousePos.X <> MousePos.X) or (NewMousePos.Y <> MousePos.Y)) then 
      begin 
MousePos:=NewMousePos; 
  
//récupération des information du contrôle 
Hd:=WindowFRomPoint(NewMousePos); 
GetWindowText(hd,WText,SizeOf(WText)); 
GetClassName(hd,ClassName,SizeOf(ClassName)); 
  
//Affichage 
label1.caption:=strfmt('Handle du contrôle : %g - Texte du contrôle: %s  - Classe du contrôle : %s',[Hd,String(WText), 
String(ClassName)]); 
Application.ProcessMessages; 
      end; 
  
    // récupération des états des touches 
    for P:=0 to 255 do KeyIndex[P]:=GetAsyncKeyState(P) <> 0; 
  
    // stocke les informations du contrôle [ClickGauche(1)]+[shift(16)] 
    if KeyIndex[1] and KeyIndex[16] and Capt then 
    begin 
ListBox2.Items.Add(IntToStr(Hd)+' : '+String(WText)+' - '+String(ClassName)); 
Capt:=false; 
    end; 
  
    // autorise une capture des informations   
    // autre que celle la touche de la souris a été relachée 
    Capt:=Not(KeyIndex[1]); 
    Application.ProcessMessages; 
  
until Fin=true; 
end;

Dans les exemples suivants, le paramètre HD est le Handle stocké avec la procédure ci-dessus.
Exemple pour cliquer sur un bouton d'une application tierce :
Code Delphi : Sélectionner tout
1
2
3
4
5
  
procedure TForm1.BoutonClick(HD:Hwnd); 
begin 
    SendMessage(HD,BM_CLICK, 0, 0); 
end;

Exemple pour la recopie d'un TEdit d'une application tierce dans son application :
Code Delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
  
function TForm1.CopyEdit(HD:Hwnd):string; 
var Size : integer; 
begin 
    Result:=''; 
    SendMessage(HD,WM_SETFOCUS, 0, 0); 
  
    Size:=SendMessage(HD,WM_GETTEXTLENGTH,0,0)+1; 
    SetLength(Result,Size); 
  
    SendMessage(HD,WM_GETTEXT,Size,Integer(@Result[1])); 
    SendMessage(HD,WM_KillFOCUS, 0, 0); 
end;

API permettant de déterminer si un contrôle est visible ou pas dans une application tierce :
Code Delphi : Sélectionner tout
1
2
  
function IsWindowVisible(hWnd: HWND): BOOL; stdcall;

Mis à jour le 17 septembre 2013 petitcoucou31

Lorsqu'un exécutable est lancé sous Vista, si le nom du fichier contient des mot-clés de ce style : « install », « patch », « setup », ou encore « update », son lancement nécessite des droits d'administrateur.
Et dans ce cas-là, CreateProcess est tout simplement annulé sans aucun avertissement.

Donc le « problème » vient du système d'administration de Vista.

Voici quelques solutions :

  • utiliser ShellExecute en lieu et place de CreateProcess. ShellExecute pourra alors lancer le programme et, le cas échéant, afficher la boîte de dialogue système de validation du lancement ;
  • renommer l'exécutable. C'est encore plus simple ;
  • désactiver les droits d'administration (UAC).


En ce qui concerne les droits d'administration, il est très simple de vérifier qu'un exécutable peut être lancé avec CreateProcess ou non : vous remarquerez que lorsque ces fichiers ont un nom de fichier contenant les mots-clés cités plus haut, un petit écusson apparaît sur son icône.
Cet écusson signifie qu'il faut les droits admin sur la machine pour le lancer. Il suffit alors de le renommer pour faire disparaître l'écusson...

Mis à jour le 17 septembre 2013 Pedro

Ce qu'il faut surtout connaître est le nom de la dll impliquée dans cette demande : printui.dll et ses différents paramètres (voir lien ci-dessous).
Deux unités seront à déclarer :

  • Printers ou Vcl.Printers : pour pouvoir obtenir le nom de l'imprimante en cours via l'instruction Printer.Printers[Printer.PrinterIndex] ;
  • ShellApi ou Windows.ShellApi : pour pouvoir utiliser la commande ShellExecute.


Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
uses printers, shellapi;

procedure TForm1.Button1Click(Sender: TObject);
var param : String;
begin
 param:=format('printui.dll,PrintUIEntry /o /n "%s"',[Printer.Printers[Printer.PrinterIndex]]);
 ShellExecute(0,'open','rundll32.exe',PChar(param),nil,SW_SHOW);
end;

Mis à jour le 13 janvier 2020 SergioMaster

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.