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. |
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
|
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; |
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... |
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
Zitat:
|
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. |
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Wäre es nicht irgendwie möglich geziehlt das Control zu bekommen, welches gerade den Focus hat?
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
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; |
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:
Klassen wo es nicht funzt:
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; "_WwG" (Word XP) "TEditControl" (Delphi2005, Code) "Internet Exploerer_Server" (IE) |
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
Da diese Controls die WM_GETTEXT nicht verarbeiten. |
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
@toms: Das war mir schon klar... nur wie komme ich nun an den Text dieser Controls?
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Schaue mal im SDC. Dort hat's Beispiele dafuer.
|
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; |
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; |
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
@Toms: Du meinst SwissDelphiCenter ? ;) ... die Abkürzung war mir jetzt nicht geläufig :oops:
Zitat:
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/ |
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
|
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.
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Hat wirklich keiner eine Idee, wie man nun an die Texte kommt und diese ersetzen kann? :gruebel:
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Zitat:
|
Re: Text in Eingabefeld beliebiger Anwendungen ersetzen?
Hat vielleicht jemand einen verwertbaren Tipp, wie ich eventuell weiterkommen könnte?
|
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.
|
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... |
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