Récupérer tous les handles d'une application choisie dans une liste [Résolu]

Messages postés
346
Date d'inscription
jeudi 1 mai 2003
Dernière intervention
4 avril 2011
- 13 avril 2006 à 09:53 - Dernière réponse :
Messages postés
4229
Date d'inscription
vendredi 23 juillet 2004
Dernière intervention
3 août 2018
- 18 avril 2006 à 15:00
Bonjour à tous,

Je liste tous les processus actifs dans une liste (de la même manière que le gestionnaire des taches).

Ensuite, à partir du ProcessID de l'application choisie, j'aimerais récuperer tous les handles de ce processus (un handle correspond à un composant de l'application choisie, je me trompe ?),
pour me permettre de sélectionner un champs texte de cette application.
Je le fait de cette manière:
tabHandles: array [0..100] of integer; // Un HWND est un integer...
procedure TfrmMain.ListerHandles(pid: Cardinal);
var
handles: TList;
i: Integer;
findWindowsStruct: TFindWindowsStruct;
begin
handles:= TList.Create;
Try
findWindowsStruct.ProcessID:= pid; // GetCurrentProcessID
findWindowsStruct.HandleList:= handles;
EnumWindows(@EnumWindowsProc, Integer(@findWindowsStruct));
cbThreads.Clear;
for i:= 0 to handles.Count - 1 do begin
cbThreads.Items.Add('Handle: '+IntToStr(Integer(handles[i])));
tabHandles[i] := Integer(handles[i]);
end;
cbThreads.ItemIndex := 0;
Finally
handles.Free;
end;
end;
Mais quand je teste les handles reçus avec un
PostMessage(tabHandles[cbThreads.ItemIndex]),WM_CHAR,sCar,0); // Simulation du copier
Rien ne se passe.

Par exemple, Si je fait:
myHandle := GetTopwindow(GetforegroundWindow); // Ca marche mais que pour notePad
PostMessage(myHandle,WM_CHAR,sCar,0);
Et que le focus est sur le notepad par exemple, handle est égal à 263014.

Mais si j'utilise la méthode de listage pour le notepad, il ne me retourne qu'un enregistrement qui est différent de celui de la solution ci-dessus (459614).

Comment faire ?

[;)] David, à VERSAILLES
Afficher la suite 

Votre réponse

12 réponses

Meilleure réponse
Messages postés
4229
Date d'inscription
vendredi 23 juillet 2004
Dernière intervention
3 août 2018
- 14 avril 2006 à 00:22
3
Merci
Bon alors regarde j'ai fait un bout de code, cette approche un peut différente mais c'est la seule qui me permet de faire l'inventaire des composants (plus où moins, ne fonctionne pas avec toutes les applications) et d'en selectionner un pour lui envoyer du texte :

Unit USendText;


Interface


Uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;


Type
TFrmMain = Class (TForm)
cbProcessus: TComboBox;
cbThreads: TComboBox;
Edit1: TEdit;
btn_Refresh: TButton;
Procedure btn_RefreshClick(Sender: TObject);
Procedure FormShow(Sender: TObject);
Procedure FormClose(Sender: TObject; Var Action: TCloseAction);
Procedure cbProcessusChange(Sender: TObject);
Procedure cbThreadsClick(Sender: TObject);
Procedure FormCreate(Sender: TObject);
Private
Procedure ListerChilds(pid: Cardinal);
{ Déclarations privées }
Public
{ Déclarations publiques }
End;


Function EnumWindowsProc(hWnd: HWND; lParam: lParam): Bool; stdcall;


Const
aStr = '%s %d';


Var
FrmMain : TFrmMain;
HandleList : TStringList;


Implementation


{$R *.DFM}
Uses TlHelp32;


Var
tabProcessus : Array[0..100] Of Cardinal;
// Contient le ProcessId de la première comboBox
tabHandles : Array[0..100] Of integer;
// Contient les handles de la deuxième comboBox


