Итак, я пытаюсь написать оболочку С# для общения с одним из наших драйверов устройств. (создание модульного теста) Драйвер новый, но закодирован для старых заголовков С++, поэтому макеты структур определены и не могут измениться.
Поэтому я воспроизвел структуры 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
терпит неудачу, потому что на стороне драйвера он проверяет размер переданного буфера. На стороне С# мой объект слишком мал, так как Marshal.SizeOf()
возвращает 52
в качестве размера, когда он должен быть 852
, если я добавлю Size=
в атрибут StructLayout
, функция "пройдёт", но я уверен, что данные передаются неправильно.
Я совершенно уверен, что проблема в этом public Points[] p = new Points[10];
Я думаю, что Marshal.StructToPtr() неправильно маршалирует это, поскольку по сути это многомерный массив.
Поэтому я предполагаю, что мои вопросы вообще возможны? Кажется, что C# может быть достаточно умным, чтобы знать, как создать правильный объем памяти для этого массива структуры... но, может быть, нет?
Альтернативы, которые я думал о том, что «могло бы» работать.
Напишите собственные serailizers, которые преобразуют объект в byte[] и обратно с нулевыми метаданными. - Не идеально.
Можно ли написать смешанную clr c++ dll и попытаться использовать ее как клин. Однако мои опасения, что у меня будет такая же проблема, но только в управляемом С++? Или даже в смешанном режиме мне пришлось бы написать управляемый класс, чтобы обернуть неуправляемый объект, чтобы использовать его в С#. Но проблема заключается в том, как передать это в deviceIOcontrol, если я сделаю это из С#, чем возникнет текущая проблема с попыткой правильно маршалировать материал? Или, если я передам его в вызов C++, который вызывает DeviceIOControl, тогда мне нужно знать, как получить неуправляемый тип каждого переданного управляемого объекта.
Просто написать функции C++, которые создают объекты и вызывают deviceIOControl, меньше идей, поскольку параметры могут выйти из-под контроля?
Откажитесь и сделайте все это на С++, я на самом деле пытаюсь написать модульный тест для своего оборудования, и более новый модульный тест 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);
}