如何将 C 数组映射到 C#?
Posted
技术标签:
【中文标题】如何将 C 数组映射到 C#?【英文标题】:How to map a C array to 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 有很多例子。
【参考方案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]
属性允许您控制发生的复制,因为默认情况下两者都是打开的。以上是关于如何将 C 数组映射到 C#?的主要内容,如果未能解决你的问题,请参考以下文章