2013-04-18 13 views
2

我試圖將C#回調函數傳遞給本機DLL。它工作正常,但我找不到方法來訪問回調方法的父對象。這裏有一個代碼,演示了什麼,我想做的事:在傳遞給本機DLL的C#回調中訪問管理對象

class MyForm: Form { 
    public delegate void CallbackDelegate(IntPtr thisPtr); 

    [DllImport("mylib.dll", CallingConvention = CallingConvention.StdCall)] 
    public static extern void Test(CallbackDelegate callback); 

    int Field; 

    static void Callback(IntPtr thisPtr) 
    { 
     // I need to reference class field Field here. 
     MyForm thisObject = ?MagicMethod?(thisPtr); 

     thisObject.Field = 10; 
    } 

    void CallExternalMethod() 
    { 
     Test(Callback); 
    } 
} 

我試圖得到的this的指針,但我得到了以下異常:「對象包含非基本或非blittable數據」。我應該提到父對象是一個WindowsForms表單。

UPDATE

DLL是用Delphi編寫和測試功能的簽名如下:

type 
    TCallback = procedure of object; stdcall; 

procedure Test(Callback: TCallback); stdcall; 

我收到上述錯誤消息時,我試圖讓指針請使用以下代碼:

var ptr = GCHandle.Alloc(this, GCHandleType.Pinned).AddrOfPinnedObject(); 
+0

如何被聲明在中是指mylib.dll您的本地試驗方法?我沒有要求定義,只是方法的簽名。 – Mzn

+0

你能提供更多的代碼嗎? –

+0

@David Heffernan我實際上是在編寫代碼,而不是複製原文以避免不相關的細節。我想我寫了所有相關的代碼。什麼不見​​了? – Max

回答

3

你在想這個。 C#編組將在您的委託周圍創建一個thunk。你不能試圖這樣做。

在德爾福側寫這樣的:

type 
    TCallback = procedure; stdcall; 

只需刪除該of object

在C#側您的代表是:

public delegate void CallbackDelegate(); 

,你用你的委託方法如下:

void Callback() 
{ 
    // an instance method, so *this* is available 
} 

然後調用到這樣的本地代碼:

void CallExternalMethod() 
{ 
    Test(Callback); 
} 

所以,讓我們把它放在一起。在德爾福方面,你可以這樣寫:

library MyLib; 

type 
    TCallback = procedure; stdcall; 

procedure Test(Callback: TCallback); stdcall; 
begin 
    Callback; 
end; 

exports 
    Test; 

begin 
end. 

和C#的一面:

class MyForm: Form { 
    public delegate void CallbackDelegate(); 

    [DllImport("mylib.dll")] 
    public static extern void Test(CallbackDelegate callback); 

    int Field; 

    static void Callback() 
    { 
     Field = 10; 
    } 

    void CallExternalMethod() 
    { 
     Field = 0; 
     Test(Callback); 
     Debug.Assert(Field == 10); 
    } 
} 
+0

哇!這真是奇怪。所以thisPtr就像這裏的一個虛擬參數。非常感謝你!這確實有效。 – Max

+0

您需要刪除雙方的thisPtr。讓編組爲你打氣。 –

+0

這裏是關於這個主題的另一個問題:http://stackoverflow.com/questions/15666173/how-do-non-static-callbacks-work-from-native-code –

0

您應該使用System.Runtime.InteropServices.GCHandle類,its MSDN documentation has examples。它涉及使用其靜態方法將C#引用從非託管值轉換爲和從非託管值轉換。

我有沒有快速的方法來檢查,但這樣的事情應該工作:在一些需要注意的是:

static void Callback(IntPtr thisPtr) 
{ 
    MyForm thisObject = (MyForm)GCHandle.FromIntPtr(thisPtr).Target; 

    thisObject.Field = 10; 
} 

IntPtr應該這樣來獲得:

IntPtr thisPtr = GCHandle.ToIntPtr(GCHandle.Alloc(thisObject))); 

PS點你必須釋放句柄,無論是在被調用者還是在調用者。

+0

我已更新我的問題。你能提供代碼來做到這一點嗎?我試圖使用這個班,但沒有成功。 – Max

+0

@Max我沒有快速的方法來測試這是否有效,但它是一般的想法。 – Medinoc

+0

這就是我在做的,只是我使用了'GCHandleType.Pinned'參數。我認爲你不允許將未固定的指針傳遞給本機代碼。 – Max

相關問題