Function EnumWindowsProc(hWnd: HWND; lParam: lParam): Bool;
Var
processID : DWORD;
aName : Array[0..255] Of Char;
Begin
GetWindowThreadProcessID(hwnd, @processID);
If (hWnd <> FindWindow('Shell_TrayWnd', Nil)) And
(hWnd <> FindWindow('Progman', Nil)) Then
If IsWindowVisible(hwnd) Then
Begin
GetWindowText(hwnd, aName, SizeOf(aName));
HandleList.Add(Format(aStr, [aName, HWnd]));
TabProcessus[HandleList.Count - 1] := hwnd;
Result := True;
End ;
End;


Procedure GetProcessList;
Begin
HandleList.Clear;
EnumWindows(@EnumWindowsProc, 0);
End;



Procedure TFrmMain.ListerChilds(pid: Cardinal);
Var aHandle : THandle;
aName : Array[0..255] Of Char;
Begin
cbThreads.Clear;
aHandle : = 0;
Repeat
aHandle := FindWindowEx(pid, aHandle, Nil , Nil);
If aHandle <> 0 Then
Begin
GetClassName(aHandle, aName, SizeOf(aName));
cbThreads.Items.Add(Format(aStr, [aName, aHandle]));
tabHandles[cbThreads.Items.Count - 1] : = aHandle;
End;
Until aHandle = 0;
End ;


Procedure TfrmMain.cbProcessusChange(Sender: TObject);
Begin
ListerChilds(TabProcessus[cbProcessus.ItemIndex]);
End;


Procedure TFrmMain.cbThreadsClick(Sender: TObject);
Var S : String;
Begin
S : = '1234567890';
SendMessage(tabHandles[cbThreads.ItemIndex], WM_SETTEXT, 0, Longint(s));
//On Change le Texte
End;


Procedure TFrmMain.FormCreate(Sender: TObject);
Begin
HandleList := TStringList.Create;
End;


Procedure TFrmMain.FormClose(Sender: TObject; Var Action: TCloseAction);
Begin
HandleList.Free;
End;


Procedure TFrmMain.FormShow(Sender: TObject);
Begin
btn_Refresh.Click;
End;


Procedure TFrmMain.btn_RefreshClick(Sender: TObject);
Begin
GetProcessList;
cbProcessus.Items.Clear;
cbProcessus.Items.AddStrings(HandleList);
End;


End.

Le TEdit n'est la que pour tester et pour avoir FrmMain dans la liste il faut cliquer sur Refresh

Tester ok sur : NotePad, Calculatrice et sur lui même.

il faut bien sur affiner mais je pense que c'est la marche à suivre

Tiens moi au courant

@+
Cirec

Merci Cirec 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 88 internautes ce mois-ci

Commenter la réponse de Cirec
Messages postés
4229
Date d'inscription
vendredi 23 juillet 2004
Dernière intervention
3 août 2018
- 13 avril 2006 à 12:18
0
Merci
Salut,
Ce bout de code envoie du texte à la calculatrice

procedure TForm1.Button1Click(Sender: TObject);
Var s : String;
H_WinCmd : THandle;
begin
S := '123456789'; // Texte à envoyer
H_WinCmd := FindWindowEx(FindWindow(Nil, 'calculatrice'), 0,'Edit', nil); // on trouve le handle de l'edit
SendMessage(H_WinCmd,WM_SETTEXT,0,Longint(s)); //On Change le Texte
end;

@+
Cirec
Commenter la réponse de Cirec
Messages postés
346
Date d'inscription
jeudi 1 mai 2003
Dernière intervention
4 avril 2011
- 13 avril 2006 à 12:28
0
Merci
Bonjour cirec,

C'est cool, je mettrais le ProcessId dans le premier paramètre mais seulement le 3ème paramètre m'est inconnu, je veux essayer avec tous les handles du processus.

N'y a t-il pas un équivalent qui attends un HWND plutot qu'un pchar en paramètre ?

