Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Text in Eingabefeld beliebiger Anwendungen ersetzen? (https://www.delphipraxis.net/39922-text-eingabefeld-beliebiger-anwendungen-ersetzen.html)

FriFra 9. Feb 2005 08:21


Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Wie stelle ich es am besten an in aktiven Eingabefeldern beliebiger Anwendungen nach einem bestimmten Text zu suchen und diesen automatisch zu ersetzen?

Im Prinzip soll das ganze in jedem Mailprogramm, in Word, im Notepad im IE u.s.w. funktionieren...


Beispiel:
Der User öffner sein Mail, wo automatisch die Signatur "###Hierhin###" eingefügt wird. Nun ersetzt mein Programm "###Hierhin###" durch einen anderen Text.

toms 9. Feb 2005 08:29

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Stichworte: Hier im Forum suchenEnumChildWindows Hier im Forum suchenWM_GETTEXT, Hier im Forum suchenWM_SETTEXT

Sprint 10. Feb 2005 04:44

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Dieses kleine Beispiel ermittelt mit Hilfe von EnumWindows alle TopLevel Fenster. Sollte das Fenster den Klassennamen "Notepad" haben, wird das Kindfenster "Edit" gesucht. Wurde es gefunden, wird es in die TList "List" eingetragen. Mit WM_GETTEXT wird dann der Inhalt von Notepad ausgelesen. StringReplace tauscht dann "###Hierhin###" durch "Neuer Text" aus. Und WM_SETTEXT sorgt dafür, das der bearbeitete Text wieder ins Notepad Fenster gelangt. Ich denke mal, als kleiner Einstieg reicht das und wird dir bestimmt weiterhelfen.

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);

  function EnumWindowsProc(Wnd: HWND; lParam: LPARAM): BOOL; stdcall;
  var
    ClassName: String;
    EditHWnd: HWND;
  begin

    SetLength(ClassName, 512);
    SetLength(ClassName, GetClassName(Wnd, PChar(ClassName), Length(ClassName)));
    if ClassName = 'Notepad' then
    begin
      EditHWnd := FindWindowEx(Wnd, 0, 'Edit', nil);
      if IsWindow(EditHWnd) then
        TList(lParam).Add(Pointer(EditHWnd));
    end;
    Result := True;

  end;

var
  List: TList;
  I: Integer;
  S: String;
begin

  List := TList.Create;
  try
    EnumWindows(@EnumWindowsProc, LPARAM(List));
    for I := 0 to List.Count - 1 do
    begin
      SetLength(S, SendMessage(HWND(List.Items[I]), WM_GETTEXTLENGTH, 0, 0) + 1);
      if Length(S) > 1 then
      begin
        SetLength(S, SendMessage(HWND(List.Items[I]), WM_GETTEXT, Length(S), LPARAM(PChar(S))));
        S := StringReplace(S, '###Hierhin###', 'Neuer Text', [rfReplaceAll]);
        SendMessage(HWND(List.Items[I]), WM_SETTEXT, Length(S), LPARAM(PChar(S)));
      end;
    end;
  finally
    List.Free;
  end;

end;

FriFra 11. Feb 2005 00:31

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Danke, das ist natürlich ein Anfang ;) ...
Aber wäre es nicht möglich einfach im gerade aktivem Control (egal welche Anwendung!) nach einem Text zu suchen?
WM_SETTEXT hat auch den unangenehmen Nebeneffekt, dass sich die Cursorposition ändert...

Sprint 11. Feb 2005 00:48

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

Zitat von FriFra
Aber wäre es nicht möglich einfach im gerade aktivem Control (egal welche Anwendung!) nach einem Text zu suchen?

Das Problem ist ja, das sich diese Daten in einem anderen Prozess befinden. Und du kannst erst im Text suchen, wenn sich diese in deinem Adressraum befinden.

Zitat:

WM_SETTEXT hat auch den unangenehmen Nebeneffekt, dass sich die Cursorposition ändert...
Dann lese vorher die Cursorposition aus. Und nach WM_SETTEXT, setzt du den Cursor wieder an die alte Position.

