注册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也将分配未管理的内存。