在VC++中结构定义:
typedef struct
{
int nDataNum;    // 数据个数
double *pdData;    // 存放数据数组
} PDData;在VC++中函数定义:
int Test(..., PDData *pOutputData, ...) {}在C#中相应结构定义:
[StructLayout(LayoutKind.Sequential)]
public class PDData
{
  public int nDataNum;  public double[] pdData;  public PDData(double[] pdData)
  {
   this.pdData = pdData;
   this.nDataNum = pdData.Length;
  }
}在C#中外部方法定义:
[DllImport("TestDll.dll")]
  public static extern int PredictData(
   ...,
   [MarshalAs(UnmanagedType.LPStruct)]
   PDData pOutputData, 
   ...);
在C#中调用该方法:(MAX_OUTPUT_DATA_NUM为常量)
PDData pOutputData = new PDData(new double[MAX_OUTPUT_DATA_NUM]);
Test(..., pOutputData, ...);在VC++中对该Dll进行测试完全正确,pdData数组中都有值输出,但在C#中按上面的方法调用该Dll时也可以正常运行,也可以得到函数返回值,但pdData数组中没有值输出。我还尝试以下几种方法:
在C#中将PDData定义成struct,并定义外部方法将pOutputData参数定义成ref;
在C#中定义外部方法将pOutputData参数定义成ref;
在C#中定义结构时将double[] pdData标识为[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_R8)];
在C#中定义结构时将double[] pdData标识为[MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_OUTPUT_DATA_NUM, ArraySubType=UnmanagedType.R8)];
在C#中定义结构时将double[] pdData标识为[MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.R8, SizeConst=MAX_OUTPUT_DATA_NUM)];
...但这些方法运行时都是出错,不是报内存不足就是报未将对象引用到实例,无比郁闷,请大家帮忙看看是什么地方出的问题,为什么结构中的数组的值传不回来?或者大家帮忙找个C#中调用非托管Dll中的带有返回对象参数的例子,谢谢

解决方案 »

  1.   

    typedef struct
    {
    int nDataNum;    // 数据个数
    double *pdData;    // 存放数据数组
    } PDData;这里有问题吧?PDData不是指针,怎么以P开头了?有歧义 :-)
    还有在struct里面定义的数组,最好是定长的,比如double pdData[10]在C#里面你可以这样定义等价的结构:
    struct DData
    {
    public int nDataNum;
    public IntPtr pdData;
    }然后使用Marshal.Copy方法把数据从指针复制到本地数组
      

  2.   

    如果改成这样定义的话:
    typedef struct
    {
    int nDataNum;    // 数据个数
    double pdData[10];    // 存放数据数组
    } PDData;C#里面这样对应:
    [StructLayout(LayoutKind.Sequential)]
    struct DData
    {
    public int nDataNum;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
    public double[] pdData;
    }
      

  3.   

    在C++里面调用不需要pin
    // marshal_embedded_pointer.cpp
    // compile with: /clr
    #include <iostream>using namespace System;
    using namespace System::Runtime::InteropServices;
    using namespace stdcli::language;// unmanaged struct, but visible to both
    struct ListStruct
    {
    int count;
    double* item;
    };
    #pragma unmanagedvoid UnmanagedTakesListStruct(ListStruct list)
    {
    printf("[unmanaged] count = %d\n", list.count);
    for (int i=0; i<list.count; i++)
    {
    printf("array[%d] = %f\n", i, list.item[i]);
    }}#pragma managedint main()
    {
    ListStruct list;
    list.count = 10;
    list.item = new double[list.count];Console::WriteLine("[managed] count = {0}", list.count);
    Random^ r = gcnew Random();
    for (int i=0; i<list.count; i++)
    {
    list.item[i] = r->NextDouble() * 100.0;
    Console::WriteLine("array[{0}] = {1}", i, list.item[i]);
    }UnmanagedTakesListStruct( list );
    delete list.item;return 0;
    }在托管里面给pdData赋初值的时候应该用pin指针钉住托管堆上的数据或者在传统堆上分配数据。
    参考http://msdn2.microsoft.com/library/23acw07k.aspx
      

  4.   

    谢谢Sunmast和其他的朋友,将数组设为定长后问题解决