f# - 可能的 F# 交互式 PInvoke 错误

标签 f# pinvoke f#-interactive

在尝试向同事证明可以使用 F# 中的 C++ 类时,我提出了以下概念证明。第一个片段是他为挑战提供的代码,下面的代码片段是我在 F# 中的实现。

namespace testapp {
    struct trivial_foo {
        int bar;
        __declspec(dllexport) void set(int n) { bar = n; }
        __declspec(dllexport) int get() { return bar; }
    }
}
open System.Runtime.InteropServices

type TrivialFoo =
    struct
        val bar: int
        new(_bar: int) = { bar = _bar }
    end

[<DllImport("Win32Project2.dll", EntryPoint="?get@trivial_foo@testapp@@QAEHXZ", CallingConvention = CallingConvention.ThisCall)>]
extern int trivial_foo_get(TrivialFoo& trivial_foo)

[<DllImport("Win32Project2.dll", EntryPoint="?set@trivial_foo@testapp@@QAEXH@Z", CallingConvention = CallingConvention.ThisCall)>]
extern void trivial_foo_set(TrivialFoo& trivial_foo, int bar)

type TrivialFoo with
    member this.Get() = trivial_foo_get(&this)
    member this.Set(bar) = trivial_foo_set(&this, bar)

在 Visual Studio 中调试或作为独立程序运行时,可以预见到:TrivialFoo.Get返回 bar 的值和 TrivialFoo.Set分配给它。然而,当从 F# Interactive 运行时,TrivialFoo.Set不会设置字段。我怀疑它可能与从非托管代码访问托管内存有关,但这并不能解释为什么它只在使用 F# Interactive 时发生。有谁知道这里发生了什么?

最佳答案

我不认为这种概念证明是互操作性的良好证明。您最好从您的 C++ 项目创建 DLL 导出定义并改用去修饰的名称。

作为 PoC:F# 创建适合 CLI 的 MSIL,因此它可以与 any other CLI language out there 互操作.如果这还不够,并且您想要本地到网络的互操作,请考虑使用 COM,或者如上所述,在您的 C++ 上使用 DLL 导出定义。我个人不会尝试按照您在此处建议的方式与 C++ 类定义进行互操作,有更简单的方法可以做到这一点。

或者,只需将您的 C++ 项目更改为 .NET C++ 项目,您就可以直接从 F# 访问这些类,同时仍然拥有 C++ 的强大功能。

当然,您可能仍然想知道为什么该示例不在 FSI 中运行。您可以通过运行以下命令来查看答案提示:

> System.IO.Directory.GetCurrentDirectory();;
val it : string = "R:\TMP"

要解决此问题,您有多种选择:
  • 复制 Win32Project2.dll到那个目录
  • 将它所在的任何路径添加到 PATH
  • 使用绝对路径
  • 使用编译时常量
  • 或使用环境变量(路径将被扩展)
  • 动态定位dll并动态绑定(bind)(复杂)

  • 复制可能是这些解决方案中最简单的。

    由于 FSI 是一个 REPL ,它可能不适合需要多个项目、库或其他复杂配置的此类任务。您可以考虑投票 this FSI request for support for #package 导入 NuGet 包,可用于简化此类任务。

    关于f# - 可能的 F# 交互式 PInvoke 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27261988/

    相关文章:

    .net - Rx 订阅和垃圾收集

    c# - 调用 C++ 函数时尝试读取/写入 protected 内存错误

    c# - 如何使用.net更改Windows2k8的时区设置

    F# 交互 : Reference a project in currently open solution

    F# 为什么我不能在 F# 交互中使用 :? 运算符?

    f# - 为什么 F# 不允许 C# 允许的多个属性?

    data-structures - 在 F# 中执行可变数据结构(例如,跳过列表、伸展树(Splay Tree))的正确方法是什么?

    generics - ToString 为单位值抛出 NullReferenceException ()

    c# - Pinvoke DeviceIoControl 参数

    f# - 在 F# 交互中更改输出结果的格式