[;)] David, à VERSAILLES
Commenter la réponse de cs_nitrique
Messages postés
4229
Date d'inscription
vendredi 23 juillet 2004
Dernière intervention
3 août 2018
- 13 avril 2006 à 13:33
0
Merci
Le handle que tu récupère ainsi c'est celui de la fenêtre et non celui d'un composant.
Pour pouvoir envoyer du texte au NotePad il faut trouver le handle de l'Edit qui se trouve sur la fiche



Voici une variante qui change le texte du Notepad
procedure TForm1.Button1Click(Sender: TObject);
Var s : String;
H_WinCmd : THandle;
begin
S := '123456789'; // Texte à envoyer
H_WinCmd := FindWindowEx(FindWindow('NotePad', Nil), 0,'edit', nil); // on trouve le handle de l'edit
SendMessage(H_WinCmd,WM_SETTEXT,0,Longint(s)); //On Change le Texte
end;


Pour énumerer les fenêtres enfants il existe :
EnumChildWindows
Essaye peut être avec mais il faudra quand même faire la différence entre un bouton et un edit pour envoyer le texte au bon composant

@+
Cirec
Commenter la réponse de Cirec
Messages postés
346
Date d'inscription
jeudi 1 mai 2003
Dernière intervention
4 avril 2011
- 13 avril 2006 à 13:40
0
Merci
Très bien, je vais essayer.

Mais dans ce cas, comment ça se fait que ma fonction retourne plusieurs handles pour certains processus (word, ...) ?
De plus, dans le cas d'une application qui a plusieurs champs textes, j'aimerais choisir !

[;)] David, à VERSAILLES
Commenter la réponse de cs_nitrique
Messages postés
4229
Date d'inscription
vendredi 23 juillet 2004
Dernière intervention
3 août 2018
- 13 avril 2006 à 14:11
0
Merci
Pourrais-tu encore fournir les déclarations et implémentations de : EnumWindowsProc & FindWindowsStruct
pour pouvoir faire un teste

@+
Cirec
Commenter la réponse de Cirec
Messages postés
346
Date d'inscription
jeudi 1 mai 2003
Dernière intervention
4 avril 2011
- 13 avril 2006 à 14:28
0
Merci
Aucun pb, les voici:
type
PFindWindowsStruct = ^TFindWindowsStruct;
TFindWindowsStruct = record
ProcessID: DWORD;
HandleList: TList;
var
tabProcessus: array [1..100] of Cardinal; // Contient le ProcessId de la première comboBox
tabHandles: array [0..100] of integer; // Contient les handles de la deuxième comboBox

function EnumWindowsProc(hwnd: HWND; lParam: LPARAM): boolean; stdcall;
var
dwProcessId: DWORD;
begin
if lParam <> 0 then
begin
GetWindowThreadProcessId(hwnd, dwProcessId);
with PFindWindowsStruct(lParam)^ do
if dwProcessID = ProcessID then
HandleList.Add(Pointer(hwnd));
result:= true;
end
else
result:= false;
end;


procedure TfrmMain.ListerProcessus(); // Lister les processus actifs du systeme
var
SnapShot: Cardinal;
ProcessEntry: TProcessEntry32;
i: integer;
begin
cbProcessus.Clear;
SnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); // Création de "l'instantané"
If SnapShot = 0 then Exit; // En cas d'erreur on sort
ProcessEntry.dwSize := SizeOf(ProcessEntry);
If Process32First(SnapShot, ProcessEntry) then begin // Lecture du premier processus de la liste
cbProcessus.Items.Add(ProcessEntry.szExeFile);
cbProcessus.ItemIndex := 0;
i := 0;
while Process32Next(SnapShot, ProcessEntry) do begin // Tant qu'il reste un processus, ajouter son nom à la liste
cbProcessus.Items.Add(ProcessEntry.szExeFile+' ('+IntToStr(ProcessEntry.th32ProcessID)+')');
i := i+1;
tabProcessus[i] := ProcessEntry.th32ProcessID; // Garde le ProcessId pour la correspondance
end;
end;
CloseHandle(SnapShot); // Libération de l'instantané
end;


