保持PInvoked方法活着

时间:2014-09-22 11:26:47

标签: c# pinvoke dllimport

这是我的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();
    }

有没有更复杂的方法来保持这种工作?

1 个答案:

答案 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。通常从不。