Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Library: Windows API / MS.NET Framework API (https://www.delphipraxis.net/20-library-windows-api-ms-net-framework-api/)
-   -   Delphi Das Handle eines Fensters herausfinden (https://www.delphipraxis.net/745-das-handle-eines-fensters-herausfinden.html)

Chewie 31. Aug 2002 17:31


Das Handle eines Fensters herausfinden
 
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]


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:16 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz