.net - 在 Linux/ARM 上使用 pinvoke 和 C 函数回调的 F# 委托(delegate)

标签 .net c f# mono pinvoke

你能帮我使用一个来自 F# 的需要回调的 C 函数吗?我在基于 ARM 处理器的 Raspberry Pi 2 上使用 F#、mono 和 Arch Linux。

我最初的问题,理解用于回调的签名,是 answered您可以阅读以获取更多上下文。

我陷入了僵局。使用该库时,程序因段错误而崩溃。

我相信这是因为编码不匹配。根据 Expert F# 3.0 一书,“clr 仅支持编码函数指针的 std 调用约定”。 CLR 假定被调用者将清理堆栈(StdCall),C 库期望调用者将根据 MSDN 上的定义清理堆栈(Cdecl)。 .因此内存泄漏。

可悲的是,我无法让 CLR 使用 Cdecl 作为该委托(delegate),也无法让 C 在 ARM 处理器上使用 StdCall。我还没有编写 C 库,但我可以访问源代码。

这是C中的函数签名

int wiringPiISR (int pin, int edgeType,  void (*function)(void)) ;

和我的 F# 代码的一部分:

type ISRCallback = delegate of unit -> unit

[<DllImport(wiringPiLib, EntryPoint = "wiringPiISR", CallingConvention = CallingConvention.Cdecl, SetLastError=true)>]
    extern int wiringPiISR(int pin, int mode, [<MarshalAs(UnmanagedType.FunctionPtr)>]ISRCallback callBack);

[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>] 装饰代表没有帮助。编译器会默默地忽略它,我认为这就是这些属性的设计方式。

有没有另一种方法来做到这一点 - 可能是编辑 C 代码,或者以另一种方式包装它? (也许是 C++?)

注意:mono-project 网站上有一篇有趣的文章,标题为 Interop with Native Libraries

与此同时,我编写了一个小循环来轮询 GPIO 引脚。不理想,但它有效。

编辑:我的内存泄漏假设是错误的,但是,感谢评论和它提示的研究,我学到了很多东西并找到了答案。

最佳答案

正如评论中所指出的以及我最初问题的答案中所建议的,段错误是由回调函数的垃圾收集引起的。

添加 GC.StayAlive (MyFunctionDoingCallBack)在我的代码中的正确位置让任何审查代码的人——我——清楚地知道何时收集回调垃圾是安全的。这个解决方案比找出回调超出范围的原因以及如何将其保持在范围内更容易。我意识到这对我作为程序员的影响很糟糕;-(。

This answer解释了为什么 SetLastError=false 是正确的。 native 代码绝对不会返回 Win32 错误,它无论如何都在 Linux 上运行,所以我只会从错误代码中得到垃圾。

设置CallingConvention.Cdecl在 DLLImport 属性上有效。也许“clr 只支持编码函数指针的 std 调用约定”这句话对我的系统(Linux 上的单声道)是错误的,或者我误解了这句话。

设置[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]EntryPoint = "wiringPiISR" 一样,委托(delegate)似乎是多余的DLLImport 的一部分属性。为了清楚起见,我删除了两者。

OldNewThing blog at MSDN 上有一系列关于 DDLImport 和 DLLExport 的文章

感谢@FyodorSoikin、@ildjarn、@BentTranberg、@CurtNichols 和 @vcsjones

关于.net - 在 Linux/ARM 上使用 pinvoke 和 C 函数回调的 F# 委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37843094/

相关文章:

recursion - F#递归成员函数: "How to Define it correctly"

f# - 将字典键序列转换为集合

c# - .NET 中是否有与 WinAPI GetColorDirectory 等效的函数?

c# - 使用 .NET C# 绘制实时数据图表

c# - Visual Studio 线程窗口为空?

c - 通过ARM(使用GCC)获取C中汇编标签的地址

c - 通过计算复制 C 数组的更快方法

c - C语言中,结构,定义上的细微差别

F# 尾递归,为什么不写一个 while 循环?

.net - 如果使 IE8 模拟 IE7 的 head 标签不起作用怎么办?