Luckie 11. Feb 2005 01:07

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Eine interessante Idee. Aber du wirst einige Hürden zu überwinden haben. Handelt es sich um ein standard Windows Edit-Controll ist es kein großes Problem, wie der Code von Sprint gezeigt hat. Word und andere Anwendungen benutzen aber selbst gebastelte Controlls. So ist das, wo du bei Word deinen Text eingibst bestimmt kein Edit-Controll. Du hast es also im Prinzip mit unendlich vielen Fensterklassen zu tun. OpenOffice wird wieder eine andere eigenen Fensterklasse benutzen usw.

@Sprint. Wenn du mit WM_GETTWEXT den Fenstertext ausliest und ihn in eine Variable deines Programmes schreibst, dann befindet sich der Text doch in einer Varaibel, die in deinem Prozess liegt. Das zeigt doch dein Quellcode? Deswegen verstehe ich deine aussage nicht so ganz.

Sprint 11. Feb 2005 01:21

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

Zitat von Luckie
Wenn du mit WM_GETTWEXT den Fenstertext ausliest und ihn in eine Variable deines Programmes schreibst, dann befindet sich der Text doch in einer Varaibel, die in deinem Prozess liegt. Das zeigt doch dein Quellcode? Deswegen verstehe ich deine aussage nicht so ganz.

FriFra wollte auf WM_SETTEXT verzichten. Das bedeutet für mich, das er auch auf WM_GETTEXT verzichten will. Darum meine Antwort mit dem Prozess/Adressraum.

FriFra 11. Feb 2005 01:55

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Wäre es nicht irgendwie möglich geziehlt das Control zu bekommen, welches gerade den Focus hat?

Sprint 11. Feb 2005 02:18

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

Zitat von FriFra
Wäre es nicht irgendwie möglich geziehlt das Control zu bekommen, welches gerade den Focus hat?

Doch natürlich. Das ist kein Problem.
Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
var
  AppHWnd: HWND;
  ThreadId: DWORD;
  FocusHWnd: HWND;
begin

  FocusHWnd := GetFocus;
  if not IsWindow(FocusHWnd) then
  begin
    AppHWnd := GetForegroundWindow;
    if AppHWnd <> Self.Handle then
    begin
      ThreadId := GetWindowThreadProcessId(AppHWnd, nil);
      if ThreadId <> 0 then
        if AttachThreadInput(GetCurrentThreadId, ThreadId, True) then
        begin
          FocusHWnd := GetFocus;
          AttachThreadInput(GetCurrentThreadId, ThreadId, False);
        end;
    end;
  end;

  ListBox1.ItemIndex := ListBox1.Items.Add('Das Fensterhandle $' + IntToHex(FocusHWnd, 8) + ' hat den Fokus');

end;

FriFra 11. Feb 2005 08:23

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Also, jetzt klappt es eigentlich schon ganz gut, wenn es ein Edit oder ein Button ist... bei einigen Controls bekomme ich jedoch noch nicht einmal den Klassennamen :?

Ich hab mir jetzt erst einmal eine Funktion gebastelt, die mir onTimer1 den gerade aktiven Klassennamen und den dazu gehörenden Text in eine ListView schreibt:
Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
var
  AppHWnd: HWND;
  ThreadId: DWORD;
  FocusHWnd: HWND;
  ClassName: string;
  S0, S1: string;
begin
  Timer1.Enabled := False;
  FocusHWnd := GetFocus;
  if not IsWindow(FocusHWnd) then
  begin
    AppHWnd := GetForegroundWindow;
    if AppHWnd <> Self.Handle then
    begin
      ThreadId := GetWindowThreadProcessId(AppHWnd, nil);
      if ThreadId <> 0 then
        if AttachThreadInput(GetCurrentThreadId, ThreadId, True) then
        begin
          FocusHWnd := GetFocus;
          AttachThreadInput(GetCurrentThreadId, ThreadId, False);

          SetLength(ClassName, 512);
          SetLength(ClassName, GetClassName(FocusHWnd, PChar(ClassName),
            Length(ClassName)));

          SetLength(S0, SendMessage(FocusHWnd, WM_GETTEXTLENGTH, 0, 0) + 1);
          if Length(S0) > 1 then
          begin
            Application.ProcessMessages;
            SetLength(S0, SendMessage(FocusHWnd, WM_GETTEXT, Length(S0),
              LPARAM(PChar(S0))));
            S1 := StringReplace(S0, '###Hierhin###', 'Neuer Text',
              [rfReplaceAll]);

            if S0 <> S1 then
              SendMessage(FocusHWnd, WM_SETTEXT, Length(S1), LPARAM(PChar(S1)));
          end;
        end;
    end;
  end;

  if (ListView1.Items.Count = 0) or (ListView1.Items[ListView1.Items.Count -
    1].Caption <> IntToStr(FocusHWnd) + '[' + ClassName + ']="' + Trim(S0) + '"')
      then
  begin
    ListView1.Items.BeginUpdate;
    ListView1.Items.Add;
    ListView1.Items[ListView1.Items.Count - 1].Caption := IntToStr(FocusHWnd) +
      '[' + ClassName + ']="' + Trim(S0) + '"';
    ListView1.Items[ListView1.Items.Count - 1].MakeVisible(False);
    ListView1.Items.EndUpdate;
  end;
  Timer1.Enabled := True;
