Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   ClassName von Edit (https://www.delphipraxis.net/207198-classname-von-edit.html)

Ykcim 3. Mär 2021 10:32

ClassName von Edit
 
Hallo Zusammen,

ich versuche gerade auf ein anderes Programm zuzugreifen und habe da meine Schwierigkeiten...

Delphi-Quellcode:
var
  fwnd: THandle;
  wnd: HWND;
  wnd_edit: HWND;
  CName: array [0..255] of Char;
begin
   fwnd := FindWindow(nil, 'Das andere Programm');
   GetClassName(fWND, CName, 256);

   wnd := FindWindowEx(wnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, 'Empfänger');  //Bis hierhin passt es. Der ClassName der App ist 'WindowsForms10.Window.8.app.0.141b42a_r6_ad1'

   wnd_edit := FindControlByNumber(wnd, 'WindowsForms10.EDIT.app.0.141b42a_r6_ad1', 1);    //Wenn ich jetzt aber auf das Edit zugreifen möchte, muss ich den ClassName ändern
   if wnd_edit<>0 then SendMessage(wnd_edit,WM_SETTEXT,0,Integer(Pchar(Edit_HausNr.Text)));   //Wenn ich das händisch mach geht das.

   //wnd_edit:= FindControlByNumber(FindWindow(CName, nil),'Edit', 1)  ///Das klappt nicht, dann wird wnd_edit=0
end;

Das Problem ist, dass ich das Edit mit der ControllNr finde:
Delphi-Quellcode:
function TTMSForm2.FindControlByNumber(hApp: HWND; ClassName: string; ControlNr: Word = 1): HWND;
var
  i: Word;
  hControl: HWND;
begin
  Result := 0;
  if IsWindow(hApp) then
  begin
    Dec(ControlNr);
    hControl := 0;
    for i := 0 to ControlNr do
    begin
      hControl := FindWindowEx(hApp, hControl, PChar(ClassName), nil);
      if hControl = 0 then
        Exit;
    end;
  end;
  Result := hControl;
end;
Dafür brauche ich den ClassName. Der ändert sich aber:
Von der App : WindowsForms10.Window.8.app.0.141b42a_r6_ad1
Von dem Edit : WindowsForms10.EDIT.app.0.141b42a_r6_ad1

Ich glaube nicht, dass es sinnvoll ist, den ClassName "händisch" zu ändern. Wenn die App auf einem anderen Rechner läuft, wird es nicht mehr klappen.

Kann mir jemand einen Tip geben, wie ich das hinbekomme?

Vielen Dank
Patrick

KodeZwerg 3. Mär 2021 10:56

AW: ClassName von Edit
 
Ändert sich auch die Caption andauernd?
Wenn beides dynamisch ist, würde ich über PID ein Handle ermitteln.

Ist Control-ID auch dynamisch muss man sich durch alle Childs durchiterieren.

Ykcim 3. Mär 2021 11:01

AW: ClassName von Edit
 
Das Problem ist, dass das Edit kein Caption hat...

Was meinst Du mit PID?

KodeZwerg 3. Mär 2021 11:06

AW: ClassName von Edit
 
Ich meinte Caption vom Ziel-Fenster.
PID = ProcessID

KodeZwerg 3. Mär 2021 11:14

AW: ClassName von Edit
 
Andersrum, wenn ich was Fernsteuern mag, schau ich mir mit WinSpy ö.ä. erstmal das Ziel an.

Wenn ich darüber eine feste Control-Id bekomme für das Edit ist die halbe Miete schon im Sack.

Dann nurnoch eine Möglichkeit finden mich mit dem Ziel zu verbinden.

Also per FindWindow() ein Handle holen. Vom Fenster, nicht vom Edit!
Wenn das nicht möglich ist halt über die ProcessID.

Dann zum Beispiel sowas machen
Code:
SendMessage(GetDlgItem(dasHandle, dieControlID), WM_SETTEXT, 0, Integer(PChar('neuer Text')));
Um text zu ändern.

Ykcim 3. Mär 2021 12:07

AW: ClassName von Edit
 
Liste der Anhänge anzeigen (Anzahl: 1)
Am Ende ist das mein Problem: Der ClassName ändert sich...

Ich hatte folgendes probiert, aber damit komme ich nicht weiter:

Delphi-Quellcode:
   fwnd := FindWindow(nil, 'WmD_VersandLabel');
   GetClassName(fWND, CName, 256);

   wnd := FindWindowEx(wnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, 'Empfänger');

   for I := 0 to 50 do begin
      wnd_edit:= GetDlgItem(wnd, I);
   end;
Ich wollte einfach mal sehen, welche ID's er findet - leider immer 0.

Ich habe mal den Tree in den Anhang gestellt, vielleicht gibt das ja Aufschluss...

An die Edits von Empfänger möchte ich ran...

Vielen Dank
Patrick

KodeZwerg 3. Mär 2021 12:30

AW: ClassName von Edit
 
Zitat:

Zitat von Ykcim (Beitrag 1484334)
Delphi-Quellcode:
   fwnd := FindWindow(nil, 'WmD_VersandLabel');
   GetClassName(fWND, CName, 256);

   wnd := FindWindowEx(wnd, 0, CName, nil);

ersetze mal im findwindowex() wnd mit fwnd. Vielleicht hilft es?

Wenn du meinen vorschlag von oben folgst, ist classname oder handle dank GetDlgItem() überflüssig.

KodeZwerg 3. Mär 2021 12:42

AW: ClassName von Edit
 
Zitat:

Zitat von Ykcim (Beitrag 1484334)
Ich wollte einfach mal sehen, welche ID's er findet - leider immer 0.

Dir ist schon bewusst das Control-Ids in die Zehntausende gehen können?
Ein 0 bis 50 durchiterieren bringt da nichts.

Ykcim 3. Mär 2021 13:47

AW: ClassName von Edit
 
Zitat:

Dir ist schon bewusst das Control-Ids in die Zehntausende gehen können?
Ja, aber ich wollte wissen, ob er irgendwann etwas anderes als 0 zurückliefert...

Ich habe es jetzt so versucht:
Delphi-Quellcode:
 fwnd: THandle;
  wnd: HWND;
  wnd_edit: HWND;
  CName: array [0..255] of Char;
  I: integer;
begin
   fwnd := FindWindow(nil, 'WmD_VersandLabel');
   GetClassName(fWND, CName, 256);

   wnd := FindWindowEx(fwnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, 'Empfänger');

   SendMessage(GetDlgItem(fwnd, 5), WM_SETTEXT, 0, Integer(PChar(Edit_Strasse_E.Text)));
wnd hat dann des Wert von Empfänger (263610)
Dort liegen auf die Felder an die ich möchte. Aber leider ändert sich ja dann der ClassName von WindowsForms10.Window.8.app.0.141b42a_r6_ad1 nach WindowsForms10.EDIT.app.0.141b42a_r6_ad1

Ich habe mal geguckt, was er mit
Delphi-Quellcode:
GetDlgItem(fwnd, 5)
zurückliefert - leider immer nur eine 0.

Irgendwie habe ich es noch nicht geblickt...

DeddyH 3. Mär 2021 14:58

AW: ClassName von Edit
 
Ist das eine .NET-Exe? Die Klassennamen lassen zumindest darauf schließen. Ich bin da kein Experte, aber bist Du sicher, dass sich das Ding einfach so fernsteuern lässt?

Ykcim 3. Mär 2021 16:38

AW: ClassName von Edit
 
Zitat:

Ist das eine .NET-Exe? Die Klassennamen lassen zumindest darauf schließen. Ich bin da kein Experte, aber bist Du sicher, dass sich das Ding einfach so fernsteuern lässt?
Mit diesem Code funktioniert das wunderbar:

Delphi-Quellcode:
procedure TTMSForm2.AdvGlowButton1Click(Sender: TObject);
var
  wnd: HWND;
  wnd_edit: HWND;
begin
   wnd := FindWindow('WindowsForms10.Window.8.app.0.141b42a_r6_ad1', 'AndereAppName');
   wnd := FindWindowEx(wnd, 0, 'WindowsForms10.Window.8.app.0.141b42a_r6_ad1', nil);
   wnd := FindWindowEx(wnd, 0, 'WindowsForms10.Window.8.app.0.141b42a_r6_ad1', nil);
   wnd := FindWindowEx(wnd, 0, 'WindowsForms10.Window.8.app.0.141b42a_r6_ad1', 'Absender');

   wnd_edit := FindControlByNumber(wnd, 'WindowsForms10.EDIT.app.0.141b42a_r6_ad1', 1);    //HNr
   if wnd_edit<>0 then SendMessage(wnd_edit,WM_SETTEXT,0,Integer(Pchar(Edit_HNr_A.Text)));

   wnd_edit := FindControlByNumber(wnd, 'WindowsForms10.EDIT.app.0.141b42a_r6_ad1', 2);    //Land
   if wnd_edit<>0 then SendMessage(wnd_edit,WM_SETTEXT,0,Integer(Pchar(Edit_Land_A.Text)));
Das einzige Problem ist, dass es nur auf der Entwicklungsmaschine läuft, aber auf anderen nicht. Das liegt daran, dass sich der ClassName (WindowsForms10.EDIT.app.0.141b42a_r6_ad1) von Maschine zu Maschine ändern kann.

Deshalb bin ich jetzt auf der Suche, den ClassName zu identifizieren und als Variable zu verwenden.

Das kann ich erreichen, wenn ich folgenden Code ausführe:
Delphi-Quellcode:
var
  fwnd: THandle;
  wnd: HWND;
  wnd_edit: HWND;
  CName: array [0..255] of Char;
begin
   fwnd := FindWindow(nil, 'AndereAppName');
   GetClassName(fWND, CName, 256);

   wnd := FindWindowEx(fwnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, 'Empfänger');
Aber die Schwierigkeit besteht darin, dass sich der ClassName nach dem Element "Empfänger" ändert. Dann wird aus
WindowsForms10.Window.8.app.0.141b42a_r6_ad1 für die App
ein WindowsForms10.EDIT.app.0.141b42a_r6_ad1 für ein Edit-Feld oder
ein WindowsForms10.BUTTON.app.0.141b42a_r6_ad1 für ein Button.

Und damit verstehe ich nicht umzugehen. Ich kann die Edits nur über die Reihenfolge ermitteln, da sie kein Caption haben...

Delphi-Quellcode:
function TTMSForm2.FindControlByNumber(hApp: HWND; ClassName: string; ControlNr: Word = 1): HWND;
var
  i: Word;
  hControl: HWND;
begin
  Result := 0;
  if IsWindow(hApp) then
  begin
    Dec(ControlNr);
    hControl := 0;
    for i := 0 to ControlNr do
    begin
      hControl := FindWindowEx(hApp, hControl, PChar(ClassName), nil);
      if hControl = 0 then
        Exit;
    end;
  end;
  Result := hControl;
end;
Aber den ClassName bekomme ich irgendwie nicht zusammengebaut. Entweder händisch zusammenfrickeln, was ich nicht gerne möchte, oder ich brauche eine Möglichkeit, eine Function wie FindControlByNumber ohne den ClassName zu bauen.

Macht das mein Problem verständlich?

Gruß
Patrick

himitsu 3. Mär 2021 16:49

AW: ClassName von Edit
 
Diese ID scheint ja bei allen Controls gleich zu sein.
Dann brauchst doch nur einmal nach irgendeinem Control zu suchen, also mit FindWindowEx ohne ClassName über alle Controls einer Form laufen und über GetClassName den Namen auslesen, bis was Passendes gefunden wurde.
Da dann die ID extrahieren und, für alle deine weiteren Zugriffe, an deine ClassName's anhängen.


Und ja, das sind die generierten Namen der .NET Winforms (C# oder VB.NET)
Bei Google suchenWindowsForms10 classname bzw. Bei Google suchenWindowsForms10 classname ... viel Spaß

Es gibt aber auch genügend Test-Frameworks, welche damit zurecht kommen und die man bestimmt auch zum Steuern nutzen könnte.

KodeZwerg 3. Mär 2021 18:46

AW: ClassName von Edit
 
Ist das Ziel Programm öffentlich?
Wenn ja, teil doch mal Link dahin.

Ykcim 4. Mär 2021 07:27

AW: ClassName von Edit
 
Guten Morgen Zusammen,

@himitsu: ich werde später mal gucken, ob ist so weiterkomme. Ich komme zwar zu dem Parent-Fenster, muss jetzt noch gucken, wie ich die darauf befindlichen auslesen kann...

@KodeZwerg: Leider ist das kein öffentlichen Programm, daher kann ich es nicht teilen.

Ich werde später berichten

Einen guten Tag
Patrick

Ykcim 4. Mär 2021 09:20

AW: ClassName von Edit
 
Wie kann ich die Childs eines Handels abrufen?
Delphi-Quellcode:
GetNextWindow(hWnd, GW_HWNDNEXT)
bringt mich leider nicht weiter?

DeddyH 4. Mär 2021 10:50

AW: ClassName von Edit
 
Versuch mal MSDN-Library durchsuchenEnumChildWindows

himitsu 4. Mär 2021 11:01

AW: ClassName von Edit
 
FindWindowEx GetNextWindow EnumChildWindows ... das liefert alles (auch) die Childs und Find/Get kann man mehrmals aufrufen (mit passenden Parametern) und bekommt so, wie auch beim Enum "alle" Childs.

venice2 4. Mär 2021 12:00

AW: ClassName von Edit
 
Ich mache es dir einfach.

Ykcim 5. Mär 2021 22:03

AW: ClassName von Edit
 
Ullala, dass ich noch nicht mein Thema!

Erst einmal vielen Dank und auch für das Beispiel! Das habe ich wirklich gebraucht... :oops:

Ich habe jetzt die ersten Aktionen hinbekommen und sie laufen auch auf einem anderen Rechner...

Ich habe es jetzt erst einmal so gelöst - mit Sicherheit noch nicht der Weisheit letzter Schluss...

Delphi-Quellcode:
function EnumChildProc(AHandle: THandle; Rows: TRows): BOOL; stdcall;
var
   buffer: array[0..255] of Char;
   caption: array[0..255] of Char;
   I: integer;
begin
   while (Rows[0,I]<>'') or (I=Length(Rows[0]) -0) do begin
      INC(I);
   end;
   Result := True;
   GetClassName(AHandle, buffer, SizeOf(buffer)-1);
   SendMessage(AHandle, WM_GETTEXT, 256, Integer(@caption));
   Rows[0,I] := IntToStr(AHandle);
   Rows[1,I] := string(buffer);
   Rows[2,I] := Caption;
end;
Delphi-Quellcode:
procedure TTMSForm2.Write_Empfaenger(Rows: TRows);
var  wnd_temp: HWND;
      I: integer;
begin
   for I := 0 to Length(Rows[0]) -1 do begin
      wnd_temp:=StrToInt(Rows[0,I]);
      case I of
      0: SendMessage(wnd_temp,WM_SETTEXT,0,Integer(Pchar(Edit_HNr_E.Text)));    //HNr.
    //1:                                                                        //           TButton
      2: SendMessage(wnd_temp,WM_SETTEXT,0,Integer(Pchar(Edit_Land_E.Text)));   //Land
      3: SendMessage(wnd_temp,WM_SETTEXT,0,Integer(Pchar(Edit_Ort_E.Text)));    //Ort
      4: SendMessage(wnd_temp,WM_SETTEXT,0,Integer(Pchar(Edit_PLZ_E.Text)));    //PLZ
      5: SendMessage(wnd_temp,WM_SETTEXT,0,Integer(Pchar(Edit_Strasse_E.Text))); //Strasse
      6: SendMessage(wnd_temp,WM_SETTEXT,0,Integer(Pchar(Edit_Name_E.Text)));   //Nachname
      7: SendMessage(wnd_temp,WM_SETTEXT,0,Integer(Pchar(Edit_Firma_E.Text)));  //Firma
      8: SendMessage(wnd_temp,WM_SETTEXT,0,Integer(Pchar(Edit_Vorname_E.Text))); //Vorname
      end;
   end;
end;
Delphi-Quellcode:
procedure TTMSForm2.AdvGlowButton2Click(Sender: TObject);
var
  fwnd: THandle;
  wnd: HWND;
  CName: array [0..255] of Char;
  Rows: TRows;
begin

   fwnd := FindWindow(nil, 'AndereApp');
   GetClassName(fWND, CName, 256);
   wnd := FindWindowEx(fwnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, nil);
   wnd := FindWindowEx(wnd, 0, CName, 'Empfänger');
   SetLength(Rows,3,9);
   EnumChildWindows(wnd, @EnumChildProc, Integer(Rows));

   Write_Empfaenger(Rows);
end;
Ich guck mal, wie weit ich jetzt komme. Muss noch Menü's, ComboBoxen und Tabellen abgreifen.

Vielen Dank!!!

Patrick


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

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