Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Von C++ nach Delphi (Macro) (https://www.delphipraxis.net/160686-von-c-nach-delphi-macro.html)

Alter Mann 26. Mai 2011 09:29

Von C++ nach Delphi (Macro)
 
Hallo,

in der WinNT.h ist das folgende macro definiert:
Code:
//
// Calculate the address of the base of the structure given its type, and an
// address of a field within the structure.
//

#define CONTAINING_RECORD(address, type, field) ((type *)( \
                                                 (PCHAR)(address) - \
                                                 (ULONG_PTR)(&((type *)0)->field)))
wie muss das ganze in Delphi aussehen und kann jemand das ganze erklären?

Danke

himitsu 26. Mai 2011 09:34

AW: Von C++ nach Delphi (Macro)
 
Geht nicht.
Außer du schreibst dir einen Preprozessor für den Compiler, welcher sowas vorher noch schnell ausrechnet.

Lösung: Rechenvorschrift erkennen und die entsprechenden Werte überall direkt einsetzen.
Eventuell kann man sich auch ein Programm schreiben (falls es das nicht schon gibt), welches den wert berechnet, falls es mehrere werden.

Oder man muß weg von Konstanten und kann dann aus dem Makro eine Funktion machen.

Alter Mann 26. Mai 2011 09:51

AW: Von C++ nach Delphi (Macro)
 
Ach himitsu, du bist wie immer so aufbauend; Danke!
Das Problem ist nur das dieses macro innerhalb einer procedur aufgerufen wird
und da ich nicht weis was da genau passiert, kann ich es nicht so einfach 'nachbauen'.
Verwendet wird es in dem USBView Beispiel des WinDDK.

himitsu 26. Mai 2011 10:34

AW: Von C++ nach Delphi (Macro)
 
Delphi-Quellcode:
function CONTAINING_RECORD(Address: Pointer; cType: PTypeInfo; Field: String): Pointer;
begin
  Result := PAnsiChar(Address) - LongInt(@cType(nil).{Field});
end;
Das Problem ist jetzt allerdings, daß du dieses nichtmal direkt übersetzen kanns.

cType it wohl ein Record-Typ
Field ist der Name eines Feldes in diesem Record

Den Typ könntest du als PTypeInfo übergeben

TypeInfo(TMyType)
und dann müßtest du über die RTTI den Offset dieses Feldes in dem record rausfinden

Danach dann diesen Offset von Address abziehen und das wäre das Ergebnis.

Delphi-Quellcode:
type
  TMyType = record
    abc: LongInt;
    def: Byte;
  end;

Pneu := CONTAINING_RECORD(P, TMyType, def);

// wäre dann
Pneu := Pointer(Integer(P) - 4);
Es gibt für dieses in Delphi leider keinerlei Sprachfeatures, welche sowas direkt bieten.
> keine Makros
> und man kann Variablen\Typen\Felder nicht direkt "namentlich" über einen "String" ansprechen.

cType könnte man noch als Gernic übergeben, aber beim Field war's das dann ... dort kommt man ohne RTTI nicht weiter.
Delphi-Quellcode:
function TTheClass.ContainingRecord<cType>(Address: Pointer; Field: String): Pointer;
var
  Offset: Integer;
begin
  Offset := {RTTI nach dem Offset von Field in cType fragen};
  Result := PAnsiChar(Address) - i;
end;
Es sei denn du nimmst mehrere Funktionen, für jeweils eine cType-Field-Kombination.
Delphi-Quellcode:
function ContainingRecord_{Type}_{Field}(Address: Pointer): Pointer; overload;
begin
  Result := Pointer(Integer(@Address) - Integer(P{Type}(nil).{Field}));
end;
Dann jeweils eine Kopie davon erstellen und dort {Type} und {Field} ersetzen.

Alter Mann 26. Mai 2011 11:26

AW: Von C++ nach Delphi (Macro)
 
Danke, die Realisierung wird allerdings etwas dauern.
Zum Glück ist der Typ bekannt 'LIST_ENTRY', mal sehen wie ich mich anstelle.
Werde mich bestimmt nochmal melden.

Der Jan 27. Mai 2011 10:15

AW: Von C++ nach Delphi (Macro)
 
Wenn dir der Typ und Feld bekannt sind (und selbige idealerweise auch noch konstant bleiben), dann kennst du doch den Offset des Feldes und ziehst diesen einfach von der gegebenen Adresse ab und hast die gesuchte Basisadresse.

Code:
//Pseudocode, nicht schlagen :)

type
  MyType = record
    Var1: Typ1;
    Var2: Typ2;
    Var3: Typ3;
    Var4: Typ4;
  end;

CONTAINING_RECORD(Addr, MyType, Var3) = Addr - sizeof(Typ2) - sizeof(Typ1)

himitsu 27. Mai 2011 10:22

AW: Von C++ nach Delphi (Macro)
 
Zitat:

Zitat von Der Jan (Beitrag 1103259)
Code:
CONTAINING_RECORD(Addr, MyType, Var3) = Addr - sizeof(Typ2) - sizeof(Typ1)


Dank der Speicherausrichtung, kann das schnell mal schief laufen.

Delphi-Quellcode:
MyType = record
  Var1: Byte;
  Var2: LongInt;
end;
Laut deiner Berechnung/Zählung würde Var2 einen Offset von 1 haben, da SizeOf(Byte) = 1, aber standardmäig wird man einen Offset von 4 vorfinden.

Der Jan 27. Mai 2011 10:35

AW: Von C++ nach Delphi (Macro)
 
Zitat:

Zitat von himitsu (Beitrag 1103260)
Dank der Speicherausrichtung, kann das schnell mal schief laufen.

Diese muss man natürlich ausschalten. Das war vorausgesetzt

himitsu 27. Mai 2011 15:11

AW: Von C++ nach Delphi (Macro)
 
Theoretisch hätte ich ja eine Funktion, ohne RTTI, welche die Ausrichtung berechnet, aber so optimal ist diese Lösung dann garnicht.
(Ich glaub ich hatte das aktuell im himXML mit hochgeladen ... siehe Record-Serialisierung)


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