procedure TfrmMain.ListerHandles(pid: Cardinal);
var
handles: TList;
i: Integer;
findWindowsStruct: TFindWindowsStruct;
begin
handles:= TList.Create;
Try
findWindowsStruct.ProcessID:= pid; // GetCurrentProcessID
findWindowsStruct.HandleList:= handles;
EnumWindows(@EnumWindowsProc, Integer(@findWindowsStruct));
cbThreads.Clear;
for i:= 0 to handles.Count - 1 do begin
cbThreads.Items.Add(IntToStr(pid)+' '+IntToStr(Integer(handles[i])));
tabHandles[i] := Integer(handles[i]);
end;
cbThreads.ItemIndex := 0;
Finally
handles.Free;
end;
end;

procedure TfrmMain.cbProcessusChange(Sender: TObject);
begin
ListerHandles(tabProcessus[cbProcessus.ItemIndex]);
end;

postMessage(tabHandles[cbThreads.ItemIndex],WM_PASTE,0,0); // Dans mon évenement

Il faut juste 2 combobox (cbProcessus et cbThreads)
Le principe est simple, quand tu changer cbProcessus qui contient le nom de tous les processus, j'aurais aimé que ça affiche tous les handles correspondant aux composants de ce processus dans la 2ème lookup.

[;)] David, à VERSAILLES
Commenter la réponse de cs_nitrique
Messages postés
346
Date d'inscription
jeudi 1 mai 2003
Dernière intervention
4 avril 2011
- 14 avril 2006 à 10:43
0
Merci
Heu...

Tu est sur que tout est la ?

Ma combobox de proccessus est vide, EnumWindows(@EnumWindowsProc, 0); ne remplit pas HandleList.

Ne faut-il pas garder ma fonction ListerProcessus() ?

[;)] David, à VERSAILLES
Commenter la réponse de cs_nitrique
Messages postés
346
Date d'inscription
jeudi 1 mai 2003
Dernière intervention
4 avril 2011
- 14 avril 2006 à 11:10
0
Merci
En fait, il ne passe pas IsWindowVisible dans EnumWindowsProc.
Si j'enlève la condition, ça plante !

Quels élements cible tu en les voulant visibles ?
Ne peut-on pas utiliser ta méthode avec ma fonction ListerProcessus() ?

[;)] David, à VERSAILLES
Commenter la réponse de cs_nitrique
Messages postés
4229
Date d'inscription
vendredi 23 juillet 2004
Dernière intervention
3 août 2018
- 14 avril 2006 à 11:30
0
Merci
La source fonctionne tel quel.
le problème c'est que je n'ai pas réussi à récuperer les handles des composants d'une fenêtre avec ta fonction.


par contre celle-ci fonctionne très bien (chez moi) et si j'enlève IsWindowVisible ça ne plante pas mais j'ai toutes les fenêtres du système ?


ps : après avoir cliquer sur Refresh tu choisis un processus qui t'interesse tu cliques dessus et si il y en a (des composants) il met les handles dans la liste

@+
Cirec
Commenter la réponse de Cirec
Messages postés
346
Date d'inscription
jeudi 1 mai 2003
Dernière intervention
4 avril 2011
- 18 avril 2006 à 14:30
0
Merci
Peux tu m'envoyer ton exe que je le teste sur mon poste ?
Car rien à faire, ma liste ne veut pas se remplir

[;)] David, à VERSAILLES
Commenter la réponse de cs_nitrique
Messages postés
4229
Date d'inscription
vendredi 23 juillet 2004
Dernière intervention
3 août 2018
- 18 avril 2006 à 15:00
0
Merci
Ok
Donne moi ton adresse mail par MP et je t'envoie le tout

@+
Cirec
Commenter la réponse de Cirec

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.