Неправильный маршалинг: массив C # в неуправляемый массив C ++ - PullRequest
6 голосов
/ 05 сентября 2011

У меня есть следующий код C # с определением структуры (CInput), определением obj и init, а также вызовом функции 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 ++, я не ищу ничего фантастического.Так что Array in Struct >>> Array in Struct.

ANY понимание в отношении этого было бы очень полезно.Я искал часы, и у меня пока нет решения.

Большое спасибо заранее.

Ответы [ 2 ]

5 голосов
/ 05 сентября 2011

Как я понимаю ваш вопрос, вы не можете использовать ByValArray с SizeConst, потому что ваша реальная структура имеет большое количество таких массивов, что приводит к переполнению стека.

Вы полагаете, что, возможно, выМне нужно использовать указатели в ваших структурах, и я согласен с вами.Вот как это сделать.

На стороне 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);
}
4 голосов
/ 05 сентября 2011
public struct CInput  
{    
    public double Time;    
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3650)] 
    public double[] Database;
}       

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

Редактировать. Если вам нужен динамически размещаемый массив Database, код C ++ и C # следует изменить. В C ++ база данных должна быть определена как double *, и вам нужно где-то добавить длину массива. В C # база данных должна быть объявлена ​​как IntPtr и размещена с использованием метода Marshal.AllocHGlobal Исправьте структуру C ++ в соответствии с вашими требованиями, и затем код C # может быть исправлен в соответствии с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...