[StructLayout = LayoutKind.Sequential]
public struct A
{
...
...
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public B[] b
}[StructLayout = LayoutKind.Sequential]
public struct B
{
...
...
}[DllImport("...")]
public static extern int Test(..., [In, Out] ref A[] a);我跟踪到Dll里调试的时候发现结构A中的数组b中的值全部丢掉了,而且在Dll里面为a赋值也都传不出来,请问在调用外部DLL时传递这种较为复杂的结构的数组该如何封送结构?谢谢!

解决方案 »

  1.   

    C++中的结构和函数声明:typedef struct
    {
    ...
    ...
    }typedef struct
    {
    ...
    ...
    B b[10];
    } A;extern "C" __declspec(dllexport) int Test(..., A *a);
      

  2.   

    不知道你现在有没有搞定?我把我的理解写出来供你参考类似嵌套结构有两种处理方式:1 嵌入到另一个结构中的结构可以通过将嵌入结构的元素直接放置在主结构中而单一化 2 该结构也可保留为嵌入结构用方法1肯定没问题,所以你可以在A中不要B[] b,而是写10个B b1;B b2;...如果还不行,就完全展开(虽然很麻烦,但总是可行的嘛,呵呵)方法2的声明中加上ArraySubType试试看
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10,ArraySubType =UnmanagedType.Struct)]
    public B[] b另外你的调用的代码不知道是否有错,最好也贴出来好运!
      

  3.   

    请参考msdn上面的例子(请留意结构MYPERSON3的使用和说明)ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/cpguide/html/cpconstructssample.htm该示例说明如何传递指向另一个结构的结构,如何传递具有嵌入结构的结构,以及如何传递具有嵌入数组的结构MyPerson3 包含作为嵌入结构的 MyPerson。嵌入到另一个结构中的结构可以通过将嵌入结构的元素直接放置在主结构中而单一化;该结构也可保留为嵌入结构,此示例中即如此处理
      

  4.   

    要知道你要调用的DLL以前C的格式,才能告诉你C#怎么封装啥
      

  5.   

    To Jim3(Jim):
    1、单一化不可行,目前我们系统中的很多地方都是需要与其他公司对接的,我们不可能要求其他公司来修改他们定义的接口中的结构,当然,我们可以在其他公司的Dll之上再自己用VC++再包一层,将结构中的元素单一化,但类似的接口很多,还有不少比上面写的更复杂的结构,结构里嵌结构嵌了四五层,如果这样做的话,工作量很大,而且代码维护起来也很困难。
    2、在结构上增加ArraySubType属性的方法我也试过了,系统报错“无法封送类型 B 的字段 b:该类型无法作为结构字段进行封送处理。”
    3、调用的代码应该没有问题,结构中所有的字段的值都赋了初始值,跟踪调试的时候在C#中都是正确的
    4、MSDN里的那个例子我看过了,但那个传递的只是“具有嵌入结构的结构”,而我们现在要解决的是“具有嵌入结构的结构的数组”
    谢谢!To Tony_lau111082(刘寓)
    C++中的结构和函数的定义在2楼
      

  6.   

    强烈建议使用XML封装。
    DOTNET下还弄结构,实在是太费力了。
      

  7.   

    刚才又做了个测试:
    C#代码:
    using System;
    using System.Runtime.InteropServices;namespace TestDll
    {
    [ StructLayout( LayoutKind.Sequential) ]
    public struct A
    {
    public int a;
    // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10, ArraySubType = UnmanagedType.Struct)]
    public B[] b;
    } [ StructLayout( LayoutKind.Sequential) ]
    public struct B
    {
    public int a;
    public int b;
    } [ StructLayout( LayoutKind.Sequential) ]
    public struct C
    {
    public int a;
    public B b;
    } public class Class1
    {
    const string DLL_PATH = @"D:\Test\Debug\Test.dll"; [DllImport(DLL_PATH)]
    public static extern int Test([In, Out] ref A[] a); [DllImport(DLL_PATH)]
    public static extern int TestA([In, Out] ref A a); [DllImport(DLL_PATH)]
    public static extern int TestB(B[] b); [DllImport(DLL_PATH)]
    public static extern int TestC(C c); [DllImport(DLL_PATH)]
    public static extern int TestBB(B[,] b);
    }
    }C++中.h文件的代码:
    typedef struct
    {
    int a;
    int b;
    } B;typedef struct
    {
    int a;
    B b[10];
    } A;typedef struct
    {
    int a;
    B b;
    } C;extern "C" __declspec(dllexport) int Test(A *a);extern "C" __declspec(dllexport) int TestA(A& a);extern "C" __declspec(dllexport) int TestB(B *b);extern "C" __declspec(dllexport) int TestC(C c);extern "C" __declspec(dllexport) int TestBB(B **b);在.Net环境下启用非托管调试跟踪时发现:
    调用TestB、TestC均能正确传值,调用Test、TestA、TestBB时进到C++中时b中的值都乱了,传递结构的多维数组时也不能正确的取到值,如果为A结构中的b添加[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10, ArraySubType = UnmanagedType.Struct)]属性修饰,则在调用Test的时候就出异常了
      

  8.   

    测试调用代码:
    private void button2_Click(object sender, System.EventArgs e)
    {
    A[] a = new A[2]; a[0].a = 1;
    a[0].b = new B[10]; for (int i = 0; i < 10; ++i)
    {
    a[0].b[i].a = i;
    a[0].b[i].b = 10 - i;
    } a[1].a = 2;
    a[1].b = new B[10]; for (int i = 0; i < 10; ++i)
    {
    a[1].b[i].a = 10 - i;
    a[1].b[i].b = i;
    } Class1.Test(ref a);
    }private void button3_Click(object sender, System.EventArgs e)
    {
    A a; a.a = 5;
    a.b = new B[10]; for (int i = 0; i < 10; ++i)
    {
    a.b[i].a = i;
    a.b[i].b = 10 - i;
    } Class1.TestA(ref a);
    }private void button4_Click(object sender, System.EventArgs e)
    {
    C c; c.a = 5;
    c.b.a = 10;
    c.b.b = 10; Class1.TestC(c);
    }private void button5_Click(object sender, System.EventArgs e)
    {
    B[] b = new B[10]; for (int i = 0; i < 10; ++i)
    {
    b[i].a = i;
    b[i].b = 10 - i;
    } Class1.TestB(b);
    }private void button6_Click(object sender, System.EventArgs e)
    {
    B[,] b = new B[10, 10]; for (int i = 0; i < 10; ++i)
    {
    for (int j = 0; j < 10; ++j)
    {
    b[i, j].a = i;
    b[i, j].b = j;
    }
    } Class1.TestBB(b);
    }
      

  9.   

    查到了一篇英文资料,搞了半天.Net Framework 1.1不支持这种结构的封送
    http://www.dotnet247.com/247reference/msgs/29/147905.aspx
    然后采用了http://blog.sunmast.com/sunmast/archive/2005/04/19/1739.aspx中的解决方法,但测试后发现该文档中的解决方法还是不能正确的传递“包含了结构数组的结构”的数组,只能传递单个“包含了结构数组的结构”,看来我目前只能用VC++再包一层,对上面的“包含了结构数组的结构”的数组将其分开一个一个的传了。非常感谢Jim3(Jim) !
      

  10.   

    我的解决办法就是用等长度的byte[]代替STRUCT[](长度需要自己计算)
    然后用我写的那个Struct2Bytes方法传入
      

  11.   

    我参考了你的解决方法,但是我在测试时发现在传递“包含了结构数组的结构的数组”的时候仍然无法正确的传入,就是我上面代码中的Test方法,并在C#中将结构A重新定义了:
    [ StructLayout( LayoutKind.Sequential) ]
    public struct A
    {
    public int a;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80, ArraySubType = UnmanagedType.U1)]
    public B[] b;
    }
    在构造A数组的时候我调用了Struct2Bytes方法不知道 Sunmast 有没有做过类似的测试
      

  12.   

    [ StructLayout( LayoutKind.Sequential) ]
    public struct A
    {
    public int a;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = xxx, ArraySubType = UnmanagedType.U1)]
    public byte[] b;
    }
      

  13.   

    不好意思,上面是我发贴的时候Copy错了,实际上我测试的时候定义的跟楼上一样:)
    算了,反正这个问题用其他方法也勉强能够解决,结贴吧
    谢谢各位朋友!