Как передать структуру из C# в C++ DLL?

Хорошо, моя серия проблем с контроллером лазерного устройства продолжается ... Я хочу вызвать следующую функцию 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#.

Любые идеи?

Вау, вот и все :)! Пожалуйста, ответьте, и я проверю его как решение. Спасибо!

salocinx 02.05.2018 15:52

Без проблем. : -] Извините за краткий ответ, в данный момент на мобильном телефоне.

ildjarn 02.05.2018 15:54

Кстати, полностью ли вы контролируете как сторону C++, так и сторону C# кода? Поскольку SendFrame можно легко заменить, чтобы избежать необходимости в point2array (довольно ужасно как есть) ...

ildjarn 02.05.2018 15:57
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
1 682
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

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

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

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

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

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

Большое спасибо за ваш ответ и предложение. У меня был ref LaserPoint[] pData, который раньше не работал. Но LaserPoint[] pData тоже работает нормально :-) Кажется, я раньше делал еще одну ошибку с указателями. Откажусь от своей дурацкой функции point2array.

salocinx 02.05.2018 16:38

Другие вопросы по теме