#c# #c #interop #marshalling
#c# #c #взаимодействие #маршалирование
Вопрос:
У меня есть программа на C, скомпилированная в DLL, которую я загружаю в C # (используя kernel32.dll LoadLibrary и FreeLibrary). Используя GetProcAddress, я могу получить указатель на некоторые данные в памяти, и я хочу преобразовать эти данные в эквивалентную структуру в C #.
Моей первой идеей было создать структуры на C #, которые отображались бы непосредственно на структуры C (используя атрибуты StructLayout
и MarshalAs
), а затем просто использовать Marshal
класс (в System.Runtime.InteropServices
). Это хорошо работает для «более простых» структур, но не работает для многомерных массивов и объединений массивов.
Структуры данных в C выглядят следующим образом (например):
struct MyStruct
{
union MyUnion my_data[16][16];
}
union MyUnion
{
uint32_t ints[2];
uint8_t bytes[8];
}
Т. е. он содержит произвольно вложенные структуры и объединения и их многомерные массивы.
Есть ли встроенный способ в C # для обработки маршалинга этих типов структур данных?
Редактировать:
Мои требования таковы:
- Объединения C # должны работать так же, как и объединения C, т. Е. запись в
bytes
поле также должна изменятьints
поле (afaik, используя явный макет структуры, вы можете создавать объединения только встроенных типов значений в C #). (Это скорее проблема C #, чем проблема маршалинга) - Структуры C # должны быть маршалируемыми для C / C и обратно
Как отметил Селвин в комментариях, можно сгладить многомерные массивы в одно измерение, а затем получить доступ с помощью [x y * 16]. Однако я предпочитаю, чтобы исходные размеры были сохранены, а метод доступа такой же, как в C.
Мой ответ ниже делает то, что я хочу, но поскольку маршалинг между C # и C настолько распространен, кажется, что должен быть более простой способ достижения этого результата.
Комментарии:
1. Добро пожаловать в SO! Обратите внимание, что формулировка » Каков наилучший способ … » может привести к тому, что ваш вопрос скоро будет закрыт, потому что прямой ответ, скорее всего, будет больше основан на мнениях, чем на фактах. Я отредактировал ваш вопрос, потому что в общем виде вы даже не просите об этом.
2. я почти уверен, что
my_data[256]
это должно работать с такими доступом, какmy_data[x y*16]
3. Здесь есть несколько хороших примеров .
4. Взгляните на классы маршалинга, структуры и объединения . Там вы найдете несколько примеров. Другой способ, который я предпочитаю, особенно для сложных структур c и / или вызова нескольких функций простой C DLL, — это создание C / CLI -библиотеки DLL-оболочки.
5. Спасибо за ответы. Моя самая большая проблема — это маршалирование объединений массивов, которое встроенному маршалл действительно не нравится. Для объединения в моем примере выше запись в
bytes
поле также должна изменять значения вints
поле. Может быть, это отдельный вопрос? Как говорит @Selvin, многомерные массивы можно свести к одному массиву. Я пробовал это, и это работает нормально, но я бы предпочел использовать тот же метод доступа к значениям, который используется в структурах C, для согласованности.
Ответ №1:
Мое текущее решение заключается в создании класса-оболочки вокруг необработанных данных byte[]
с средствами доступа, которые имитируют структуру базовых данных.
Например, для простой структуры в C:
struct MySimpleStruct
{
uint32_t my_ints[16];
}
Я создаю оболочку:
public class MySimpleStruct
{
private byte[] _underlying;
public UintAccessor[] MyInts { get; }
public MySimpleStruct(byte[] data)
{
_underlying = data;
MyInts = new UintAccessor[16];
// for-loop to initialize each accessor with the right index
}
}
public class UintAccessor
{
public uint Value
{
get => BitConverter.ToUint32(_underlying, _idx);
set => BitConverter.GetBytes(value).CopyTo(_underlying, _idx);
}
public UintAccessor(byte[] data, int index) { /* ... */ }
}
и оболочку можно использовать следующим образом
var myStruct = new MySimpleStruct(theData);
myStruct.MyInts[5].Value = 123;
Эти классы-оболочки могут стать довольно сложными, однако мы автоматически генерируем структуры C, и мы будем генерировать эти оболочки C # одновременно, поэтому сложность возникает только при генерации кода.