2014-07-14 220 views
3

我想在delphi中使用這個簡單的C函數,但不能完美地將值轉換爲指針。德爾福指針鑄造

C函數:

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

德爾福功能:

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; 

對不起我的英語不好。

+0

在查看x86實現(Delphi例程中的註釋代碼)時,x64實現顯然是錯誤的。所以C函數可能是錯誤的(如果乘以8)。這也是有道理的,因爲參數被稱爲methodIndex而不是byteOffset,或者類似於依賴於調用方的體系結構。 –

+1

'return *(PVOID *)(*(DWORD_PTR *)intf + methodIndex * sizeof(PVOID));'可以在任何地方工作,儘管這樣做可能是一種非常蹩腳的方式。 –

回答

8

這不是C代碼的100%的翻譯,但它確實你想達到什麼目的使用此方法:

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; 

此代碼說明了一個事實,一個接口引用的指針IMT如下所示:

enter image description here

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

解碼此我們需要了解C++ operator precedence。這裏最高優先級的運算符是類型轉換。然後解引用高於二進制加法。因此,與加括號括住表達式爲:

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

即:

  • intf是指向DWORD_PTR
  • 解引用,爲了DWORD_PTR
  • 添加methodIndex,
  • 投向指向PVOID
  • de參考。

請注意,這個函數很奇怪,因爲methodIndex是一個字節偏移量而不是數組索引。最好的參數名稱是非常具有誤導性的。最糟糕的是,它使得該功能非常難以使用,特別是如果你想要獨立於指針大小的代碼。所以,如果這個功能真的是解決您實際遇到的任何問題的最佳方法,我會感到驚訝。

逐字翻譯是這樣的:

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

你可能更願意寫這樣的代碼,其中methodIndex是一個數組的索引,而不是一個字節偏移。這樣會更有意義。 C代碼是:

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

和匹配Delphi代碼:

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

注意非常小心,這個功能由一個以上的,因爲methodIndex被解釋爲一個數組索引的行爲完全不同。所以,這個函數不是問題中C代碼的翻譯。