Delphi-PRAXiS
Seite 2 von 12     12 34     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Zugriff auf ein TImage einer externen Anwendung (https://www.delphipraxis.net/86561-zugriff-auf-ein-timage-einer-externen-anwendung.html)

KoS 19. Feb 2007 17:30

Re: Zugriff auf ein TImage einer externen Anwendung
 
Hallo,
Zitat:

Zitat von sirius
Ich hab jetzt keine weiteren Kommentare, da ich nur ein wenig rumgespielt habe. Letztenendes macht es nix andere, als:

Also ich hab das mal eben ausprobiert und bekomme Folgendes Resultat:
Delphi-Quellcode:
TApplication
THintWindow
TForm1
Was mir jetzt mal sagt das eigentlich nur die "Hauptklassen" angezeigt nicht jedoch die Komponenten auf dem Form.

Wenn ich jedoch direkt folgendes mache:
Delphi-Quellcode:
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;
Erhalte ich nur die Komponenten von dem Fenster:
Delphi-Quellcode:
TImage
TImage
TMemo
TButton
Hab ich irgendwas vergessen oder warum funktioniert das nicht so wie es soll?

sirius 19. Feb 2007 19:47

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:
p:=pointer(getwindowlong(myhandle,gwl_wndproc)+9);
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 :| .

Man könnte natürlich auch Tform1 nehmen und dann weiter suchen. aber das ist nicht gerade sinnvoll.

KoS 19. Feb 2007 21:17

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:
myhandle:=getforegroundwindow;
mache, bekomm ich eine Zugriffsverletzung, sobald ein anderes Programm im Vordergrund ist, also eben jenes was ich "auslesen" möchte.
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. ;-)

Namenloser 19. Feb 2007 22:10

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:
  p:=p^;
Ich habe mal gehört, dass die VCL von zwei Anwendungen nicht miteinander kompatibel ist. Liegt das daran?

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;

sirius 20. Feb 2007 07:41

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:
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]
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:
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).

sirius 20. Feb 2007 09:42

Re: Zugriff auf ein TImage einer externen Anwendung
 
Ok, bei mir getestet und es funktioniert:
Delphi-Quellcode:
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.
Man kann auch nach ClassName suchen (dann ist mem.count notwendig, da es ja mehrere TImages geben kann):
Delphi-Quellcode:
  mem.count:=2; //welches TImage (=mem.vgl)? (nur für Searchtype=sClassName)
  mem.vgl:='TImage'; //der Vergleichsstring
  mem.vgllength:=6; //Länge des Vergleichsstrings
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).


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.

KoS 20. Feb 2007 12:43

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:
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;
Bei dem Nutzen des SetSize erhalte ich folgenden Fehler: "Cannot change the size of a JPEG image".
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!

sirius 20. Feb 2007 13:06

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:

Zudem noch eine Frage, wie bekomm ich jetzt noch den Caption-Wert wenn es sich nicht um ein TImage sonder um ein TLable handelt?
Du willst aus dem Programm, wo du Images gesucht hast auch den Inhalt von Labels wissen? Erklär mal genauer!

KoS 20. Feb 2007 14:05

Re: Zugriff auf ein TImage einer externen Anwendung
 
Zitat:

Zitat von sirius
Also bei D7 gibt es kein TGraphic.SetSize.

Ich habs auch mit TGraphic.Height, TGraphic.Width versucht, kommt ebenfalls der Fehler.
Soweit ich das sehe ist das SetSize nur ne Funktion die die beiden Zeilen in 1 zusammenfasst.

Zitat:

Zitat von sirius
Zitat:

Zudem noch eine Frage, wie bekomm ich jetzt noch den Caption-Wert wenn es sich nicht um ein TImage sonder um ein TLable handelt?
Du willst aus dem Programm, wo du Images gesucht hast auch den Inhalt von Labels wissen? Erklär mal genauer!

Ja genau so wie du es gesagt hast. In dem Form wo ich die Images suche gibt es auch Labels dessen Text ich wissen möchte. Ebenfalls Namen bekannt.

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);

sirius 20. Feb 2007 14:26

Re: Zugriff auf ein TImage einer externen Anwendung
 
Zitat:

Mit hilfe deines TJPEGImage.DIBNeeded bin ich auf ein Thread gestoßen der folgendes Resultat hat:
Wenn es funktioniert... Mit dem Canvas kannst du machen, was du auch sonnst in deiner eigenen Anwendung machen kannst.
Ü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:
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.
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.


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:21 Uhr.
Seite 2 von 12     12 34     Letzte »    

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