【问题标题】:C# Interop with __cdecl callbacks and delegates与 __cdecl 回调和委托的 C# 互操作
【发布时间】: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。只要类保持活动状态,并且对象是类中的全局变量,你就可以了。如果您将其设为静态,并实例化多个这些类(我就是这样做的),那么您将进入一个受伤的世界……请参阅下面的解决方案。

标签: c# interop


【解决方案1】:

将 MarshalAs 语句添加到 PInvoke 原型中有效。不知何故,我想我认为既然代表被标记为那样,它也会以这种方式编组。但是你需要更明确的原因可能是有原因的。

   public static extern int DAQmxRegisterEveryNSamplesEvent(IntPtr task, Int32 everyNsamplesEventType, UInt32 nSamples, UInt32 options,[MarshalAs(UnmanagedType.FunctionPtr)]EveryNSamplesCallback callbackFunction, IntPtr callbackData);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-16
    • 1970-01-01
    • 1970-01-01
    • 2012-09-21
    • 2011-07-02
    • 1970-01-01
    相关资源
    最近更新 更多