Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Überprüfen, ob ein Pointer auf ein Objekt zeigt (https://www.delphipraxis.net/142768-ueberpruefen-ob-ein-pointer-auf-ein-objekt-zeigt.html)

fajac 3. Nov 2009 13:09


Überprüfen, ob ein Pointer auf ein Objekt zeigt
 
Hallo Experten, folgendes Problem:

Ich möchte eine Listenklasse erstellen, die von TList abgeleitet ist. In allen Methoden, die einen Pointer zur Liste hinzufügen oder einen entfernen, möchte ich, falls es sich bei dem übergebenen Pointer um ein Objekt eines bestimmten Typs handelt, eine Methode davon aufrufen. Zur Überprüfung, ob es sich um diesen Typ handelt, benutze ich den is-Operator.
Diese Liste möchte ich applikationsweit als Ersatz von TList verwenden.

Das funktioniert auch wunderbar, solange die Liste ausschließlich mit Objekten gefüttert wird. Aber wehe, man versucht das mit Zeigern auf Records, dann gibt es eine AV - hier ein Beispiel:

Delphi-Quellcode:
type
  TMyObject = class (TObject) { Der Typ, auf den ich prüfen möchte }
  public
    procedure DoSomething();
  {...}
  end;

  TMyList = class (TList)
  public
    function Add (AItem : Pointer) : Integer; reintroduce;
    {...}
  end;

implementation
 
function TMyList.Add (AItem : Pointer) : Integer;
var
  obj : TObject;
begin
  obj := AItem; { Cast auf TObject, um "is" anwenden zu können }
  if obj is TMyObject then { <== hier schepperts, wenn AItem ein "normaler" Zeiger ist }
    TMyObject (AItem).DoSomething;
  Result := inherited Add (AItem);
end;
Ich bin mir darüber im klaren, dass der Cast auf TObject an sich schon problematisch ist - aber mir fällt keine andere Möglichkeit ein, herauszufinden um was es sich bei dem Pointer handelt. Natürlich könnte man die Exception abfangen und dann davon ausgehen, dass AItem kein Objekt ist, aber das fände ich auch unsauber.
Kann jemand helfen?

himitsu 3. Nov 2009 13:20

Re: Überprüfen, ob ein Pointer auf ein Objekt zeigt
 
Sowas ist nicht 100%ig möglich.

einzige wirkliche Lösung: Pointer und Objekte getrennt verwalten


Delphi-Quellcode:
TObject(P) is TXyz
liefert bei Objekten richtige Lösungen (solange das Objekt nicht durch z.B. einen Bufferoverflow zerstört wurde),
aber in anderen Daten, wie z.B. einem Record, können zufällig Werte vorhanden sein, welche der "Signatur" eines Objektes entsprechen, wodurch der Record dann als Objekt erkannt würde.

sirius 3. Nov 2009 13:21

Re: Überprüfen, ob ein Pointer auf ein Objekt zeigt
 
Zitat:

Zitat von fajac
Ich bin mir darüber im klaren, dass der Cast auf TObject an sich schon problematisch ist

Ja, aber es gibt keine andere Möglichkeit. Du kannst auch nicht prüfen, ob ein Zeiger auf ein Objekt zeigt. Es gäbe bestimmte Tricks, aber nichts ist sicher.

Neutral General 3. Nov 2009 13:24

Re: Überprüfen, ob ein Pointer auf ein Ojekt zeigt
 
Delphi-Quellcode:
function PointsToObj(P: Pointer): Boolean;
begin
  try
    Result := TObject(P).ClassName <> '';
  except
    Result := false;
  end;
end;
Konnts mir nicht verkneifen :stupid:

Hawkeye219 3. Nov 2009 13:42

Re: Überprüfen, ob ein Pointer auf ein Objekt zeigt
 
Hallo,

der folgende Code basiert auf einer Vorlage von Hallvard Vassbotn:

Delphi-Quellcode:
function IsValidObject (const aObject: TObject): Boolean;
type
  PVmt = ^TVmt;
  TVmt = packed record
    SelfPtr: TClass;
    ignored: array [0..-(4 + vmtSelfPtr) - 1] of Byte;
  end;
var
  VMT: PVmt;
begin
  Result := False;

  if {Windows.}IsBadReadPtr(aObject, 4) then
    Exit;

  VMT := PVmt(aObject.ClassType);
  Dec (VMT);

  if IsBadReadPtr(VMT, 4) then
    Exit;

  if (aObject.ClassType = VMT.SelfPtr) then
    Result := True;
end;
Die Anmerkung von himitsu bezüglich der getrennten Verwaltung von Pointern und Objekten sollte trotzdem beachtet werden. Der Code könnte aber beim Debuggen nützlich sein.

Gruß Hawkeye

fajac 3. Nov 2009 15:15

Re: Überprüfen, ob ein Pointer auf ein Objekt zeigt
 
Vielen Dank für Eure Antworten - leider habe ich mir sowas schon gedacht...
Natürlich ist der Hinweis, die Verwaltung der Objekte von der der Zeiger zu trennen völlig richtig - das Problem ist, dass ich hier ein ziemlich altes und krudes Projekt bearbeiten muss und mir gedacht habe, dass ich mit der neuen Liste da etwas Ordnung schaffen könnte...war wohl nix.
Gruß
Frank

mjustin 3. Nov 2009 15:30

Re: Überprüfen, ob ein Pointer auf ein Objekt zeigt
 
Zitat:

Zitat von fajac
Diese Liste möchte ich applikationsweit als Ersatz von TList verwenden.

Das funktioniert auch wunderbar, solange die Liste ausschließlich mit Objekten gefüttert wird.

Ok, dann nimm eine Klasse die einen Pointer als einzige Property enthält. Ein Workaround, aber wenn es der Codeverbesserung dienlich ist ... :)

