Einzelnen Beitrag anzeigen

Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#16

Re: Zugriff auf ein TImage einer externen Anwendung

  Alt 20. Feb 2007, 10:42
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 .

Edit: "break" eingefügt. Man muss ja nicht weiter suchen, wenn man schon gefunden hat.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat