The CONTAINING_RECORD macro in C returns the base address of a structure/record type variable based on the address of a field member within the structure. It is extremely helpful in cases where I can pass only a predefined record pointer to some Windows API function which triggers callbacks.
For example if I have some types like:
type
tInnerRecord = record
x, y : integer;
end;
pInnerRecord = ^tInnerRecord
tOuterRecord = record
field1 : integer;
inner : tInnerRecord;
field2 : integer;
end;
pOuterRecord = ^tOuterRecord;
I would like to be able to do something like:
procedure SomeCallback( pIn : pInnerRecord ); stdcall;
var
Out : pOuterRecord;
begin
Out := CONTAINING_RECORD(pIn, tOuterRecord, inner);
Out.field1 := pIn.x + pIn.y;
end;
In my specific case I want to pass my object pointer along with the overlapped data pointer of ReadFileEx (Windows Async I/O) so I can access the object in the callback.
Is there some equivalent function that provides similar functionality in Delphi (2006)?
I'm out of compiler just now, but this should do the trick:
Out := Pointer( Cardinal(pIn) - Cardinal(@TOuterRecord(nil^).inner));
David explains why there could be no direct equivalent function in Delphi. So here is a function that comes closest:
function ContainingRecord( var aField; aFieldOffsetRef : Pointer) : Pointer;
{$IF Declared(NativeUInt) = False}
type
NativeUInt = Cardinal;
{$IFEND}
begin
Result := Pointer(NativeUInt(@aField) - NativeUInt(aFieldOffsetRef));
end;
Calling example:
Out := ContainingRecord(pIn^, @pOuterRecord(nil).inner);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With