c++ - F#:使用自定义类型参数调用 native 函数

标签 c++ f# interop native

我正在从 F# 调用 native DLL。事实证明,对于不带参数或只带基本类型的函数来说,这非常简单,但我在让我的代码正常工作时遇到了很多麻烦。

C++ 代码是:

struct CatDef
{
    uint8_t cat;
    uint8_t arrogance;

    CatDef() : cat(0), arrogance(0) {}
};

struct HomeInfo
{
    enum { MAX_CATDEF = 5 };
    enum {
        LONE_CAT = 0x01,
    };
    CatDef  cd[MAX_CATDEF];
    uint8_t  notoriety;
    uint8_t  etc;

    HomeInfo()
        : notoriety(0), etc(0)
    {
        memset(cd, 0, sizeof(cd));
    }

    size_t howBig() const
    {
        size_t hb = 0;
        for (; hb < MAX_CATDEF; ++hb)
            if (!cd[hb].cat)
                break;
        return hb;
    }
};

struct HomeQuery
{
    char addr[ADDR_LENGTH];    // ADDR_LENGTH is 1024
    char verifiedAddr[ADDR_LENGTH];
    HomeInfo homeData;
    unsigned int id;
    Status  st;    // Status is an enum

    HomeQuery()
        : homeData()
        , id(0)
        , st(Unprocessed)
    {
        memset(addr, 0, sizeof(addr));
        memset(verifiedAddr, 0, sizeof(verifiedAddr));
    }
};

__declspec(dllexport) bool GetHomeInfo(
    HomeQuery* queries, size_t qCount, void (*callback)(HomeQuery*, size_t) = 0);

到目前为止,我对 F# 有这个:

[<Struct>]
type CatDef =
    [<DefaultValue>]
    val mutable cat : uint8
    [<DefaultValue>]
    val mutable arrogance : uint8

[<Struct>]
type HomeInfo =
    [<DefaultValue; MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)>]
    val mutable cd : CatDef array
    [<DefaultValue>]
    val mutable notoriety : uint8
    [<DefaultValue>]
    val mutable etc : uint8

[<Struct>]
type HomeQuery =
    [<DefaultValue; MarshalAs(UnmanagedType.LPStr, SizeConst = 1024)>]
    val mutable addr : string
    [<DefaultValue; MarshalAs(UnmanagedType.LPStr, SizeConst = 1024)>]
    val mutable verifiedAddr : string
    [<DefaultValue>]
    val mutable homeData : HomeInfo
    [<DefaultValue>]
    val mutable id : uint32
    [<DefaultValue>]
    val mutable st : int

type HomeQueryCallback = delegate of (HomeQuery array * uint) -> unit

module private Wrapper =
    [<DllImport(
        "Homes.dll",
        EntryPoint = "?GetHomeInfo@People@@NA_WBYUHomeQuery@1@IP6AX0I@Z@Z",
        CallingConvention = CallingConvention.Cdecl)>]
    extern bool GetHomeInfo(HomeQuery[] queries, uint qCount, HomeQueryCallback callback)

[<RequireQualifiedAccess>]
module HomeLib =
    let getHomeInfo queries = Wrapper.GetHomeInfo (queries, uint queries.Length, null)

关于类型编码的规则,我一直引用https://learn.microsoft.com/en-us/dotnet/standard/native-interop/type-marshaling#default-rules-for-marshaling-common-types .

当我打电话HomeLib.getHomeInfo时并进入 native 库 (Homes.dll),我看到 HomeQuery 中第一个(也是唯一一个)项目的字段数组包含乱码信息。 ( qCountcallback 未损坏,并且包含预期值。)如您所见,我尝试添加 MarshalAs属性到一些领域,但这并没有产生任何积极的效果。两者都没有用 [<StructLayout(LayoutKind.Sequential)>] 装饰任何类型。 .

最佳答案

没关系,我已经解决了。

对于任何可能关心的人来说,我的 F# 代码只需进行一些更改即可工作:

  1. 我改变了UnmanagedType.LPStrUnmanagedType.ByValTStr
  2. extern函数声明,我装饰HomeQuery[] queries[<In; Out>] (即 [<In; Out>]HomeQuery[] queries )。

仅此而已。

关于c++ - F#:使用自定义类型参数调用 native 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63276765/

相关文章:

f# - (F#) 从 CryptoStream 读取所有字节的最流畅方式

unit-testing - 如何保证 FsCheck 的重现性

.net - 如何从纯 C 应用程序重用 .Net 程序集

C++:在数字中查找特定数字

c++ - 为什么该区域返回为 0?

c++ - 无法在 ubuntu 12.04 64 位中使用 gloox 库

c++ - Qt SIGNAL->SLOTS 机制

使用类型约束的 F# 模式匹配

c# - 使用包含来自托管代码的指针的 Fortran 类型

c# - 如何将数字写入文件并使其在 Java 和 C# 之间可读