end;
Klassen wo es nicht funzt:
"_WwG" (Word XP)
"TEditControl" (Delphi2005, Code)
"Internet Exploerer_Server" (IE)

toms 11. Feb 2005 08:37

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

"_WwG" (Word XP)
"TEditControl" (Delphi2005, Code)
"Internet Exploerer_Server" (IE)
Dort wird es mit WM_GETTEXT auch nicht funktionieren.
Da diese Controls die WM_GETTEXT nicht verarbeiten.

FriFra 11. Feb 2005 08:40

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
@toms: Das war mir schon klar... nur wie komme ich nun an den Text dieser Controls?

toms 11. Feb 2005 08:41

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Schaue mal im SDC. Dort hat's Beispiele dafuer.

FriFra 11. Feb 2005 09:07

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
@toms: SDC??

Ich hab jetzt mal meinen Code etwas erweitert... jetzt blinken die betreffenden Controls ;) (ausser beim IE, dort blinkt das gesamte Fenster und nicht nur das aktive Control) ... mehr bekomme ich im Moment damit allerdings nicht gebacken
Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
var
  AppHWnd: HWND;
  ThreadId: DWORD;
  FocusHWnd: HWND;
  ClassName: string;
  S0, S1: string;
  Rect: TRect;
  Canvas: TCanvas;
  Loop: integer;
begin
  Timer1.Enabled := False;
  FocusHWnd := GetFocus;
  if not IsWindow(FocusHWnd) then
  begin
    AppHWnd := GetForegroundWindow;
    if AppHWnd <> Self.Handle then
    begin
      ThreadId := GetWindowThreadProcessId(AppHWnd, nil);
      if ThreadId <> 0 then
        if AttachThreadInput(GetCurrentThreadId, ThreadId, True) then
        begin
          FocusHWnd := GetFocus;
          AttachThreadInput(GetCurrentThreadId, ThreadId, False);

          SetLength(ClassName, 512);
          SetLength(ClassName, GetClassName(FocusHWnd, PChar(ClassName),
            Length(ClassName)));

          SetLength(S0, SendMessage(FocusHWnd, WM_GETTEXTLENGTH, 0, 0) + 1);
          if Length(S0) > 1 then
          begin
            Application.ProcessMessages;
            SetLength(S0, SendMessage(FocusHWnd, WM_GETTEXT, Length(S0),
              LPARAM(PChar(S0))));
            S1 := StringReplace(S0, '###Hierhin###', 'Neuer Text',
              [rfReplaceAll]);
            if S0 <> S1 then
              SendMessage(FocusHWnd, WM_SETTEXT, Length(S1), LPARAM(PChar(S1)));
          end
          else
          begin
            //Get editor co-ordinates
            Windows.GetClientRect(FocusHWnd, Rect);
            //Change width/height to be right/bottom
            Rect.BottomRight := Point(Rect.Left + Rect.Right, Rect.Top +
              Rect.Bottom);
            //Turn client-relative co-ordinates into screen-relative co-ordinates
            Windows.ClientToScreen(FocusHWnd, Rect.TopLeft);
            Windows.ClientToScreen(FocusHWnd, Rect.BottomRight);
            //Set up canvas for whole desktop and flash the editor a few times
            Canvas := TCanvas.Create;
            try
              Canvas.Pen.Mode := pmNot;
              Canvas.Pen.Width := 5;
              Canvas.Handle := GetDC(HWnd_Desktop);
              try
                for Loop := 1 to 8 do
                begin
                  Canvas.Polyline([Rect.TopLeft, Point(Rect.Right, Rect.Top),
                    Rect.BottomRight, Point(Rect.Left, Rect.Bottom),
                      Rect.TopLeft]);
                  Sleep(100);
                end
              finally
                ReleaseDC(HWnd_Desktop, Canvas.Handle)
              end;
            finally
              Canvas.Free
            end;
          end;
        end;
    end;
  end;

  if (ListView1.Items.Count = 0) or (ListView1.Items[ListView1.Items.Count -
    1].Caption <> IntToStr(FocusHWnd) + '[' + ClassName + ']="' + Trim(S0) + '"')
      then
  begin
    ListView1.Items.BeginUpdate;
    ListView1.Items.Add;
    ListView1.Items[ListView1.Items.Count - 1].Caption := IntToStr(FocusHWnd) +
      '[' + ClassName + ']="' + Trim(S0) + '"';
    ListView1.Items[ListView1.Items.Count - 1].MakeVisible(False);
    ListView1.Items.EndUpdate;
  end;
  Timer1.Enabled := True;
