Поэтому я пытаюсь написать оболочку 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 # может быть достаточно умен, чтобы знать, как создать нужное количество места в памяти для этого массива структуры … но, возможно, нет?
Альтернативы я думал о том, что «может» работать.
Напишите собственные serailizer, которые преобразуют объект в byte [] и обратно, с нулевыми метаданными. — Не идеально.
Было бы возможно написать смешанный clr c ++ dll и попытаться использовать это как клин. Однако, мои проблемы, я просто собираюсь иметь ту же проблему, но только в управляемом C ++? Или даже в смешанном режиме мне пришлось бы написать управляемый класс, чтобы обернуть необработанный объект, чтобы использовать его в c #. Но проблема заключается в том, как передать это в deviceIOcontrol, если я сделаю это из c #, чем будет иметь место текущая проблема с попыткой правильно маршалировать вещи? Или, если я передам его в вызов C ++, который вызывает DeviceIOControl, то мне нужно знать, как добраться до необработанного типа каждого передаваемого объекта.
Просто напишите функции на языке c ++, которые создают объекты, и вызовите deviceIOControl. Меньше идей, поскольку параметры могут выйти из-под контроля?
Сдавайся и делай все это на 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);
}
Я действительно не знаю, что на заголовках, но в качестве отправной точки рассмотреть чтение этот о том, когда использовать структура или же учебный класс
В качестве предупреждения … вы уверены, что 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.
Поскольку вы встраиваете структуры в структуры, вам нужно будет использовать структуры 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;
};
Я наконец смог исправить это, сделав следующие 2 вещи.
fixed
ключевое слово.Я удалил 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];
};