封送指向字符串数组的指针

Posted

技术标签:

【中文标题】封送指向字符串数组的指针【英文标题】:Marshaling pointer to an array of strings 【发布时间】:2009-08-24 17:55:04 【问题描述】:

我在编组指向字符串数组的指针时遇到了一些麻烦。它看起来像这样无害:

typedef struct

    char* listOfStrings[100];
 UnmanagedStruct;

这实际上嵌入在另一个结构中,如下所示:

typedef struct

    UnmanagedStruct umgdStruct;
 Outerstruct;

非托管代码回调托管代码,并将 Outerstruct 作为 IntPtr 返回,其中分配了内存并填充了值。

托管世界:

[StructLayout(LayoutKind.Sequential)]
public struct UnmanagedStruct

    [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr, SizeConst=100)]
    public string[] listOfStrings;


[StructLayout(LayoutKind.Sequential)]
public struct Outerstruct

    public UnmanagedStruct ums;


public void CallbackFromUnmanagedLayer(IntPtr outerStruct)

    Outerstruct os = Marshal.PtrToStructure(outerStruct, typeof(Outerstruct));
    // The above line FAILS! it throws an exception complaining it cannot marshal listOfStrings field in the inner struct and that its managed representation is incorrect!

如果我将 listOfStrings 更改为简单的 IntPtr,那么 Marshal.PtrToStructure 可以工作,但现在我无法翻入 listOfStrings 并一一提取字符串。

【问题讨论】:

【参考方案1】:

编组除非常基本的字符串之外的任何内容都很复杂,并且充满了难以发现的副案例。通常最好在结构定义中使用安全/简单的路线,并添加一些包装器属性来整理一下。

在这种情况下,我将使用 IntPtr 数组,然后添加一个将它们转换为字符串的包装器属性

[StructLayout(LayoutKind.Sequential)]
public struct UnmanagedStruct

    [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr, SizeConst=100)]
    public IntPtr[] listOfStrings;

    public IEnumerable<string> Strings  get  
      return listOfStrings.Select(x =>Marshal.PtrToStringAnsi(x));
    

【讨论】:

Jared 感谢您的验证!在看到你的问题之前,我刚刚发布了我自己问题的答案。一个问题——如何在帖子中格式化我的代码?他们看起来都一团糟,总得有人编辑和纠正。 @Dilip,选择您的代码 sn-p 并按 CTRL+K。这将通过缩进所有 4 spcaes 来修复格式 @Jared:只是快速跟进。如果我使用 UnmanagedType.LPArray,代码会继续爆炸。只有 UnmanagedType.ByValArray 有效。我现在明白 KeeperOfTheSoul 在他/她的 cmets 中暗示了什么。【参考方案2】:

好的..我似乎已经开始工作了。它应该被编组为 IntPtr[]

这似乎有效:

[StructLayout(LayoutKind.Sequential)] 
public struct UnmanagedStruct 
 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=100)] 
    public IntPtr[] listOfStrings; 


for (int i = 0; i < 100; ++i)

    if (listOfstrings[i] != IntPtr.Zero)
        Console.WriteLine(Marshal.PtrToStringAnsi(listOfStrings[i]));
    

【讨论】:

ByValArray == 就地数组,LPArray == 指向数组的指针。虽然 SizeConst 仍然应该与 LPArray 一起使用,但编组时的错误有点奇怪。

以上是关于封送指向字符串数组的指针的主要内容,如果未能解决你的问题,请参考以下文章

修改指向指针的数组中对应元素的字符出现异常,该如何解决?

MIDL相关

C 语言字符串 一级指针 内存模型 ( 指定大小字符数组 | 未指定大小字符数组 | 指向常量字符串的指针 | 指向堆内存的指针 )

C# 结构到字节数组封送产生 19 个元素而不是 20 个

数组名相当于一个指针,哪数组指针char *p[],不就变成一个二级指针?

《C语言程序设计》指针