从C++;到C#? 在我的C代码中,我试图从一个传统的C++ DLL(一个不能更改的代码)中获取一个结构数组。 在C++代码中,结构定义如下: struct MyStruct { char* id; char* description; }; [StructLayout(LayoutKind.Sequential)] public class MyStruct { [MarshalAsAttribute(UnmanagedType.LPStr)] // <-- also tried without this private string _id; [MarshalAsAttribute(UnmanagedType.LPStr)] private string _description; } int structuresCount = ...; IntPtr myStructs = GetMyStructures(); int structSize = Marshal.SizeOf(typeof(MyStruct)); // <- returns 8 in my case for (int i = 0; i < structuresCount; i++) { IntPtr data = new IntPtr(myStructs.ToInt64() + structSize * i); MyStruct ms = (MyStruct) Marshal.PtrToStructure(data, typeof(MyStruct)); ... } 0: id (char*) <---- [MyStruct 1] 4: description (char*) 8: id (char*) <---- [MyStruct 2] 12: description (char*) 16: id (char*) <---- [MyStruct 3] ... for (int i = 0; i < structuresCount; i++) { MyStruct ms = (MyStruct) Marshal.PtrToStructure(myStructs, typeof(MyStruct)); ... myStructs += Marshal.SizeOf(ms); }

从C++;到C#? 在我的C代码中,我试图从一个传统的C++ DLL(一个不能更改的代码)中获取一个结构数组。 在C++代码中,结构定义如下: struct MyStruct { char* id; char* description; }; [StructLayout(LayoutKind.Sequential)] public class MyStruct { [MarshalAsAttribute(UnmanagedType.LPStr)] // <-- also tried without this private string _id; [MarshalAsAttribute(UnmanagedType.LPStr)] private string _description; } int structuresCount = ...; IntPtr myStructs = GetMyStructures(); int structSize = Marshal.SizeOf(typeof(MyStruct)); // <- returns 8 in my case for (int i = 0; i < structuresCount; i++) { IntPtr data = new IntPtr(myStructs.ToInt64() + structSize * i); MyStruct ms = (MyStruct) Marshal.PtrToStructure(data, typeof(MyStruct)); ... } 0: id (char*) <---- [MyStruct 1] 4: description (char*) 8: id (char*) <---- [MyStruct 2] 12: description (char*) 16: id (char*) <---- [MyStruct 3] ... for (int i = 0; i < structuresCount; i++) { MyStruct ms = (MyStruct) Marshal.PtrToStructure(myStructs, typeof(MyStruct)); ... myStructs += Marshal.SizeOf(ms); },c#,.net,c++,interop,marshalling,C#,.net,C++,Interop,Marshalling,我调用的方法(get_my_structures)返回指向MyStruct结构数组的指针: MyStruct* get_my_structures() { ... } 还有一个方法返回结构的数量,所以我知道返回了多少个结构 在我的C#代码中,我对MyStruct的定义如下: struct MyStruct { char* id; char* description; }; [StructLayout(LayoutKind.Sequential)] public c

我调用的方法(get_my_structures)返回指向MyStruct结构数组的指针:

MyStruct* get_my_structures()
{
    ...
}
还有一个方法返回结构的数量,所以我知道返回了多少个结构

在我的C#代码中,我对MyStruct的定义如下:

struct MyStruct
{
    char* id;
    char* description;
};
[StructLayout(LayoutKind.Sequential)]  
public class MyStruct
{
  [MarshalAsAttribute(UnmanagedType.LPStr)]    // <-- also tried without this
  private string _id;
  [MarshalAsAttribute(UnmanagedType.LPStr)]
  private string _description;
}
int structuresCount = ...;
IntPtr myStructs = GetMyStructures();
int structSize = Marshal.SizeOf(typeof(MyStruct));    // <- returns 8 in my case
for (int i = 0; i < structuresCount; i++)
{
    IntPtr data = new IntPtr(myStructs.ToInt64() + structSize * i);
    MyStruct ms = (MyStruct) Marshal.PtrToStructure(data, typeof(MyStruct));
    ...
}
0: id (char*)           <---- [MyStruct 1]
4: description (char*)
8: id (char*)           <---- [MyStruct 2]
12: description (char*)
16: id (char*)          <---- [MyStruct 3]
...
for (int i = 0; i < structuresCount; i++)
{
    MyStruct ms = (MyStruct) Marshal.PtrToStructure(myStructs, typeof(MyStruct));
    ...
    myStructs += Marshal.SizeOf(ms);
}
最后,获取MyStruct结构数组的代码如下所示:

struct MyStruct
{
    char* id;
    char* description;
};
[StructLayout(LayoutKind.Sequential)]  
public class MyStruct
{
  [MarshalAsAttribute(UnmanagedType.LPStr)]    // <-- also tried without this
  private string _id;
  [MarshalAsAttribute(UnmanagedType.LPStr)]
  private string _description;
}
int structuresCount = ...;
IntPtr myStructs = GetMyStructures();
int structSize = Marshal.SizeOf(typeof(MyStruct));    // <- returns 8 in my case
for (int i = 0; i < structuresCount; i++)
{
    IntPtr data = new IntPtr(myStructs.ToInt64() + structSize * i);
    MyStruct ms = (MyStruct) Marshal.PtrToStructure(data, typeof(MyStruct));
    ...
}
0: id (char*)           <---- [MyStruct 1]
4: description (char*)
8: id (char*)           <---- [MyStruct 2]
12: description (char*)
16: id (char*)          <---- [MyStruct 3]
...
for (int i = 0; i < structuresCount; i++)
{
    MyStruct ms = (MyStruct) Marshal.PtrToStructure(myStructs, typeof(MyStruct));
    ...
    myStructs += Marshal.SizeOf(ms);
}
int-structuresunt=。。。;
IntPtr myStructs=GetMyStructures();

int structSize=Marshal.SizeOf(typeof(MyStruct));// 对于char*,必须使用
UnmanagedType.LPTStr
。对于非常量字符*,建议使用
StringBuilder
: 和字符集规范:

[StructLayout(LayoutKind.Sequential, Charset = CharSet.Auto)]  
public class MyStruct
{
  [MarshalAsAttribute(UnmanagedType.LPTStr)]
  private StringBuilder _id;
  [MarshalAsAttribute(UnmanagedType.LPTStr)]
  private StringBuilder _description;
}
至于DllImport声明,你试过了吗

[DllImport("legacy.dll", EntryPoint="get_my_structures")]
public static extern MarshalAs(UnmanagedType.LPArray) MyStruct[] GetMyStructures();
?

此外,如果前一个不起作用,请将其保留在IntPtr中,并尝试按如下方式Mashal返回的结构:

struct MyStruct
{
    char* id;
    char* description;
};
[StructLayout(LayoutKind.Sequential)]  
public class MyStruct
{
  [MarshalAsAttribute(UnmanagedType.LPStr)]    // <-- also tried without this
  private string _id;
  [MarshalAsAttribute(UnmanagedType.LPStr)]
  private string _description;
}
int structuresCount = ...;
IntPtr myStructs = GetMyStructures();
int structSize = Marshal.SizeOf(typeof(MyStruct));    // <- returns 8 in my case
for (int i = 0; i < structuresCount; i++)
{
    IntPtr data = new IntPtr(myStructs.ToInt64() + structSize * i);
    MyStruct ms = (MyStruct) Marshal.PtrToStructure(data, typeof(MyStruct));
    ...
}
0: id (char*)           <---- [MyStruct 1]
4: description (char*)
8: id (char*)           <---- [MyStruct 2]
12: description (char*)
16: id (char*)          <---- [MyStruct 3]
...
for (int i = 0; i < structuresCount; i++)
{
    MyStruct ms = (MyStruct) Marshal.PtrToStructure(myStructs, typeof(MyStruct));
    ...
    myStructs += Marshal.SizeOf(ms);
}
for(int i=0;i
我通常通过反复试验来解决这些问题。确保在StructLayout上设置了CharSet属性,我会尝试UnmanagedType.LPTStr,它似乎更适合char*,尽管我不知道为什么

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]  
public class MyStruct
{
    [MarshalAsAttribute(UnmanagedType.LPTStr)]
    private string _id;
    [MarshalAsAttribute(UnmanagedType.LPTStr)]
    private string _description;
}

我认为,除给出的答案外,还需要提供长度,即 [MarshalAsAttribute(UnmanagedType.LPTStr),SizeConst=,ArraySubType=System.Runtime.InteropServices.UnmanagedType.AnsiBStr]


这是一个尝试和错误得到这一权利,也是另一件事,在一些WinAPI调用,期望字符串参数,通常是一个REF参数,它可能值得你尝试String BuudRead类……除了这一点我在这里提到的其他东西都没有想到…希望这有帮助,汤姆。我会改变结构。使用IntPtr代替字符串等:

