Handles auf Objekte in sichtbaren Fenstern kann man mit
EnumWindows recht einfach finden. Komplizierter sieht es schon aus, wenn das Programm im Hintergrund läuft und z. B. in die Tray minmimiert ist.
Da ich in den letzten Wochen dies das ein oder andere Mal gebraucht habe und dabei wieder dank der netten Leute hier einiges über die
WinAPI &
nonVCL-Programmierung gelernt hab, schreib ich diesen Tip.
Es ist wohl nicht der sicherste Code, ich habe keine
try..finally-Blöcke etc. verwendet wie ich es vielleicht hätte tun sollen, aber es funktioniert und vielleicht liefere ich die nach.
Folgendermaßen funnktioniert das Ganze:
1.
Delphi-Quellcode:
type DWordArray = Array of DWord;
function GetThreadID(const FileName: String): DWordArray;
var
ToolHnd, MToolHnd: HWND;
PE32: TProcessEntry32;
ME32: TModuleEntry32;
TE32: TThreadEntry32;
PIDArray, TIDArray: DWordArray;
PID: DWord;
a: Byte;
begin
Result := nil;
PIDArray := nil;
TIDArray := nil;
ToolHnd := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS or TH32CS_SNAPTHREAD, 0);
if ToolHnd <> ERROR_INVALID_HANDLE then
begin
PE32.dwSize := SizeOf(ProcessEntry32);
if Process32First(ToolHnd, PE32) then
begin
repeat
if CompareText(ExtractFileName(FileName), PE32.szExeFile) = 0 then
begin
SetLength(PIDArray, Length(PIDArray) + 1);
PIDArray[Length(PIDArray)-1] := PE32.th32ProcessID;
end;
until not Process32Next(ToolHnd, PE32);
end
else
begin
Result := nil;
Exit;
end;
PID := 0;
if Length(PIDArray) = 0 then
begin
Result := nil;
Exit;
end;
for a := 0 to Length(PIDArray) - 1 do
begin
MToolHnd := CreateToolHelp32Snapshot(TH32CS_SNAPMODULE, PIDArray[a]);
if MToolHnd <> ERROR_INVALID_HANDLE then
begin
ME32.dwSize := SizeOf(ModuleEntry32);
if Module32First(MToolHnd, ME32) then
begin
repeat
if CompareText(FileName, ME32.szExePath) = 0 then
begin
PID := ME32.th32ProcessID;
break;
end;
until not Module32Next(MToolHnd, ME32);
end
else
begin
Result := nil;
Exit;
end;
end;
CloseHandle(MToolHnd);
end;
end
else
begin
Result := nil;
Exit;
end;
TE32.dwSize := Sizeof(ThreadEntry32);
if Thread32First(ToolHnd, TE32) then
begin
repeat
if TE32.th32OwnerProcessID = PID then
begin
SetLength(TIDArray, Length(TIDArray) + 1);
TIDArray[Length(TIDArray)-1] := TE32.th32ThreadID;
end;
until not Thread32Next(ToolHnd, TE32);
end
else
begin
Result := nil;
Exit;
end;
if Length(TIDArray) = 0 then
begin
Result := nil;
Exit;
end;
CloseHandle(ToolHnd);
if Length(TIDArray) <> 0 then Result := TIDArray;
end;
Hier wird an die Funktion der Name + Pfad des Programms übergeben, in dem nach dem
Handle gesucht werden soll. Das Programm sollte nur einmal laufen. Diese Funktion liefert die IDs aller Threads des gesuchten Prozesses.
2. Wir enumerieren die Fenster jedes Threads
Delphi-Quellcode:
for a := 0 to Length(TIDArray) - 1 do
begin
EnumThreadWindows(TIDArray[a], @EnumWndProc, LabelHnd);
end;
Die Callback-Funktion:
Delphi-Quellcode:
{ Thread-Window-Callback-Funktion }
function EnumWndProc(Hnd: HWND; lParam: LParam): Boolean; stdcall;
var
Buf: array[0..1024] of Char;
ClassName, WindowText: string;
begin
Result := True;
SetString(ClassName, Buf, GetClassName(Hnd, Buf, 1024));
SetLength(WindowText, SendMessage(Hnd, WM_GETTEXTLENGTH, 0, 0));
if ClassName = ClassName_gesucht then
if WindowText = WindowText_gesucht then
begin
Result := False;
Hnd_gesucht := Hnd;
end;
EnumChildWindows(Hnd, @EnumChildProc, lParam);
end;
Dazu werden folgende globalen Variablen benötigt:
Delphi-Quellcode:
var
Hnd_gesucht: HWND;
//unser gesuchtes Handle
ClassName_gesucht:
String;
//Der Klassentyp des gesuchten Objekts
WindowText_gesucht:
String;
//Die Caption des gesuchten Objekts
Wenn man z. B. den Button
Button1 suchen will, muss man für ClassName
TButton und für WindowText die Caption des Buttons einsetzen.
3.
Wenn in der ThreadWindow-Funktion das Fenster nicht gefunden wird, kann es noch ein Kind-Fenster eines Threadfensters sein. Um das herauszufinden, wird in der obigen Callback-Funktion die EnumChildWindows-Funktion aufgerufenn. Die Callback-Funktion dieser Funktion ist wiederum fast identisch mit der anderen Callback-Funktion, da ja nach dem gleichen gesucht wird:
Delphi-Quellcode:
var
Buf: array[0..1024] of Char;
ClassName, WindowText: string;
begin
Result := True;
SetString(ClassName, Buf, GetClassName(Hnd, Buf, 1024));
SetLength(WindowText, SendMessage(Hnd, WM_GETTEXTLENGTH, 0, 0));
if ClassName = ClassName_gesucht then
if WindowText = WindowText_gesucht then
begin
Result := False;
Hnd_gesucht := Hnd;
end;
end;
Jetzt haben wir entweder das
Handle des Objekts oder das Objekt existert nicht und Hnd_gesucht erfährt keine Wertänderung.
[edit=Matze][ code ] durch [ delphi ]-Tags ersetzt. Mfg, Matze[/edit]
[edit=Phoenix]Versuch, den Syntax-Highlighter nochmal anzustubbsen. Mfg, Phoenix[/edit]