不正确的编组:C#数组到C ++非托管数组

时间:2011-09-05 15:06:27

标签: c# c++ pinvoke marshalling

我有以下带有结构定义(CInput),obj定义和init的C#代码,以及对C ++(本机)DLL函数的调用(也是由我编写的)。

//C# code

 public struct CInput
 {

  [MarshalAsAttribute(UnmanagedType.R8)] 
  public double Time;

  [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_R8)]
  public double[] Database;

  /* other similar fields*/

}     

CInput Inputs = new CInput();

/* init of Inputs fields*/

int bfr = Example(ref Inputs); //'Example' being the C++ DLL call

Messagebox.Show(bfr.ToString());

第二个参数的编组有错误,我不知道在哪里。然后:

//C++ code

struct CInput {

  double Time;                       
  double Database[3650];     
  /*etc*/   
}

int Example(CInput& ObjIn) {

    return ObjIn.Database[0];        // just an example
}

如果我不小心并且在数据库封送中仅指定“SafeArray”,则会出现“读/写内存错误,可能已损坏”等。

如果“数据库”被编组为ByValArray一切正常,则值会正确显示。不幸的是我得到了一个内部大小异常,因为我有很多那个大小的数组,因此我必须去指针 - 但是任何带有“SizeArray”的东西都会带来以下结果(代码刚刚发布):

(来自C ++):

Database[0] = **0**

Database[1..etc] = values of the next parameters in the struct marshaled with ByValArray.

我想我应该提到我需要从C#到C ++的相同结构,我不是在寻找任何花哨的东西。所以结构中的数组>>>结构中的数组。

任何对此的见解都具有重要价值。我一直在寻找几个小时,但我还没有解决方案。

非常感谢提前。

2 个答案:

答案 0 :(得分:5)

根据我的理解,您不能将ByValArraySizeConst一起使用,因为您的真实结构有大量此类数组会导致堆栈溢出。

你认为也许你需要在你的结构中使用指针而且我同意你的看法。这是怎么做的。

在C ++方面,您应该将每个数组声明为指向元素类型的指针:

struct CInput {
  double *array;
}

您可能还希望在结构中包含数组的长度,以避免过多的硬编码常量。

所有艰苦的工作都发生在C#方面。

public struct CInput
{
    public IntPtr array;
}
...
double[] theArray = new double[3650];
CInput input = new CInput();
input.array = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(double))*theArray.Length);
try 
{
    Marshal.Copy(theArray, 0, input.array, theArray.Length);
    //call your C++ function here
}
finally
{
    Marshal.FreeHGlobal(input.array);
}

答案 1 :(得分:4)

public struct CInput  
{    
    public double Time;    
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3650)] 
    public double[] Database;
}       

CInput Inputs = new CInput();  
int bfr = Example(ref Inputs);

编辑。如果需要动态分配数据库数组,则应更改C ++和C#代码。在C ++中,数据库应定义为double *,并且需要在某处添加数组长度。在C#Database中应声明为IntPtr,并使用Marshal.AllocHGlobal方法进行分配。请根据您的要求更正C ++结构,然后根据此修复C#代码。