C # вызывающее устройство IOControl со сложными структурами

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

Итак, я скопировал структуры c ++, которые ожидают от устройства DeviceIOControl.

Обновление № 3 — изменение кода на демо-код, который имеет ту же проблему. Также уточняю вопрос, чтобы быть более полезным для других, см. Мой ответ ниже

[StructLayout(LayoutKind.Sequential, Pack=1)]
public class Points
{
public int id;

[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
public int[] x = new int[10];
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
public int[] y = new int[10];
};

[StructLayout(LayoutKind.Sequential, Pack=1)]
public class Shape
{
public int name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
public Points[] p = new Points[10];
};

[StructLayout(LayoutKind.Sequential,Pack1)]
public class GeoShape:Shape
{
public int top;
public int left;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
public int[] v = new int[10];
};

Мой звонок deviceIOControl не удается, потому что на стороне драйвера он проверяет размер передаваемого буфера. На стороне C # мой объект слишком мал Marshal.SizeOf() возвращается 52 как размер, когда это должно быть 852если я добавлю Size= к StructLayout атрибут, функция «пройдет», но я уверен, что данные не передаются правильно.

Я уверен, что проблема заключается в следующем public Points[] p = new Points[10]; Я думаю, что Marshal.StructToPtr () неправильно маршалирует это, поскольку это по сути многомерный массив.

Так что я думаю, мои вопросы это вообще возможно? Похоже, C # может быть достаточно умен, чтобы знать, как создать нужное количество места в памяти для этого массива структуры … но, возможно, нет?

Альтернативы я думал о том, что «может» работать.

  1. Напишите собственные serailizer, которые преобразуют объект в byte [] и обратно, с нулевыми метаданными. — Не идеально.

  2. Было бы возможно написать смешанный clr c ++ dll и попытаться использовать это как клин. Однако, мои проблемы, я просто собираюсь иметь ту же проблему, но только в управляемом C ++? Или даже в смешанном режиме мне пришлось бы написать управляемый класс, чтобы обернуть необработанный объект, чтобы использовать его в c #. Но проблема заключается в том, как передать это в deviceIOcontrol, если я сделаю это из c #, чем будет иметь место текущая проблема с попыткой правильно маршалировать вещи? Или, если я передам его в вызов C ++, который вызывает DeviceIOControl, то мне нужно знать, как добраться до необработанного типа каждого передаваемого объекта.

  3. Просто напишите функции на языке c ++, которые создают объекты, и вызовите deviceIOControl. Меньше идей, поскольку параметры могут выйти из-под контроля?

  4. Сдавайся и делай все это на C ++, на самом деле я пытаюсь написать модульный тест для моего оборудования, а более новый модульный тест cpp в VS действительно довольно хорошо интегрируется …

Я также видел этот предыдущий вопрос и попробовал его, однако я думаю, что мой сценарий немного другой. Не / Маршаллинг вложенных структур, содержащих массивы структур

 struct Points
{
int id;
int x[10];
int y[10];
};struct Shape
{
int name;
Points p[10];
};

struct GeoShape :Shape
{
int top;
int left;
int v[10];
};

Обновлено 2
Я должен уточнить, что я пытаюсь отправить объект водителю, а не получить его обратно (пока не менее)

Вот как я это называю.

public static bool SetObject(SafeFileHandle device, DeviceControlCode ioctlCode, Object obj)
{
int size = Marshal.SizeOf(obj.GetType());
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(obj, ptr, false);

// call the dviceIOControl method
return Control(device, ref ioctlCode, ptr, size, IntPtr.Zero, 0);
}

0

Решение

Я действительно не знаю, что на заголовках, но в качестве отправной точки рассмотреть чтение этот о том, когда использовать структура или же учебный класс

В качестве предупреждения … вы уверены, что Pack = 1? У вас есть #pragma, установив его в 1?

Если вы предоставите соответствующий код .h, будет проще проверить, что может быть не так. Во всяком случае, с доступной информацией, я бы сделал это так:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct VENUS_FORMAT4
{
public uint Top;
public uint Left;
public uint Rows;
public uint Columns;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.MAX_CD_ROWS)]
public uint[] V65Rows;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.MAX_CD_COLS_DD2)]
public uint[] CDCols;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.MAX_DD_SECTIONS)]
public uint[] DDSections;
}

Остальное в основном такое же, как указано выше, за исключением VENUS_VM4_DEVICE_FORMAT4IL который вам придется «копировать» поля, потому что вы не можете наследовать при использовании структур (в C # (значения типа)).

Кроме того, если на стороне C ++ у вас есть союзы это не сработает, и вы должны использовать LayoutKind.Explicit а также FieldOffset.

1

Другие решения

Поскольку вы встраиваете структуры в структуры, вам нужно будет использовать структуры C #, а не классы, чтобы ваши структуры были значениями, а не ссылками. Это означает, что вам придется отказаться от использования наследования. Вы можете перевести свои структуры так:

public struct Points
{
int id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
int[] x;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
int[] y;
};

public struct Shape
{
int name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
Points[] p;
};

public struct GeoShape
{
int name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
Points[] p;
int top;
int left;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
int[] v;
};

С этими определениями Marshal.SizeOf(typeof(GeoShape)) оценивается как 892. Обратите внимание, что, хотя вы утверждаете, что правильное значение равно 852, это не так. Размер вашей структуры C ++ составляет 892.

Если вы хотите избежать повторения определения Shape в GeoShape Вы можете вставить это:

public struct GeoShape
{
Shape shape;
int top;
int left;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]
int[] v;
};
1

Я наконец смог исправить это, сделав следующие 2 вещи.

  1. Я изменил свой первый класс, чтобы быть структурой и использовал fixed ключевое слово.
  2. Я удалил pack=1 значение на StructLayoutAttribute,

    [StructLayout(LayoutKind.Sequential)] public struct Points
    {
    public int id;
    public unsafe fixed int x[10];
    public unsafe fixed int y[10];
    //[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)] //public int[] x = new int[10];
    //[MarshalAs(UnmanagedType.ByValArray, SizeConst=10)] //public int[] y = new int[10];
    };

0
По вопросам рекламы [email protected]