这是我的 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()当回调到来时我得到空引用异常。所以我使用 Thread 来保持它并且一切正常,但我对这个解决方案不满意:
static public bool Working = true;
static public void Init() {
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
Initialize(FirstScanForDevicesDone);
while (Working)
{
Thread.Sleep(1000);
}
}).Start();
}
有没有更复杂的方法来保持这个功能?
所以我使用 Thread 来保留它,一切正常
不,该线程实际上并不能解决问题。它只是looks就像它一样,测试调试版本和使用调试器的副作用。在您将发布版本交付给客户后,它仍然会以完全相同的方式崩溃。当然是最糟糕的失败。为什么它seems就像线程解决它的解释一样这个帖子 https://stackoverflow.com/a/17131389/17034.
您需要解决真正的问题,您将委托对象传递给本机代码,但在 Init() 方法完成后,不再有对该对象的可见引用。垃圾收集器无法查看本机代码内部以查看它的使用情况。因此,当本机代码在此之后进行回调时,下一次垃圾收集将销毁该对象,kaboom。请注意,您通常会从调试器助手那里收到措辞强烈的警告,请确保您没有通过射击信使来解决问题。
正确的修复方法是:
static FirstScanForDevicesDoneFunc callbackDelegate;
static public void Init() {
callbackDelegate = new FirstScanForDevicesDoneFunc(FirstScanForDeviceDone);
Initialize(callbackDelegate);
}
The 回调委托变量确保 GC 始终可以看到对该对象的引用。当本机代码无法再进行回调时,您可以将其设置回 null。通常不会。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)