Как передать struct из C # в C ++ DLL? - PullRequest
0 голосов
/ 02 мая 2018

Хорошо, моя серия проблем с контроллером лазерного устройства продолжается ... Я хочу вызвать следующую функцию C ++ в DLL из моего кода C #:

extern "C" _declspec(dllimport) int SendFrame(DWORD deviceIndex, byte* pData, DWORD numOfPoints, DWORD scanrate);

Указатель pData указывает на массив лазерных точек, которые определены в заголовочном файле C ++ следующим образом:

#pragma pack (1)
struct LaserPoint {
    WORD x;
    WORD y;
    byte colors[6];
};

На стороне C # я определил импорт функции следующим образом:

[DllImport("..\\..\\dll\\StclDevices.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SendFrame(UInt32 deviceIndex, ref byte[] pData, UInt32 numOfPoints, UInt32 scanrate);

... и LaserPoint структура, подобная этой:

[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct LaserPoint {
    public UInt16 x;
    public UInt16 y;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public byte[] colors;
}

Затем я вызываю функцию SendFrame следующим образом:

LaserPoint point = new LaserPoint();
point.x = 16384;
point.y = 32768;
point.colors = new byte[] {255, 0, 0, 0, 0, 0};

byte[] arr = point2array(points);
SendFrame(0, ref arr, 1, 30000);

Это моя функция для преобразования экземпляра структуры LaserPoint в байтовый массив:

private static byte[] point2array(object obj) {
    int len = Marshal.SizeOf(obj);
    byte[] arr = new byte[len];
    IntPtr ptr = Marshal.AllocHGlobal(len);
    Marshal.StructureToPtr(obj, ptr, true);
    Marshal.Copy(ptr, arr, 0, len);
    Marshal.FreeHGlobal(ptr);
    return arr;
}

Но мое лазерное устройство не получает правильного ввода, поскольку лазер ведет себя очень странно. Использование одного и того же кода в проекте C ++ прекрасно работает. Так что ошибка где-то с этим кодом взаимодействия C #.

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

Если вы собираетесь использовать здесь только структуры LaserPoint, вы можете определить функцию как

[DllImport("..\\..\\dll\\StclDevices.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int SendFrame(UInt32 deviceIndex, LaserPoint[] pData, UInt32 numOfPoints, UInt32 scanrate);

И избавьтесь от копирования, и пусть среда выполнения сделает это за вас.

В противном случае, как говорит ildjarn, избавление от ref должно сработать, поскольку байтовые массивы уже являются ссылочными (указательными) типами.

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

0 голосов
/ 02 мая 2018

Массивы уже являются ссылочными типами, поэтому ref byte[] - это двойное косвенное обращение, похожее на byte** - потеря ref.

...