end;

Sprint 11. Feb 2005 09:08

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Delphi-Quellcode:
procedure TForm1.Timer1Timer(Sender: TObject);
const
  S_SEARCH = '###Hierhin###';
  S_REPLACE = 'Neuer Text';
var
  AppHWnd: HWND;
  ThreadId: DWORD;
  FocusHWnd: HWND;
  ClsName: String;
  WndText: String;
begin

  AppHWnd := GetForegroundWindow;
  if IsWindow(AppHWnd) then
  begin
    if AppHWnd <> Self.Handle then
    begin
      ThreadId := GetWindowThreadProcessId(AppHWnd, nil);
      if ThreadId <> 0 then
        if AttachThreadInput(GetCurrentThreadId, ThreadId, True) then
        begin
          FocusHWnd := GetFocus;
          AttachThreadInput(GetCurrentThreadId, ThreadId, False);
        end;
    end else
      FocusHWnd := GetFocus;
    if IsWindow(FocusHWnd) then
    begin
      SetLength(ClsName, 512);
      SetLength(ClsName, GetClassName(FocusHWnd, PChar(ClsName), Length(ClsName)));
      SetLength(WndText, SendMessage(FocusHWnd, WM_GETTEXTLENGTH, 0, 0) + 1);
      SetLength(WndText, SendMessage(FocusHWnd, WM_GETTEXT, Length(WndText), LPARAM(PChar(WndText))));
      if Pos(S_SEARCH, WndText) > 0 then
      begin
        WndText := StringReplace(WndText, S_SEARCH, S_REPLACE, [rfReplaceAll]);
        SendMessage(FocusHWnd, WM_SETTEXT, Length(WndText), LPARAM(PChar(WndText)));
      end;
      with ListView1.Items.Add do
      begin
        Caption := '[' + ClsName + '] = "' + WndText + '"';
        MakeVisible(False);
      end;
    end;
  end;

end;

Sprint 11. Feb 2005 09:10

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

Zitat von FriFra
@toms: Das war mir schon klar... nur wie komme ich nun an den Text dieser Controls?

In deiner Signatur steht, das du Delphi Professional hast. Dann kannst du für Word die Komponente TWordApplication nehmen.

toms 11. Feb 2005 09:16

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

@toms: SDC??
Bei Google suchensdc delphi

FriFra 11. Feb 2005 09:26

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
@Toms: Du meinst SwissDelphiCenter ? ;) ... die Abkürzung war mir jetzt nicht geläufig :oops:

Zitat:

Zitat von Sprint
In deiner Signatur steht, das du Delphi Professional hast. Dann kannst du für Word die Komponente TWordApplication nehmen.

Das hilft mir nicht weiter. Es soll ja bei JEDEM aktiven Eingabefeld funktionieren :gruebel:
Ich kann nicht für jedes nur denkbare Programm eine eigene Funktion basteln...

Das es geht, sieht man an diesem Programm: http://www.is.tuwien.ac.at/emu/

Sprint 11. Feb 2005 09:36

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