Objekte dieses Typs können dann leicht mit is erkannt werden.

Delphi-Quellcode:
TMyPointerHolder = class
private
  FP: Pointer;

public
  property P: Pointer read FP write FP;

end;
Viele Grüße,

himitsu 3. Nov 2009 15:40

Re: Überprüfen, ob ein Pointer auf ein Objekt zeigt
 
@General: ich konnte es mir auch nicht verkneifen :oops:
Delphi-Quellcode:
var x: Array[0..100] of Integer;
  P: PInteger;
begin
  X[30] := $6d696807;
  X[31] := $75737469;
  X[40] := Integer(@X[30]);
  X[51] := Integer(@X[51]);
  P := @X[51];
  if PointsToObj(P) then
    ShowMessage('Ja, ich bin eine Klasse, und mein Klassenname ist "'
      + TObject(P).ClassName + '"');
  if not IsValidObject(TObject(P)) then
    ShowMessage('Ich bin zwar zufällig kein valides Object, '
      + 'aber das kann man leicht ändern *grins*');
Gut, IsValidObject hat duch mehr Abfragen eine höhere Wahrscheinlichkeit, daß es richtig liegt,
aber dennoch kann es immernoch mal falsch liegen. ;)

Nein, ich bin nicht so sehr selbstverliebt, aber dieser Name paßte nunmal zufällig genau rein :angel2:
(und ich verrate nicht, was ich mit diesem Satz meine ... wer es gesehn hat, der weiß es)

[add]
so, der obere Code funktioniert mit D7 und wer weiß womit sonst noch,
so wie ich es will ... ansonsten funktioniert er zwar, aber der Name gefällt mir nicht ... drum hier noch 'ne etwas angepaßtere Version
der and
Delphi-Quellcode:
var x: Array[0..100] of Integer;
  P: PInteger;
  i: Integer;
begin
  i := 40 - vmtClassName shr 2;
  X[30] := $6d696807;
  X[31] := $75737469;
  X[40] := Integer(@X[30]);
  X[ i] := Integer(@X[ i]);
  P := @X[i];
  if PointsToObj(P) then
    ShowMessage('Ja, ich bin eine Klasse, und mein Klassenname ist "'
      + TObject(P).ClassName + '"');
  //if not IsValidObject(TObject(P)) then
  //  ShowMessage('Ich bin zwar zufällig kein valides Object, '
  //    + 'aber das kann man leicht ändern *grins*');
end;

Blup 4. Nov 2009 08:29

Re: Überprüfen, ob ein Pointer auf ein Objekt zeigt
 
Ich würde das Problem so angehen:
Delphi-Quellcode:
  TMyList = class (TObjectList)
    constructor Create;
  public
    {...} 
  end;

constructor TMyList.Create;
begin
  inherited;
  OwnsObjects := False;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:26 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