Re: Zugriff auf ein TImage einer externen Anwendung
Hallo,
Zitat:
Delphi-Quellcode:
Was mir jetzt mal sagt das eigentlich nur die "Hauptklassen" angezeigt nicht jedoch die Komponenten auf dem Form.
TApplication
THintWindow TForm1 Wenn ich jedoch direkt folgendes mache:
Delphi-Quellcode:
Erhalte ich nur die Komponenten von dem Fenster:
for i:=0 to Form1.componentcount-1 do begin
memo1.lines.add(Form1.component[i].classname); //Und wenn classname TImage ist, dann noch die Abmaße aufschreiben end;
Delphi-Quellcode:
Hab ich irgendwas vergessen oder warum funktioniert das nicht so wie es soll?
TImage
TImage TMemo TButton |
Re: Zugriff auf ein TImage einer externen Anwendung
Hmm, rätselhaft. vorhin ging es so bei mir jetzt hatte ich dasselbe Ergebnis und muss die eine Zeile ändern:
Delphi-Quellcode:
Aus der 35 ist eine 9 geworden. das ist halt meine Referenz. Ich hab leider den Code von heut mittag verworfen. Da kann ich leider nicht überprüfen warum das vorhin eine 35 war. Der Schlüssel liegt in der Funktion MakeObjectInstance der Unit Classes, aber da hab ich jetzt grad keine Lust mich weiter reinzuarbeiten. Vielleicht klappt die 9 ja ab jetzt :| .
p:=pointer(getwindowlong(myhandle,gwl_wndproc)+9);
Man könnte natürlich auch Tform1 nehmen und dann weiter suchen. aber das ist nicht gerade sinnvoll. |
Re: Zugriff auf ein TImage einer externen Anwendung
Ahhhja ... mit der 9 sieht das ganze doch gleich viel besser aus! Vielen Dank!
Jetzt hab ich aber doch noch 2 Fragen, zum einen - wird es doch auch bestimmt möglich sein den Namen es TImages neben dem Handle ausfindig zu machen? Damit ich dann besser die TImages unterscheiden kann und wie du beim "s='TImage'" eine if-Abfrage machen kann. Zum anderen, wenn ich den ganzen Code mit
Delphi-Quellcode:
mache, bekomm ich eine Zugriffsverletzung, sobald ein anderes Programm im Vordergrund ist, also eben jenes was ich "auslesen" möchte.
myhandle:=getforegroundwindow;
Realisiert mit einem Timer der alle 5 Sec. die Button Prozedur ausführt. Funktioniert aber auf dem eigenen Form. Dazu noch eine Idee? Die ganze WinAPI geschichte was du hier bisher aufgebracht hast ist für mich noch ein buch mit 7 Siegeln. ;-) |
Re: Zugriff auf ein TImage einer externen Anwendung
Ich hab diesen code, von dem größtenteils Bahnhof verstehe :lol: , mal etwas umgeschrieben, sodass er den namen der komponente anzeigt. Allerdings funktioniert das nur bei formularen in der eigenen anwendung, bei formularen aus anderen delphi anwendungen streikt er, und zwar bei
Delphi-Quellcode:
Ich habe mal gehört, dass die VCL von zwei Anwendungen nicht miteinander kompatibel ist. Liegt das daran?
p:=p^;
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var pi,p,pm:ppointer; s:string; c:pchar; i,a:integer; obj: tPersistent; myhandle: hwnd; begin memo1.clear; myhandle:=...; //myhandle ist das einzige, was ich benötige p:=pointer(getwindowlong(myhandle,gwl_wndproc)+9); pm:=p; p:=p^; p:=pointer(integer(p^)-44); p:=p^; c:=pchar(p); s:=''; inc(c); for i:=1 to pbyte(p)^ do begin s:=s+c^; inc(c); end; memo1.lines.Add(s); //classname des Windows pm:=pointer(integer(pm^)+16); for a:=0 to pinteger(integer(pm^)+8)^-1 do begin //von 0 bis componentcount p:=pointer(integer(pm^)+4); p:=pointer(integer(p^)+4*a); pi:=p; //pi^ ist Zeiger auf ein Objekt obj := TPersistent(pi^); memo1.lines.add(obj.GetNamePath); end; end; |
Re: Zugriff auf ein TImage einer externen Anwendung
@namenlozer
In dem Fall kannst du noch viel früher ansetzen. Bei der Adresse der WndProc-funktion (+9 Bytes dahinter) steht die Adresse eines TWinControls. Nämlich genau das, welches die Messages bekommt. Demnach könnte man ab hier mit VCL-Komponenten arbeiten:
Delphi-Quellcode:
Aber das war nicht sinn der Sache. Ich wollte ja komplett ohne VCL und nur mit Adressen/Pointern auskommen, weil (und jetzt kommt der Knackpunkt) man damit (hoffentlich :mrgreen: ) auch in fremden Prozessen recht einfach lesen kann. Ihr habt ja beide schon bemerkt, dass der Code nur im eigenen Programm/Prozess funktioniert. Das ist auch gut so. Denn schließlich ist die CPU im Protected Mode und Windows ein sicheres Betriebsystem :party: , wo man nicht einfach in fremden Adressbereichen lesen und schreiben kann/darf. Das wäre ja zu schön, da könnte ja jeder Trojaner einfach so eueren Programmspeicher (inkl. Passwörter) auslesen. :dancer2:
p:=pointer(getwindowlong(myhandle,gwl_wndproc)+9);
obj:=Twincontrol(p^); memo1.Lines.add(obj.Name); //.. und dann weiter über obj.componentcount bzw. obj.component[0..obj.componentcount] Ok, soviel Witz am Rande, kommen wir zurück zur Realität (ihr wisst anscheinend noch nicht, was virtueller Adressraum bedeutet -->unbedingt mal bei Wiki oder so reinlesen). Und die Realität kennt Windows und Windows kenn: -openprocess -readprocessmemory -writeprocessmemory So, und damit können wir in einem fremden Prozess auch mitlesen,... irgendwie. Ich schau mal. Ansonsten, was ich da oben bisher gemacht habe, sieht nur kompliziert aus, ist aber nur ein wenig Adressrechnung. Ich springe immer von einer Adresse zur nächsten und rechne zwischendruch konstante Werte dazu (entsprechend wie die VCL aufgebaut ist). Als Startadresse nehme ich mir die WndProc-Funktion, die ich ja recht einfach aus dem Window-Handle bekomme (getwindowlong). |
Re: Zugriff auf ein TImage einer externen Anwendung
Ok, bei mir getestet und es funktioniert:
Delphi-Quellcode:
Man kann auch nach ClassName suchen (dann ist mem.count notwendig, da es ja mehrere TImages geben kann):
unit U_getImage;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; const mymsg=WM_User+1; type TSearchtype=(sClassName,sName); type PMemory=^TMemory; TMemory=packed record Thread:array[0..1023] of char; Postmessage:function(wnd:hwnd;msg,wparam,lparam:cardinal):bool;stdcall; exitthread:procedure(exitcode:integer);stdcall; getwindowlong:function(wnd:hwnd;index:integer):cardinal;stdcall; watchwnd:hwnd; backwnd:hwnd; backmsg:integer; count:integer; SearchType:TSearchtype; vgl:array[0..31] of char; //kann noch verlängert werden vgllength:integer; end; type TForm1 = class(TForm) Memo1: TMemo; Button1: TButton; Button2: TButton; procedure Button2Click(Sender: TObject); procedure Button1Click(Sender: TObject); procedure GetMyMsg(var msg:TMessage);message mymsg; private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} function injectThread(memory:Pmemory):integer; stdcall; {Diese Funktion landet nachher in einem fremden Process. Deswegen dürfen hier keine Funktionen von Delphi benutzt werden (inkl. Stringoperationen, VCL, etc.).} var pi,p,pm:ppointer; i,a:integer; c:pchar; left,top,width,height:smallint; same:boolean; wparam,lparam:cardinal; begin lefT:=0; top:=0; width:=0; height:=0; p:=pointer(memory^.getwindowlong(memory^.watchwnd,gwl_wndproc)+9); //Ab hier wie gehabt, nur die Stringoperationen verändert //und die Variante sName eingefügt pm:=pointer(integer(p^)+16); for a:=0 to pinteger(integer(pm^)+8)^-1 do begin //von 0 bis componentcount p:=pointer(integer(pm^)+4); p:=pointer(integer(p^)+4*a); pi:=p; //pi^ ist Zeiger auf ein Objekt if memory^.SearchType=sClassname then begin p:=p^; p:=pointer(integer(p^)-44); end else p:=pointer(integer(p^)+8); p:=p^; c:=pchar(p); if (pbyte(p)^=memory^.vgllength)or(memory^.SearchType=sName) then begin if memory^.SearchType=sClassName then inc(c); same:=false; for i:=1 to memory^.vgllength do begin if memory^.vgl[i-1]<>c^ then break; same:=i=memory^.vgllength; inc(c); end; if same then begin dec(memory^.count); if (memory^.count=0)or(memory^.SearchType=sName) then begin left:=(pinteger(integer(pi^)+$40)^); top:=(pinteger(integer(pi^)+$44)^); width:=pinteger(integer(pi^)+$48)^; height:=pinteger(integer(pi^)+$4C)^; break; end; end; end; end; //4 Zahlen in 2*32Bit kopieren wparam:=left*65536+top; lparam:=width*65536+height; //Ergebnis Nach Hause senden memory^.Postmessage(memory^.backwnd,memory^.backmsg,wparam,lparam); result:=0; //Thread beenden memory^.exitthread(0); end; procedure endpoint; //ohne Funktion nur zum finden des Address-endes von injcetThread asm nop end; procedure TForm1.Button2Click(Sender: TObject); begin close; end; procedure TForm1.Button1Click(Sender: TObject); var myhandle:hwnd; mem:TMemory; lib:THandle; size:integer; process:cardinal; processid:cardinal; procmem:PMemory; tmp:cardinal; threadID:cardinal; thread:THandle; begin memo1.clear; myhandle:=findwindow(nil,'PImage'); //Beispielprogramm finden //mem ist der Record der nachher in den anderen Process kopiert wird mem.backwnd:=self.Handle; //Handle, damit wir Nachrichten zurückschicken können mem.backmsg:=mymsg; //Message-Nr., damit wir unsere Message wiederfinden mem.watchwnd:=myhandle; //Das Handle für getwindowlong //mem.count:=1; //welches TImage (=mem.vgl)? (nur für Searchtype=sClassName) mem.vgl:='Image3'; //der Vergleichsstring mem.vgllength:=6; //Länge des Vergleichsstrings mem.SearchType:=sName; //vgl vergleichen mit Classname oder Name //kopieren der funktion injectthread in den Record size:=integer(@endpoint)-integer(@injectThread); move(injectthread,mem.thread,size); //EinsprungAdresse von 3 WinAPI-funktionen, die nacher benötigt werden //Die Adressen sind in jedem Process gleich lib:=getmodulehandle('user32.dll'); mem.Postmessage:=getprocaddress(lib,'PostMessageA'); mem.getwindowlong:=getprocaddress(lib,'GetWindowLongA'); lib:=getmodulehandle('kernel32.dll'); mem.exitthread:=getprocaddress(lib,'ExitThread'); //Thread-Record in anderen Process kopieren und mem.Thread starten getwindowthreadprocessid(myhandle,@processid); process:=openprocess(PROCESS_ALL_ACCESS,false,processid); //Speicher reservieren procmem:=virtualallocex(process,nil,sizeof(Tmemory),MEM_COMMIT,PAGE_EXECUTE_READWRITE); //Kopieren writeprocessmemory(process,procmem,@mem,sizeof(TMemory),tmp); //Starten thread:=createremotethread(process,nil,0,@procmem.thread,procmem,0,threadid); //Warten bis injectthread beendet ist waitforsingleobject(thread,infinite); //Speicher wieder freigeben closehandle(thread); virtualfreeex(process,procmem,0,mem_decommit); closehandle(process); end; procedure TForm1.GetMyMsg(var msg:TMessage); begin memo1.Lines.add(inttostr(msg.WParamlo)); memo1.Lines.add(inttostr(msg.WParamhi)); memo1.Lines.add(inttostr(msg.lParamlo)); memo1.Lines.add(inttostr(msg.lParamhi)); end; end.
Delphi-Quellcode:
All das funktioniert wie gesagt nur mit Programmen, die mit der VCL programmiert wurden, genauer gesagt, mit der VCL die in Delphi 7 ist (Ich weis ja nicht ob sich an diesen grundlegenden Strukturen bis D2006 etwas geändert hat).
mem.count:=2; //welches TImage (=mem.vgl)? (nur für Searchtype=sClassName)
mem.vgl:='TImage'; //der Vergleichsstring mem.vgllength:=6; //Länge des Vergleichsstrings Und nun noch zum Beispielprogramm: Er sucht jetzt quasi ein Window, dessen Titel PImage ist, das sieht so aus (zweites Programm):
Delphi-Quellcode:
unit U_Image;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Image1: TImage; Image2: TImage; Image3: TImage; Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin close; end; procedure TForm1.FormCreate(Sender: TObject); begin self.caption:='PImage'; end; end. PS: Eigentlich sollte man noch Sicherheiten einbauen. An der Stelle wo der Thread-Record in den anderen Process kopiert und gestartet wird, kann man an den Ergebnissen der funktionen sehen, ob es überhaupt geklappt hat. Aber das überlasse ich dem geneigten Leser :mrgreen: . Edit: "break" eingefügt. Man muss ja nicht weiter suchen, wenn man schon gefunden hat. |
Re: Zugriff auf ein TImage einer externen Anwendung
Das finden der TImages nach Namen funktioniert soweit richtig super!
Auch das Zeichnen eines Textes mit Canvas in das Form klappt ganz gut. Es gibt aber nach wie vor noch ein anliegen was ich durchs rum probieren noch nicht so richtig hinbekommen habe. Ich habs mit folgendem Versucht:
Delphi-Quellcode:
Bei dem Nutzen des SetSize erhalte ich folgenden Fehler: "Cannot change the size of a JPEG image".
procedure TForm1.Button3Click(Sender: TObject);
var dc:hdc; //Device Context Handle Canvas:Tcanvas; begin dc:=getwindowdc(myhandle); //TCanvas auf den Device Context setzen canvas:=TCanvas.Create; canvas.Handle := dc; Image1.Picture.LoadFromFile('mein_bild.jpg'); Image1.Picture.Graphic.SetSize(ImgWidth,ImgHeight); canvas.Draw(ImgLeft,ImgTop,Image1.Picture.Graphic); canvas.Free; releasedc(myhandle,dc); end; Wenn ich das SetSize vom Image1 raus lasse zeichnet er mir zwar das Bild auf das Ziel-Form, aber in voller Größe. Ich möchte es aber nur entweder in der Größe des eigenen Image1 oder aus den ImgWidth,ImgHeigth Variablen welche dem des ziel TImage entsprechen. Zudem noch eine Frage, wie bekomm ich jetzt noch den Caption-Wert wenn es sich nicht um ein TImage sonder um ein TLable handelt? Vielen Dank! |
Re: Zugriff auf ein TImage einer externen Anwendung
Also bei D7 gibt es kein TGraphic.SetSize. Das muss irgendwie neu sein. Da kann ich dir auch nicht weiterhelfen (außer wenn ich zu Hause mal mei TurboDelphi anschmeiße, aber da hab ich wahrscheinlich keine Zeit). Wahrscheinlich musst du irgendwie das jpg in ein Bitmap umwandeln. Dazu gibts TJPEGImage und die Methode DIBneeded. Musst du mal irgendwie damit probieren.
Zitat:
|
Re: Zugriff auf ein TImage einer externen Anwendung
Zitat:
Soweit ich das sehe ist das SetSize nur ne Funktion die die beiden Zeilen in 1 zusammenfasst. Zitat:
Edit: Mit hilfe deines TJPEGImage.DIBNeeded bin ich auf ein Thread gestoßen der folgendes Resultat hat:
Delphi-Quellcode:
var rect : TRect;
rect.Left := ImgLeft; rect.Top := ImgTop; rect.Right := ImgLeft + ImgWidth; rect.Bottom := ImgTop + ImgHeight; canvas.StretchDraw(rec,Image1.Picture.Graphic); |
Re: Zugriff auf ein TImage einer externen Anwendung
Zitat:
Übrigens: das Canvas wird aber genau wie in deiner eignen Anwendung übermalt, wenn z.B. ein anderes Fenster drüber geschoben wird. Zu dem Label: Ich habe es gefunden. Aber hier bin ich mir am wenigsten sicher, dass der Code generell so eingesetzt werden kann. Bei mir klappts erstmal:
Delphi-Quellcode:
Ich hab die injectThread angepasst um die Caption zu finden. Und es ist die GetmyCaption dazugekommen um die neue Message zu verarbeiten. In die Erste konnte ich es nicht mehr reinpacken.
unit U_getImage;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; const mymsg=WM_User+1; type TSearchtype=(sClassName,sName,sCaption); type PMemory=^TMemory; TMemory=packed record Thread:array[0..1023] of char; Postmessage:function(wnd:hwnd;msg,wparam,lparam:cardinal):bool;stdcall; exitthread:procedure(exitcode:integer);stdcall; getwindowlong:function(wnd:hwnd;index:integer):cardinal;stdcall; watchwnd:hwnd; backwnd:hwnd; backmsg:integer; count:integer; SearchType:TSearchtype; vgl:array[0..31] of char; vgllength:integer; end; type TForm1 = class(TForm) Image1: TImage; Memo1: TMemo; Button1: TButton; Button2: TButton; Button3: TButton; Label1: TLabel; procedure Button2Click(Sender: TObject); procedure Button1Click(Sender: TObject); procedure GetMyMsg(var msg:TMessage);message mymsg; procedure GetMyCaption(var msg:TMessage);message mymsg+1; procedure Button3Click(Sender: TObject); private { Private-Deklarationen } myhandle:hwnd; public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} function injectThread(memory:Pmemory):integer; stdcall; {Diese Funktion landet nachher in einem fremden Process. Deswegen dürfen hier keine Funktionen von Delphi benutzt werden (inkl. Stringoperationen, VCL, etc.).} var pi,p,pm:ppointer; i,a:integer; c:pchar; left,top,width,height:smallint; same:boolean; wparam,lparam:cardinal; begin wparam:=0; lparam:=0; p:=pointer(memory^.getwindowlong(memory^.watchwnd,gwl_wndproc)+9); pm:=pointer(integer(p^)+16); for a:=0 to pinteger(integer(pm^)+8)^-1 do begin //von 0 bis componentcount p:=pointer(integer(pm^)+4); p:=pointer(integer(p^)+4*a); pi:=p; //pi^ ist Zeiger auf ein Objekt if memory^.SearchType=sClassname then begin p:=p^; p:=pointer(integer(p^)-44); end else p:=pointer(integer(p^)+8); p:=p^; c:=pchar(p); if (pbyte(p)^=memory^.vgllength)or(memory^.SearchType in[sName,sCaption]) then begin if memory^.SearchType=sClassName then inc(c); same:=false; for i:=1 to memory^.vgllength do begin if memory^.vgl[i-1]<>c^ then break; same:=i=memory^.vgllength; inc(c); end; if same then begin dec(memory^.count); if (memory^.count=0)or(memory^.SearchType in [sName,sCaption]) then begin if memory^.SearchType=sCaption then begin p:=pointer(integer(pi^)+$64); wparam:=cardinal(p^); c:=pchar(p^); while c^<>#0 do begin inc(c); inc(lparam); end; inc(memory^.backmsg); end else begin left:=pinteger(integer(pi^)+$40)^; top:=pinteger(integer(pi^)+$44)^; width:=pinteger(integer(pi^)+$48)^; height:=pinteger(integer(pi^)+$4C)^; //4 Zahlen in 2*32Bit kopieren wparam:=left*65536+top; lparam:=width*65536+height; end; break; end; end; end; end; //Ergebnis Nach Hause senden memory^.Postmessage(memory^.backwnd,memory^.backmsg,wparam,lparam); result:=0; //Thread beenden memory^.exitthread(0); end; procedure endpoint; //ohne Funktion nur zum finden des Address-endes von injcetThread asm nop end; procedure TForm1.Button2Click(Sender: TObject); begin close; end; procedure TForm1.Button1Click(Sender: TObject); var mem:TMemory; lib:THandle; size:integer; process:cardinal; processid:cardinal; procmem:PMemory; tmp:cardinal; threadID:cardinal; thread:THandle; begin memo1.clear; myhandle:=findwindow(nil,'PImage'); //Beispielprogramm finden if myhandle=0 then exit; //mem ist der Record der nachher in den anderen Process kopiert wird mem.backwnd:=self.Handle; //Handle, damit wir Nachrichten zurückschicken können mem.backmsg:=mymsg; //Message-Nr., damit wir unsere Message wiederfinden mem.watchwnd:=myhandle; //Das Handle für getwindowlong mem.count:=6; //welches TControl (=mem.vgl)? (nur für Searchtype=sClassName) mem.vgl:='Label2'; //der Vergleichsstring mem.vgllength:=6; //Länge des Vergleichsstrings mem.SearchType:=sCaption; //vgl vergleichen mit Classname oder Name oder Caption zurücksenden //kopieren der funktion injectthread in den Record size:=integer(@endpoint)-integer(@injectThread); move(injectthread,mem.thread,size); //EinsprungAdresse von 3 WinAPI-funktionen, die nacher benötigt werden //Die Adressen sind in jedem Process gleich lib:=getmodulehandle('user32.dll'); mem.Postmessage:=getprocaddress(lib,'PostMessageA'); mem.getwindowlong:=getprocaddress(lib,'GetWindowLongA'); lib:=getmodulehandle('kernel32.dll'); mem.exitthread:=getprocaddress(lib,'ExitThread'); //Thread-Record in anderen Process kopieren und mem.Thread starten getwindowthreadprocessid(myhandle,@processid); process:=openprocess(PROCESS_ALL_ACCESS,false,processid); //Speicher reservieren procmem:=virtualallocex(process,nil,sizeof(Tmemory),MEM_COMMIT,PAGE_EXECUTE_READWRITE); //Kopieren writeprocessmemory(process,procmem,@mem,sizeof(TMemory),tmp); //Starten thread:=createremotethread(process,nil,0,@procmem.thread,procmem,0,threadid); //Warten bis injectthread beendet ist waitforsingleobject(thread,infinite); //Speicher wieder freigeben closehandle(thread); virtualfreeex(process,procmem,0,mem_decommit); closehandle(process); end; procedure TForm1.GetMyMsg(var msg:TMessage); begin memo1.Lines.add(inttostr(msg.WParamlo)); memo1.Lines.add(inttostr(msg.WParamhi)); memo1.Lines.add(inttostr(msg.lParamlo)); memo1.Lines.add(inttostr(msg.lParamhi)); end; procedure TForm1.GetMyCaption(var msg:TMessage); var process,processID,tmp:cardinal; s:string; begin if myhandle=0 then exit; //in msg.wparam steht der Pointer auf das TLabel.caption im anderen Process //in msg.lparam die Länge des TCaption getwindowthreadprocessid(myhandle,@processid); process:=openprocess(PROCESS_VM_READ,false,processid); setlength(s,msg.LParam); readprocessmemory(process,pointer(msg.wparam),@s[1],msg.lparam,tmp); closehandle(process); memo1.Lines.add(s); end; end. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:21 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