Zitat von FriFra
Das hilft mir nicht weiter. Es soll ja bei JEDEM aktiven Eingabefeld funktionieren
Ich kann nicht für jedes nur denkbare Programm eine eigene Funktion basteln...
Das es geht, sieht man an diesem Programm: [EMU]

Das Programm arbeitet nach einem ganz anderen Prinzip.

FriFra 11. Feb 2005 09:40

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

Zitat von Sprint
Das Programm arbeitet nach einem ganz anderen Prinzip.

Nach welchem denn? Es ist auf jeden Fall in der Lage in beliebigen Textfeldern beliebiger Programme Texte zu erkennen und zu ersetzen - genau das suche ich doch. :roll:

Sprint 11. Feb 2005 09:46

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

Zitat von FriFra
Nach welchem denn? Es ist auf jeden Fall in der Lage in beliebigen Textfeldern beliebiger Programme Texte zu erkennen und zu ersetzen - genau das suche ich doch.

Tastaturhooks & SendKeys-Methode.

FriFra 11. Feb 2005 09:53

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Aber auf jeden Fall ist das Programm in der Lage den Inhalt des aktiven Controls auszulesen, unabhängig von den Tastatureingaben! Wenn man z.B. den cursor nach links ans Ende eines Wortes bewegt, so wird dieses korrekt erkannt, obwohl es NICHT eingetippt wurde... Das Programm liest also den Text des controls in dem sich der Cursor befindet.

Sprint 11. Feb 2005 10:02

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

Zitat von FriFra
Aber auf jeden Fall ist das Programm in der Lage den Inhalt des aktiven Controls auszulesen

Dazu bin ich auch in der Lage. Mach' mir einen vernünftigen Preis und ich programmiere dir so ein Programm. :wink:

FriFra 11. Feb 2005 10:05

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

Zitat von Sprint
Dazu bin ich auch in der Lage. Mach' mir einen vernünftigen Preis und ich programmiere dir so ein Programm. :wink:

Der war gut... nach welchem Prinzip muss man denn dabei vorgehen? Ich will kein Programm programmiert haben, sondern nur den Weg wissen, wie man an die Texte kommt :?

FriFra 13. Feb 2005 11:58

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Hat wirklich keiner eine Idee, wie man nun an die Texte kommt und diese ersetzen kann? :gruebel:

CHB 18. Feb 2005 16:53

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Zitat:

Zitat von FriFra
Hat wirklich keiner eine Idee, wie man nun an die Texte kommt und diese ersetzen kann? :gruebel:

:witch: Ich wüßte da schon jemanden: Wir von fortec (http://www.is.tuwien.ac.at), denn wir haben EMU geschrieben und es ist wirklich nicht so schwer. Kleiner Tip zum Anfangen: Es geht um die Kommunikation mit Fenstern mit Hilfe von Messages. MSAA brauchst du übrigens nicht zu quälen. Geht auch, hat aber mehr Probleme als zu Fuiß mit Messages.....

FriFra 20. Jun 2005 21:18

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Hat vielleicht jemand einen verwertbaren Tipp, wie ich eventuell weiterkommen könnte?

Flocke 20. Jun 2005 21:40

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Versuch mal, dem aktiven Control ein WM_COPY zu schicken, und dann den Inhalt der Zwischenablage auszulesen (etwas unsauber, aber naja ...). Alternativ kannst du dem Control auch die Tastenkombination dafür schicken.

FriFra 20. Jun 2005 22:23

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Das kann ich nicht machen. Das Programm soll permanent im Hintergrund laufen und quasi auf einen bestimmten Text "warten"... wenn ich jetzt jedes mal die Zwischenablage befülle, kann der User diese praktisch nicht mehr verwenden.
Mal ganz davon abgesehen, soll ja z.B. auch der Cursor an der Stelle bleiben, wo er vorhar war...

FriFra 27. Dez 2005 21:54

Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
 
Es ist zwar schon etwas her... Ich hab immernoch keinen verwertbaren Ansatz gefunden :cry: :roll:

Das man irgendwie mit Messages arbeiten muss ist mir schon klar, nur auf WM_GETTEXT, WM_SETTEXT reagieren eben manche Controls nicht :gruebel: ... EMU kann das aber, also mus es einen Weg geben :?


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:39 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