【发布时间】:2019-11-20 18:35:57
【问题描述】:
一段时间以来,我一直成功地使用 Interop 来使用外部 C 库。太棒了。我们需要添加使用具有回调的函数的能力。这有点更具挑战性。我们尝试将它作为 IntPtr 和其他几个选项传递。但它似乎总是让 VisualStudio 崩溃。我们还尝试启用本机调试,但没有用于其他库的调试库,就到此为止了。
相关C库代码:
#define CVICDECL __cdecl
#define CVICALLBACK CVICDECL
typedef int32 (CVICALLBACK *DAQmxEveryNSamplesEventCallbackPtr)(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData);
int32 __CFUNC DAQmxRegisterEveryNSamplesEvent(TaskHandle task, int32 everyNsamplesEventType, uInt32 nSamples, uInt32 options, DAQmxEveryNSamplesEventCallbackPtr callbackFunction, void *callbackData);
还有 C# 代码:
[DllImport("nicaiu", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int DAQmxRegisterEveryNSamplesEvent(IntPtr task, Int32 everyNsamplesEventType, UInt32 nSamples, UInt32 options, EveryNSamplesCallback callbackFunction, IntPtr callbackData);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate Int32 EveryNSamplesCallback(IntPtr taskHandle, Int32 everyNsamplesEventType, UInt32 nSamples, IntPtr callbackData);
...
func = new EveryNSamplesCallback(Test2Callback); //func is a class-level variable
tmp += ChkForError(DAQmxRegisterEveryNSamplesEvent(taskHandle_DAT, DAQmx_Val_Transferred_From_Buffer, 104, 0 , func, new IntPtr()));
...
public Int32 Test2Callback(IntPtr taskHandle, Int32 everyNsamplesEventType, UInt32 nSamples, IntPtr callbackData)
{
Console.WriteLine("CALLBACK!!");
return 0;
}
我们已经尝试了许多不同的东西(在签名中使用 IntPtr)和其他地方,它总是想吐给我们。关于如何实现和/或调试的想法?
【问题讨论】:
-
正如他们提到的 here 似乎 TaskHandle 只是一个整数
-
这里的TaskHandle 完全没有问题,我可以向您保证它是一个IntPtr。我还有几百个其他函数可以使用 taskHandle 并且可以很好地工作。似乎有问题的是特定于回调的部分。
-
我们看不到
func变量声明,它是static至关重要,因此垃圾收集器不会收集委托对象。 -
这不会是导致此问题的原因——因为该类已完全加载,并且它是该类中的一个全局变量,它不会被 GC 处理。如果它正在工作,然后随机停止,那么您会认为 GC 是罪魁祸首。但它在创建后的下一条指令基本上不起作用,显然不能是 GC。只要类保持活动状态,并且对象是类中的全局变量,你就可以了。如果您将其设为静态,并实例化多个这些类(我就是这样做的),那么您将进入一个受伤的世界……请参阅下面的解决方案。