2014-04-11 55 views
2

我正在使用Delphi XE編寫一個基類,這將允許降序類通過應用註釋映射dll方法。但是,我得到一個類型轉換錯誤,這是可以理解的。使用Rtti設置方法字段

本質的基類應該是這樣的:

TWrapperBase = class 
public 
    FLibHandle: THandle; 
    procedure MapMethods; 
end; 

procedure TWrapperBase.MapMethods; 
var 
    MyField: TRttiField; 
    MyAttribute: TCustomAttribute; 
    pMethod: pointer; 
begin 
    FLibHandle := LoadLibrary(PWideChar(aMCLMCR_dll)); 
    for MyField in TRttiContext.Create.GetType(ClassType).GetFields do 
    for MyAttribute in MyField.GetAttributes do 
     if MyAttribute.InheritsFrom(TMyMapperAttribute) then 
     begin 
     pMethod := GetProcAddress(FLibHandle, (MyAttribute as TMyMapperAttribute).TargetMethod); 
     if Assigned(pMethod) then 
      MyField.SetValue(Self, pMethod); // I get a Typecast error here 
end; 

和下降類看起來是這樣的:

TDecendant = class(TWrapperBase) 
private type 
    TSomeDLLMethod = procedure(aParam: TSomeType); cdecl; 
private 
    [TMyMapperAttribute('MyDllMethodName')] 
    FSomeDLLMethod: TSomeDLLMethod; 
public 
    property SomeDLLMethod: TSomeDLLMethod read FSomeDLLMethod; 
end; 

我可以不同的方式實現這一點,通過硬編碼的連接每個方法在重寫'MapMethods'中。然而,這將要求每個後代都這樣做,我想避免。

我知道在這種情況下使用的TValue將包含一個指針而不是正確類型(在這種情況下爲procedure(aParam: TSomeType); cdecl;)。

我的問題:有沒有辦法將'GetProcAdress'的指針作爲正確的類型,或者直接設置字段(例如使用字段地址'PByte(Self)+ MyField.Offset')你可以用來設置記錄屬性的值)?

在舊RTTI,可以這樣做,但只針對發佈的屬性,沒有任何類型檢查:

if IsPublishedProp(Self, 'SomeDLLMethod') then 
    SetMethodProp(Self, 'SomeDLLMethod', GetProcAddress(FLibHandle, 'MethodName'); 

回答

5

有兩個問題:

首先你EInvalidCast由TValue是非常嚴格所致關於類型轉換。您正在傳入Pointer並且想要設置類型爲TSomeDLLMethod的字段。您需要明確地通過具有正確類型信息的TValue

if Assigned(pMethod) then 
begin 
    TValue.Make(@pMethod, MyField.FieldType.Handle, value); 
    MyField.SetValue(Self, value); 
end; 

現在你會碰上這是因爲這對於一個tkProcedure一種類型的返回0 Rtti.pas的GetInlineSize方法裏面XE的一個錯誤觸發另一EInvalidCast異常中。我不知道這個版本修復了哪些版本,但在XE5中不存在。

對於XE,這可以通過使用我之前寫過的單元(我剛剛更新以修復此錯誤)來修復:RttiPatch.pas

我也報道了原來的問題,因爲指針是分配兼容的程序類型,以便TValue也應該處理這個問題:http://qc.embarcadero.com/wc/qcmain.aspx?d=124010

+0

請注意[QualityCentral現已關閉](https://community.embarcadero.com/blogs/entry/quality-keeps-moving-forward),因此您無法訪問'qc.embarcader o.com'鏈接了。如果您需要訪問舊的QC數據,請查看[QCScraper](http://www.uweraabe.de/Blog/2017/06/09/how-to-save-qualitycentral/)。 –

1

你可以嘗試這樣的:

Move(pMethod, PByte(Self) + Field.Offset, SizeOf(Pointer)); 

PPointer(PByte(Self) + Field.Offset)^ := pMethod; 
+0

第一個不起作用,因爲第二個參數作爲const傳遞(根據Delphi IDE)。 – deColaman

相關問題