Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Mittels CodeRedirect Funktionen patchen (https://www.delphipraxis.net/166831-mittels-coderedirect-funktionen-patchen.html)

ConnorMcLeod 1. Mär 2012 18:21

Delphi-Version: 5

Mittels CodeRedirect Funktionen patchen
 
Hallo DPler,
wie es der Zufall will, habe ich ein ähnliches Problem wie Himitsu:

Ich möchte in der Unit <Graphics.pas> die Routine <RequiredState> vom TCanvas ersetzen. Das geht so (und funkt auch - getestet):

Neue Unit, z.B. UMyCanvas.pas, dort:

eine neue Klasse für den Hack, der Zugriff auf das private Feld <State> ermöglicht:

Delphi-Quellcode:
  THackCanvas = class(Graphics.TCanvas)
  private
    FHandle: HDC;
    State : TCanvasState;
  end;
Eine neue Klasse, in der die neue Routine definiert wird:
Delphi-Quellcode:
  TMyCanvas = class(Graphics.TCanvas)
  protected
    procedure RequiredStatePatch(ReqState: TCanvasState);
  end;
...
implementation
...
procedure TMyCanvas.RequiredStatePatch(ReqState: TCanvasState);
var
  NeededState: TCanvasState;
begin
  NeededState := ReqState - THackCanvas(Self).State;
end;
Im initialization-Teil wird dann mittels
Delphi-Quellcode:
CodeRedirect
(von http://chee-yang.blogspot.com/2008/11/hack-into-delphi-class.html) die Adresse der vorhandenen Routine durch die Adresse der neuen Routine ersetzt und die neue Routine wird künftig so verwendet, als ob sie ganz normal zu TCanvas gehören würde:

Delphi-Quellcode:
var
  P: TCodeRedirect;

initialization
  P := TCodeRedirect.Create(@TMyCanvas.RequiredState, @TMyCanvas.RequiredStatePatch);

finalization
  P.Free;
OK.

Das Problem ist: für den Zugriff auf <State> muss ich in
Delphi-Quellcode:
RequiredStatePatch
schreiben:
Delphi-Quellcode:
THackCanvas(Self).State
, damit das Ganze kompiliert; zur Laufzeit aber gilt das nicht mehr, weil sich die Routine - nach dem Umbiegen der Adresse - zu TCanvas zugehörig fühlt und deshalb hier nur
Delphi-Quellcode:
State
stehen dürfte. Irgendwie ein Henne/Ei-Problem.

Wenn zur Laufzeit
Delphi-Quellcode:
THackCanvas(Self).State
abgefragt wird, dann bringt das ein falsches Ergebnis.

War das halbwegs verständlich bzw wer weiss Rat?

Furtbichler 1. Mär 2012 20:59

AW: Mittels CodeRedirect Funktionen patchen
 
Wenn Du schon so einen 'Blödsinn' machst, dann mach es richtig: Editiere Graphics.PAS und verändere sie nach deinen Vorstellungen. Dein Vorgehen ist eh nicht kompatibel und sauber.

Mit 'Blödsinn' meine ich nur die Art und Weise, wie Du das Problem lösen willst ('Mit dem Kopf durch die Wand'). Oder reizt dich nur die technische Machbarkeit?

Thom 1. Mär 2012 21:08

AW: Mittels CodeRedirect Funktionen patchen
 
Das ist kein Blödsinn. Vor einem Jahr hatte ich leider auch noch so argumentiert. :pale: Inzwischen weiß ich aber, daß einige Probleme, die durch "Compilermagie" erst verursacht werden oder durch - nett ausgedrückt - ungünstige Programmierung der System-Units entstehen, nur durch das Patchen der entsprechenden Stellen im Speicher zur Laufzeit behoben werden können. Dagegen ist die Neucompilierung der Delphi-Units unsinnig und durch das Fehlen einiger Bestandteile oft auch nicht machbar.

Bjoerk 2. Mär 2012 00:04

AW: Mittels CodeRedirect Funktionen patchen
 
Wenn es dir nur um State geht, könntest du's auch so machen. (Merkwürdig, daß die private Variable in der Graphics nicht FState heißt :gruebel:):

Delphi-Quellcode:
unit Unit2;

interface

type
  TTest = class
  private
    State: integer;
  public
    property Test: integer read State;
    constructor Create;
  end;

implementation

constructor TTest.Create;
begin
  State:= -1;
end;

end.
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, unit2;

type
  TMyTest = class
  private
    State: integer;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    O: TTest;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(O.Test));
  TMyTest(O).State:= 1;
  ShowMessage(IntToStr(O.Test));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  O:= TTest.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  O.Free;
end;

end.

ConnorMcLeod 2. Mär 2012 04:36

AW: Mittels CodeRedirect Funktionen patchen
 
@Furtbichler: wie Thom schon sagt, möchte ich die Originale nicht editieren. Das hätte enorme Auswirkungen auf die ganze Firma; so passe ich nur das Verhalten einiger Komponenten an. Es ist übrigens eine ähnliche Methode, wie sie auch in Delphi Speed Up und in IDE Fix Pack angewandt werden, die die meisten von uns täglich im Einsatz haben.

@Thom: ganz meine Meinung.

@Bjoerk: Du siehst das Problem nur von außen - da funktioniert es so, wie Du sagst. Aber durch das Patchen wird die Prozedur zu einem integrierten Teil der gepachten Klasse und daher ist dann das Casten unnötig geworden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:17 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz