Невозможно вернуть структуру из C ++ обратно в C # - PullRequest
0 голосов
/ 07 августа 2009

У меня есть программа на C #, которая вызывает родную C ++ dll.

C # имеет следующую структуру:

[StructLayout(LayoutKind.Sequential)]
public struct Phenomenon
{
    [MarshalAs(UnmanagedType.U1)] public char Type;
    [MarshalAs(UnmanagedType.R8)] public double Jd;
    [MarshalAs(UnmanagedType.R8)] public double Loc_jd;
    [MarshalAs(UnmanagedType.R8)] public double Angle;
    [MarshalAs(UnmanagedType.U1)] public char Tran_dir;
    [MarshalAs(UnmanagedType.I2)] public Int16 Warning;
}

Программа на C ++ имеет следующее определение структуры:

   typedef struct
   {
      char type;
      double jd;
      double loc_jd;
      double angle;
      char tran_dir;
      short int warning;
   } phenomenon;

Программа C # создает экземпляры объектов Phenomenom и имеет следующий вызов метода C ++:

Phenomenon[] phenomena = new Phenomenon[6];
short status = rsttwi_temp(phenomena);

C ++ просто обновляет структуру и возвращает. Вот функция C ++:

__declspec(dllexport) short int rsttwi_temp (phenomenon phen[1])
{
    phen[0].type = 'Z';
    phen[0].jd = 1.1;
    phen[0].loc_jd = 2.2;
    phen[0].angle = 3.3;
    phen[0].tran_dir = 4.4;
    phen[0].warning = '0';

    return 0;
}

Из программы C #, когда я распечатываю значения структуры после вызова функции C ++, структура не обновлялась (то есть она такая же, как до вызова функции C ++). Кажется, что программа C ++ может видеть значения и обновлять их, но по возвращении C # никогда не видит обновлений значений в структуре. Думая, что это проблема соотношения стоимости и ссылки, я даже попытался сделать это с помощью класса в программе на C # вместо структуры. Все еще не повезло.

Вопрос: Какой маршалинг мне нужен, чтобы вызываемая функция C ++ могла обновлять фактическую структуру, которая была ей передана?

Спасибо. Грег Эдвардс Total Immersion Software

Ответы [ 3 ]

2 голосов
/ 07 августа 2009

Нелегко понять, почему это не работает, не видя определения вашей функции C #. Я думаю, это выглядит примерно так, хотя

[DllImport("somedll.dll")]
public static extern Int16 rsttwi_temp(Phenomenon[] array);

У меня нет большого опыта работы с pinvoking собственного массива фиксированного размера. Но вы можете изменить сигнатуру C ++ на указатель вместо массива фиксированного размера и переключить управляемый код для передачи по ссылке. Например

[DllImport("somedll.dll")]
public static extern Int16 rsttwi_temp(ref Phenomenon value);

__declspec(dllexport) short int rsttwi_temp (phenomenon* phen)
1 голос
/ 24 декабря 2010

Использование таким образом работает:

C ++

 __declspec(dllexport) short int rsttwi_temp (phenomenon* phen)
{
    phen->jd = 1.1;
    phen->loc_jd = 2.2;
    phen->angle = 3.3;
    phen->warning = 0;
    return 0;
}

typedef struct
       {
          double jd;
          double loc_jd;
          double angle;
          short int warning;
       } phenomenon;

C #

[DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern Int16 rsttwi_temp(ref Phenomenon value);

[StructLayout(LayoutKind.Sequential)]
        public struct Phenomenon
        {
            [MarshalAs(UnmanagedType.R8)]
            public double Jd;
            [MarshalAs(UnmanagedType.R8)]
            public double Loc_jd;
            [MarshalAs(UnmanagedType.R8)]
            public double Angle;
            [MarshalAs(UnmanagedType.I2)]
            public Int16 Warning;
        }

C # Call

 Phenomenon phenomena = new Phenomenon();
 short status = rsttwi_temp(ref phenomena);
0 голосов
/ 05 марта 2010

C # char! = C ++ char.

C # char == C ++ wchar_t

C ++ char == C # byte

...