Reputation: 387
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
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:
Upvotes: 7
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:
intf
to be pointer to DWORD_PTR
,DWORD_PTR
,PVOID
,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