FAQ DelphiConsultez toutes les FAQ
Nombre d'auteurs : 124, nombre de questions : 934, dernière mise à jour : 23 octobre 2024 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.
- Comment réaliser un splash screen ?
- Comment réaliser un splash screen transparent ?
- Comment n'instancier qu'une seule fois un programme ?
- Comment passer au premier plan une application instanciée une seconde fois ?
- Comment imposer une pause au programme ?
- Comment ne pas bloquer une application pendant un traitement long ?
- Comment récupérer les paramètres passés au programme ?
- Comment exécuter une application extérieure ?
- Comment lancer et contrôler une application extérieure ?
- Comment fermer une application externe ?
- Comment modifier le titre de l'application dans la barre des tâches ?
- Comment lancer automatiquement une application au démarrage de Windows ?
- Comment savoir si une application est en cours d'exécution ?
- Comment interdire la mise en veille d'une machine sous Windows ?
- Comment remettre son application en avant plan ?
- Comment envoyer du texte au debugger ?
- Comment tuer un processus à partir de son nom ?
- Comment lancer un programme sous un autre contexte de sécurité ?
- Comment désactiver la combinaison de touches CTRL-ALT-SUPPR ?
- Comment ne pas afficher l'icône d'une fiche dans la barre des tâches ?
- Comment centrer la fenêtre sur l'écran ?
- Comment connaître l'état des touches du Clavier ?
- Comment imprimer un fichier PDF à partir de son application sans l'ouvrir ?
- Comment piloter une application tierce ?
- Pourquoi CreateProcess ne fonctionne-t-il pas dans certains cas sous Vista ?
- Comment afficher la file d'impression de l'imprimante en cours ?
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. |
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; {...} |
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. |
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. |
L'important, dans notre cas, est qu'il existe et donc que le programme (ou service) est bien actif et a verrouillé le Mutex.
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. |
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.
Il existe deux manières pour faire cela :
1. La méthode Sleep :
Il suffit de mettre Application.Sleep(duree_voulue) où 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; |
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; |
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; |
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; |
Code delphi : | Sélectionner tout |
uses [...], ShellApi;
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'),...)
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é.
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"';
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; |
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.
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; |
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; |
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; |
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. |
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; |
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; |
D'autres debuggers, comme OllyDbg ou Win32DASM, sont également capables d'afficher ces chaînes.
Ne fonctionne qu'avec des applications Win32.
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; |
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; |
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.
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; |
Code Delphi : | Sélectionner tout |
function CreateProcessWithLogon; external 'advapi32.dll' name 'CreateProcessWithLogonW';
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; |
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; |
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; |
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; |
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; |
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)); |
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; |
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...
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; |
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 çaLes 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.