2017-07-03 182 views
2

我用於從C#委託註冊以這樣的回調函數指針(不使用Marshal.GetFunctionPointerForDelegate):註冊C#委託給C++回調,Marshal.GetFunctionPointerForDelegate做什麼?

C++(Test.dll的)

typedef void (__stdcall* Callback)(int num); 

Callback pCallback = 0; 

void __stdcall SetCallback(Callback callback) 
{ 
    pCallback = callback; 
} 

void __stdcall ActionCpp() 
{ 
    if(pCallback) 
    { 
     pCallback(); 
    } 
} 

C#

class Program 
{ 
    [DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)] 
    public static extern void SetCallBack(Callback callback); 

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

    public delegate void Callback(); 

    static void Action() 
    { 
     Console.WriteLine("Callback succeeded."); 
    } 

    static void Main(string[] args) 
    { 
     Callback myAction = new Callback(Action); 
     SetCallback(myAction); 
     ActionCpp(); //Suppose to do the same thing as Action(); 
    } 
} 

看來這種方式很好。然而,我發現我們可以通過使用Marshal.GetFunctionPointerForDelegate來完成相同的事情,並將委託的IntPtr註冊到C++中的函數指針。 我想知道有什麼不同以及哪種做法更好? (也爲什麼?提前致謝。)

這是使用Marshal.GetFunctionPointerForDelegate時的C#代碼。 (沒有在C++代碼更改。)

C#(帶Marshal.GetFunctionPointerForDelegate)

class Program 
{ 
    [DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)] 
    public static extern void SetCallBack(IntPtr pCallBack); //change to type "IntPtr" this time. 

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

    public delegate void Callback(); 

    static void Action() 
    { 
     Console.WriteLine("Callback succeeded."); 
    } 

    static void Main(string[] args) 
    { 
     Callback myAction = new Callback(Action); 
     //GCHandle gcHandle = GCHandle.Alloc(myAction); <-- Is this necessary? 
     IntPtr pMyAction = Marshal.GetFunctionPointerForDelegate(myAction); 
     SetCallback(pMyAction); 
     ActionCpp(); 
     //gcHandle.Free(); 
    } 
} 

我又一但關於是否有必要使用「GCHandle.Alloc」(在我的意見相關的問題在上面的代碼中),以避免任何GC行動,只要我的回調myAction仍然活着? 我是C#和C++回調的新手,如果我有天真的錯誤,請告訴我。

回答

0

回調需要處理事件的方法的起始地址。所以你的兩個方法都獲得相同的起始地址。第一種方法很清晰,因爲您使用的是方法的名稱。第二種方法,你有更多的語句完成相同的第一種方法。

c#是託管語言,而C++是未託管的。這基本上意味着爲了防止PC進入藍屏,c#中增加了額外的保護。所以當從c#中調用un-managed C++規則時,必須遵循以防止藍屏。因此,任何傳遞給C++方法的指針變量都必須在c#中分配爲未使用GCHandle.Alloc或使用其他Marshal方法進行管理。 Marshal.StrToPtr也將分配未管理的內存。