c# - PInvoke - 从指针编码结构数组

标签 c# c pointers pinvoke

我正在尝试在 this question 上寻找答案

我的结构在 C 中看起来像这样

typedef struct drive_info_t {
    unsigned char drive_alias[32];
} drive_info_t;

我的函数在 C 中看起来像这样

unsigned int get_drive_info_list(drive_info_t **list, unsigned int *item_count) {
    //fill list in native C

    //print out in native C
    printf("list.alias - %s\r\n",list[i]->drive_alias);
}

我的 C# 结构如下所示

[StructLayout(LayoutKind.Sequential)]
public struct drive_info_t
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public byte[] drive_alias;
}

我的 C# 函数声明如下所示

[DllImport("mydll.dll", EntryPoint = "get_drive_info_list", CallingConvention = CallingConvention.Cdecl)]
public static extern uint GetDriveInfoList(out System.IntPtr ptr_list_info, out System.IntPtr ptr_count);

我正在这样调用 C# 函数

IntPtr ptr_list_info = IntPtr.Zero;
IntPtr ptr_cnt = IntPtr.Zero;

ret = api.GetDriveInfoList(out ptr_list_info, out ptr_cnt);

我正在像这样编码返回的指针

nAlloc = ptr_cnt.ToInt32();

int szStruct = Marshal.SizeOf(typeof(api.drive_info_t));
api.drive_info_t[] localStructs = new api.drive_info_t[nAlloc];

for (int i = 0; i < nAlloc; i++)
{
    localStructs[i] = (api.drive_info_t)Marshal.PtrToStructure(ptr_list_info, typeof(api.drive_info_t));
    ptr_list_info = new IntPtr(ptr_list_info.ToInt32() + (szStruct));
}

像这样打印结构别名

for (uint i = 0; i < localStructs.Length; i++)
{    
    Console.WriteLine("list.alias - {0}", System.Text.Encoding.Default.GetString(localStructs[i].drive_alias));
}

谢谢你一直陪着我..

这是我在 C# 控制台应用程序上的输出结果。您可以看到 native C dll 将其值打印到控制台,但我的编码(marshal)处理在某处搞砸了:

======================== C values ============================
list.alias - drv1
list.alias - drv2
list.alias - drv3
list.alias - drv4
======================== C# values ============================
list.alias - drv1
list.alias - o£Q95drv2
list.alias -         o£Q95drv3
list.alias -                 o£Q95drv4

我不知道这些垃圾文本和偏移量是从哪里来的。

我负责 .Net 方面,其他团队成员可以根据需要更改原生 C,但原生 C 更改需要跨平台 OSX/Windows/Linux。

提前致谢。

最佳答案

这是一个很好的例子,说明了为什么参数的类型没有定义接口(interface)。考虑

drive_info_t **list

这可能是一个指向结构数组的指针。在这种情况下,大概数组是由被调用者分配的。这就是为什么使用指向数组的指针而不是数组的原因。

或者它可以是指向结构的指针数组。这里数组将由调用者分配,结构可以由被调用者或调用者分配。我们无从得知。

我们可以看出您的接口(interface)接受一个结构指针数组。看这段代码:

list[i]->drive_alias

很明显,list 是指向结构的指针数组。

这告诉您您的代码是错误的。您使用了错误的模板,因为您错误地识别了语义。您的下一步是返回接口(interface)文档和任何示例调用代码以准确了解语义是什么。谁分配和释放什么。

几乎可以肯定,您将使用 IntPtr[] 来编码数组,但除此之外,我们无法说出会发生什么。我猜想调用者分配了结构但不依赖于猜测。阅读文档和示例调用代码。

除此之外,第二个参数应该是 ref uint 或者可能是 out uint,具体取决于函数的语义。同样,这是我们无法解决的问题。

关于c# - PInvoke - 从指针编码结构数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38648173/

相关文章:

pointers - go map,键是字符串,值是指向结构的指针

c# - 使用 xml 填充对象的设计模式

c# - 通过单击 asp.net 中的按钮在网格中添加多行

c# - 如何使用 ASP.Net Web Api 2 进行部分响应

c - 解析前两个值时出现 Libconfig 错误

c - 索引二维矩阵(指针样式)- 错误 : cant index

c# - 新应用程序域的类型

c - 在 header 中声明结构使其成为全局结构

C函数不可调用

c++ - 使用已删除的 shared_ptr 中的原始指针的未定义行为?