[StructLayout(LayoutKind.Sequential)] public class MyStruct { private IntPtr _id; private IntPtr _description; } [StructLayout(LayoutKind.Sequential)] 公共类MyStruct { 私有IntPtr_id; 私有IntPtr_描述; }
<> P>数组的每个值可以用MARHAL..ptrtoString手动考虑到字符串,考虑到字符集等。

< P>我不能重现你的问题,这使我怀疑它实际上是C++的。这是我尝试的完整源代码

dll.cpp
-使用
cl.exe/LD
编译:

extern "C" {

struct MyStruct
{
    char* id;
    char* description;
};

__declspec(dllexport)
MyStruct* __stdcall get_my_structures()
{
    static MyStruct a[] =
    {
        { "id1", "desc1" },
        { "id2", "desc2" },
        { "id3", "desc3" }
    };
    return a;

}

}
test.cs
-使用
csc.exe/platform:x86编译:

using System;
using System.Runtime.InteropServices;


[StructLayout(LayoutKind.Sequential)]  
public class MyStruct
{
  [MarshalAsAttribute(UnmanagedType.LPStr)]
  public string _id;
  [MarshalAsAttribute(UnmanagedType.LPStr)]
  public string _description;
}


class Program
{
    [DllImport("dll")]
    static extern IntPtr get_my_structures();

    static void Main()
    {
        int structSize = Marshal.SizeOf(typeof(MyStruct));
        Console.WriteLine(structSize);

        IntPtr myStructs = get_my_structures();
        for (int i = 0; i < 3; ++i)
        {
            IntPtr data = new IntPtr(myStructs.ToInt64() + structSize * i);
            MyStruct ms = (MyStruct) Marshal.PtrToStructure(data, typeof(MyStruct));

            Console.WriteLine();
            Console.WriteLine(ms._id);
            Console.WriteLine(ms._description);
        }
    }
}
使用系统;
使用System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
公共类MyStruct
{
[MarshalAsAttribute(UnmanagedType.LPStr)]
公共字符串_id;
[MarshalAsAttribute(UnmanagedType.LPStr)]
公共字符串描述;
}
班级计划
{
[DllImport(“dll”)]
静态外部IntPtr获取我的结构();
静态void Main()
{
int structSize=Marshal.SizeOf(typeof(MyStruct));
Console.WriteLine(structSize);
IntPtr myStructs=获取我的结构();
对于(int i=0;i<3;++i)
{
IntPtr data=newintptr(myStructs.ToInt64()+structSize*i);
MyStruct ms=(MyStruct)Marshal.PtrToStructure(数据,typeof(MyStruct));
Console.WriteLine();
控制台写入线(ms._id);
控制台写入线(ms.\U说明);
}
}
}
这将正确打印出所有3个结构


你能显示填充结构的C++代码吗?你可以直接从C++调用它并得到正确的结果并不一定意味着它是正确的。例如,可以返回指向堆栈分配结构的指针。当进行直接调用时,您会得到一个技术上无效的指针,但数据可能会保留下来。在执行P/Invoke封送处理时,当P/Invoke数据结构试图从中读取值时,堆栈可能会被其覆盖

char*以null结尾,因此我不提供长度。这就是为什么我们有UnmanagedType.LPWStr和UnmanagedType.LPTStr。如果要提供长度,还必须使其非常大,以便不截断任何数据。这不是一个优雅的解决方案。如果我尝试使用StringBuilder,当我尝试这样做时,我会得到一个ArgumentException:int itemSize=Marshal.SizeOf(typeof(MyStruct));错误消息是“类型'MyStruct'不能作为非托管结构封送;无法计算有意义的大小或偏移量”。@vladimir:您使用的是
UnmanagedType.LPTStr
?另外:尝试像其他建议的那样指定
字符集
。“字符串是结构的有效成员;但是,StringBuilder缓冲区在结构中无效。”->@hjb417:I stand corrected。。。似乎StrigBuudor只能用于DllImport函数的语句中,它使用char *作为参数。@弗拉迪米尔:我猜问题不是与结构的声明有关,而是用你把返回的ItpTR转换成你的单独结构的方式。我已经更新了我的问题,添加了C++代码。既然你已经表明互操作部分本身(也不是C语言侧)没有什么错误,那么它确实是合乎逻辑的,它必须是C++代码。听起来像是可行的方法,但不幸的是它似乎没有解决我的问题。即使使用IntPtr成员,这些成员在除第一个之外的所有结构中仍然具有相同的(无效)值。