Kamran
Kamran

Reputation: 387

Delphi pointer casting

I want to use this simple C function in delphi, but cant cast the values to pointer perfectly.

C function :

PVOID GetInterfaceMethod(PVOID intf, DWORD methodIndex)
{
  return *(PVOID*)(*(DWORD_PTR*)intf + methodIndex);
}

Delphi function :

function GetInterfaceMethod(const intf; methodIndex: DWORD): Pointer;
begin
  // return *(PVOID*)(*(DWORD_PTR*)intf + methodIndex);    x64
  // return *(PVOID*)(*(DWORD*)intf + methodIndex * 4);    x86
  Result := Pointer(Pointer(DWORD_PTR(Pointer(intf)^) + methodIndex)^);  //x64
end;

Excuse me for my bad English.

Upvotes: 3

Views: 1791

Answers (2)

Stefan Glienke
Stefan Glienke

Reputation: 21713

This is not a 100% translation of the C code but it does what you are trying to achieve by using this method:

  function GetInterfaceMethod(const intf; methodIndex: Cardinal): Pointer;
  type
    PPVtable = ^PVtable;
    PVtable = ^TVtable;
    TVtable = array[0..MaxInt div SizeOf(Pointer) - 1] of Pointer;
  begin
    Result := PPVtable(intf)^^[methodIndex];
  end;

This code illustrates the fact that an interface reference is a pointer to the IMT as shown below:

enter image description here

Upvotes: 7

David Heffernan
David Heffernan

Reputation: 612794

PVOID GetInterfaceMethod(PVOID intf, DWORD methodIndex)
{
  return *(PVOID*)(*(DWORD_PTR*)intf + methodIndex);
}

To decode this we need to understand C++ operator precedence. The highest precedence operator here is the type cast. Then dereference is higher than binary addition. So with added parens the expression becomes:

*(PVOID*)((*(DWORD_PTR*)intf) + methodIndex)

That is:

  • cast intf to be pointer to DWORD_PTR,
  • dereference that, to DWORD_PTR,
  • add methodIndex,
  • cast to pointer to PVOID,
  • dereference that.

Note that this function is rather odd in that methodIndex is a byte offset rather than an array index. At best the parameter name is very misleading. At worst, it makes the function exceedingly hard to use, especially if you want code that will work independently from pointer size. So, I'd be surprised if this function is really the best way to solve whatever problem you are actually facing.

A literal translation goes like this:

function GetInterfaceMethod(intf: Pointer; byteOffset: DWORD): Pointer;
begin
  Result := PPointer(PDWORD_PTR(intf)^ + byteOffset)^;
end;

You might prefer to write this code where methodIndex is an array index rather than a byte offset. That would make way more sense. The C code would be:

PVOID GetInterfaceMethod(PVOID intf, DWORD methodIndex)
{
    return *(*(PVOID**)intf + methodIndex);
}

And the matching Delphi code:

{$POINTERMATH ON}
function GetInterfaceMethod(intf: Pointer; methodIndex: DWORD): Pointer;
begin
  Result := (PPointer(intf^) + methodIndex)^;
end;

Note very carefully that this function behaves quite differently from the one above because methodIndex is interpreted as an array index. So, this function is not a translation of the C code in the question.

Upvotes: 0

Related Questions