这是我的C代码:
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 。所以我使用Thread保留它并且一切正常,但我对这个解决方案不满意:
static public bool Working = true;
static public void Init() {
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
Initialize(FirstScanForDevicesDone);
while (Working)
{
Thread.Sleep(1000);
}
}).Start();
}
有没有更复杂的方法来保持这种工作?
答案 0 :(得分:10)
所以我使用Thread保留它,一切正常
不,该主题并未真正解决问题。它只是看起来,它是测试Debug构建和使用调试器的副作用。将Release版本发布给客户后,它仍会以完全相同的方式崩溃。最糟糕的当然是失败。为什么似乎就像线程解决它一样在this post中解释。
您需要解决实际问题,您正在将委托对象传递给本机代码,但在Init()方法完成后,对该对象不再有可见的引用。垃圾收集器无法查看本机代码以查看其中的使用情况。因此,当本机代码在此之后进行回调时,下一个垃圾收集将破坏对象kaboom。请注意,您通常会从调试器助手那里得到一个措辞强烈的警告,请确保您没有通过拍摄信使来解决问题。
正确修复:
static FirstScanForDevicesDoneFunc callbackDelegate;
static public void Init() {
callbackDelegate = new FirstScanForDevicesDoneFunc(FirstScanForDeviceDone);
Initialize(callbackDelegate);
}
callbackDelegate 变量确保GC始终可以看到对象的引用。当本机代码不能再进行回调时,将其设置为null。通常从不。