【问题标题】:How to map a C array to C#?如何将 C 数组映射到 C#?
【发布时间】:2010-12-08 16:43:21
【问题描述】:

我的问题与尝试从 C# 调用用 C 编写的函数有关。我查看了 C 库附带的头文件,以了解 C dll 中存在的函数。这是我看到的:

C 代码(用于名为“LocGetLocations”的函数):

typedef enum {
    eLocNoError,
    eLocInvalidCriteria,
    eLocNoMatch, 
    eLocNoMoreLocations,
    eLocConnectionError, 
    eLocContextError,
    eLocMemoryError
} tLocGetStatus; 

typedef void *tLocFindCtx;

typedef void *tLocation;    

PREFIX unsigned int POSTFIX LocGetLocations
(
    tLocFindCtx pCtx, 
    tLocation *pLoc,
    unsigned int pNumLocations,
    tLocGetStatus *pStatus
);

在 C# 中,我有这个:

[DllImport(@"VertexNative\Location.dll")]
public static extern uint LocGetLocations(IntPtr findContext, out byte[] locations, uint numberLocations, out int status);

问题是我不太清楚如何处理 C# 中的 pLoc 参数。我将它作为字节数组引入,尽管我不确定这是否正确。 C 库的文档说该参数是指向句柄数组的指针。

如何在 C# 端获取数组并访问其数据?

我在 C 中给出的示例如下所示:

tLocation lLocation[20];

// other stuff

LocGetLocations(lCtx, lLocation, 20, &lStatus)

任何帮助将不胜感激!

【问题讨论】:

  • 如果它是句柄数组,您需要将其设为 IntPtr 数组。
  • pinvoke.net/index.aspx 有很多例子。

标签: c# c++ interop pinvoke marshalling


【解决方案1】:

通常,唯一重要的是参数的大小。我记得枚举是 C 中的整数,所以你可以简单地使用它。或者更好的是,在 C# 中重新创建相同的枚举,我认为它会起作用。需要记住的一件事是,在处理复杂结构时,需要使用属性来告诉框架所需的成员对齐方式。

【讨论】:

    【解决方案2】:

    最后,这个签名有效:

    [DllImport(@"VertexNative\Location.dll")]
    public static extern uint LocGetLocations(IntPtr findContext, [Out] IntPtr[] locations, uint numberLocations, out int status);
    

    我可以这样称呼它(需要一些重构):

    IntPtr[] locations = new IntPtr[20];
    int status;
    // findContext is gotten from another method invocation
    uint result = GeoCodesNative.LocGetLocations(findContext, locations, 20, out status);
    

    感谢您的帮助!

    【讨论】:

    • 注意,我认为是我使用了“out”关键字让我感到困惑。删除它让我走得更远。我猜这是有道理的,因为数组是一开始的引用类型,不需要将局部变量分配给方法中的新值。
    • @Nick:您想要的是将 [OutAttribute](或只是 [Out])添加到 IntPtr[] 位置。这告诉编组器只在输出时复制,而不是在输入和输出时复制。这样可以避免发生不必要的块副本。
    • 添加到 IntPtr[] 位置会给我一个运行时错误。
    • 我编辑了您的答案以说明我的意思。不是out[Out]
    • out 是一个参数修饰符。 [Out] 是一个属性,具体来说是System.Runtime.InteropServices.OutAttribute。这个属性不是由编译器检查的,而是在运行时由 CLR 编组器检查的。编组意味着分配非托管内存,从托管内存复制到非托管,调用非托管函数,然后从非托管复制回托管。 [In][Out] 属性允许您控制发生的复制,因为默认情况下两者都是打开的。
    猜你喜欢
    • 2023-01-01
    • 2022-01-11
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-16
    相关资源
    最近更新 更多