C# 保持pinvoke方法的活力
这是我的C代码:C# 保持pinvoke方法的活力,c#,pinvoke,dllimport,C#,Pinvoke,Dllimport,这是我的C代码: LIBRARY_API bool __cdecl Initialize(void (*FirstScanForDevicesDoneFunc)(void)); 下面是使用此DLL的C#PINvoke代码: [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void FirstScanForDevicesDoneFunc(); [DllImport("Nati
LIBRARY_API bool __cdecl Initialize(void (*FirstScanForDevicesDoneFunc)(void));
下面是使用此DLL的C#PINvoke代码:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FirstScanForDevicesDoneFunc();
[DllImport("Native.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern bool Initialize(FirstScanForDevicesDoneFunc);
当我这样调用此方法时:
static public void Init() {
Initialize(FirstScanForDevicesDone);
}
static public void FirstScanForDevicesDone() {
//do something
}
在Init()的末尾,当回调到来时,我得到NullReferenceException。因此,我使用线程来保持它,一切正常,但我不满意此解决方案:
static public bool Working = true;
static public void Init() {
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
Initialize(FirstScanForDevicesDone);
while (Working)
{
Thread.Sleep(1000);
}
}).Start();
}
有没有更复杂的方法让它继续工作
所以我用线来保持它,一切正常
不,线程实际上并没有解决问题。它只是看起来像这样,这是测试调试构建和使用调试器的副作用。在您将发布版本发布给客户之后,它仍然会以完全相同的方式崩溃。当然是最糟糕的失败。中解释了线程解决问题的原因
您需要解决真正的问题,您正在将委托对象传递给本机代码,但是在Init()方法完成后,就不再有对该对象的可见引用。垃圾收集器无法窥视本机代码内部以查看其使用情况。因此,下一次垃圾收集将销毁对象,当本机代码在此之后进行回调时,kaboom。请注意,通常情况下,调试器助手会对此发出措辞强烈的警告,请确保您没有通过射击messenger来解决问题
正确的解决方法是:
static FirstScanForDevicesDoneFunc callbackDelegate;
static public void Init() {
callbackDelegate = new FirstScanForDevicesDoneFunc(FirstScanForDeviceDone);
Initialize(callbackDelegate);
}
callbackDelegate变量确保GC始终可以看到对对象的引用。当本机代码无法再进行回调时,将其设置回null。通常不会。我们首先需要了解问题所在。为什么要出现
NullReferenceException
?本机代码在做什么?何时调用回调?为本机代码定义托管回调的标准方法是使用Marshal.GetFunctionPointerForDelegate方法。@AlexFarber您之前的注释似乎有效:保留回调函数的静态变量。这意味着回调将在最后被收集。我现在觉得自己很笨。这里不需要GetFunctionPointerForDelegate
。谢谢-这是一个很好的简单解决方案。我觉得自己很愚蠢,因为我以前没有注意到这一点。