注册C#委托给C++回调,Marshal.GetFunctionPointerForDelegate做什么?

问题描述:

我用于从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++回调的新手,如果我有天真的错误,请告诉我。

回调需要处理事件的方法的起始地址。所以你的两个方法都获得相同的起始地址。第一种方法很清晰,因为您使用的是方法的名称。第二种方法,你有更多的语句完成相同的第一种方法。

c#是托管语言,而C++是未托管的。这基本上意味着为了防止PC进入蓝屏,c#中增加了额外的保护。所以当从c#中调用un-managed C++规则时,必须遵循以防止蓝屏。因此,任何传递给C++方法的指针变量都必须在c#中分配为未使用GCHandle.Alloc或使用其他Marshal方法进行管理。 Marshal.StrToPtr也将分配未管理的内存。