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

Dil*_*lip 6 c# pinvoke unmanaged marshalling

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

typedef struct
{
    char* listOfStrings[100];
} UnmanagedStruct;
Run Code Online (Sandbox Code Playgroud)

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

typedef struct
{
    UnmanagedStruct umgdStruct;
} Outerstruct;
Run Code Online (Sandbox Code Playgroud)

非托管代码回调到托管代码,并将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!
}
Run Code Online (Sandbox Code Playgroud)

如果我将listOfStrings改为简单地为IntPtr,那么Marshal.PtrToStructure可以工作,但现在我无法翻录到listOfStrings并逐个提取字符串.

Jar*_*Par 5

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

在这种情况下,我将使用 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));
    }
}
Run Code Online (Sandbox Code Playgroud)


Dil*_*lip 1

好吧..我似乎已经开始工作了。它应该被封送为 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]));
}    
Run Code Online (Sandbox Code Playgroud)