#.net #windows #c -cli #interop
#.net #Windows #c -cli #взаимодействие
Вопрос:
Я пишу уровень C / CLI для обработки некоторого взаимодействия.
Собственный API заполняет сложную структуру, включающую фиксированные массивы, объединения, анонимные структуры и т. Д:
typedef struct DECLSPEC_ALIGN(16) _FOO {
union {
BAR Bar;
struct {
POP Array[8];
DWORD More;
};
};
} FOO, *PFOO;
Я пытаюсь перевести эту структуру данных в более «нормальный» класс .NET для использования C #. Проблема в том, что я не могу использовать эту устаревшую структуру и gcnew
мой новый класс в той же функции:
Foo^ Test::GetFoo(HANDLE h)
{
FOO foo; // Necessarily unmanaged
if (!::GetFoo(h, amp;foo))
throw gcnew Exception("GetFoo failed");
Foo^ result = gcnew Foo(); // Necessarily managed
// populate result
return resu<
}
Это приводит к ошибке:
Ошибка 2 ошибка C3821: ‘void Test::getFoo (HANDLE)’: управляемый тип или функция не могут быть использованы в неуправляемой функции
Если собственная структура и a gcnew
не могут существовать в одной и той же функции, как можно надеяться (даже вручную) распределить данные между ними?
Многие вопросы и ответы здесь связаны с переносом неуправляемых классов, что, по-видимому, здесь неуместно.
Комментарии:
1. @HansPassant Не так.
/clr
включен, и у меня#pragma managed
нигде нетunmanaged
операторов or. Попытка принудительной генерации управляемого кода с/clr:pure
помощью выдает ошибкуTest::GetFoo cannot be generated in managed code: 'Aligned data types not supported in managed code'; compile with /clr to generate a mixed image
. Я предполагаюDECLSPEC_ALIGN
, что это то, что меня убивает? Хотя я был бы удивлен, если бы объединение было разрешено где-либо рядом с управляемым кодом.2. Хорошо, я понял. Пожалуйста , избегайте публикации невозможных сообщений об ошибках, getFoo() не возвращает void .
3. @HansPassant Извините за это, я, очевидно, работаю с большей базой кода и попытался свести проблему к минимальному примеру, фактически не создавая этот минимальный пример.
Ответ №1:
Выровненные типы данных не поддерживаются в управляемом коде
Это реальное сообщение об ошибке, к сожалению, оно не отображается в окне списка ошибок. Вы можете увидеть это только в окне вывода. Что-то, что следует иметь в виду, когда сообщения об ошибках компилятора выглядят странно.
И да, это точно, управляемый код не выполняется с гарантиями выравнивания стека, которые необходимы для выравнивания этой структуры. 32-разрядный код выполняется с выравниванием 4, 64-разрядный код может обеспечить 8. Недостаточно хорошо, чтобы получить 16. Компилятор также ничего не может с этим поделать, обычные манипуляции с указателями стека недоступны в IL, что приводит к искажению метаданных, генерируемых дрожанием, которые сообщают сборщику мусора, где искать ссылки на объекты, когда он проходит по стеку.
Итак, ничего не поделаешь, вы не можете сделать это локальной переменной. У вас есть выбор, самый простой способ — выделить его:
#include <malloc.h>
....
FOO* value = (FOO*)_aligned_malloc(sizeof(FOO), __alignof(FOO));
try {
// etc...
}
finally {
_aligned_free(value);
}
Комментарии:
1. Я всегда могу рассчитывать на то, что ты, Ханс, ответишь на мои вопросы о взаимодействии с .NET. Всегда ценю ваши подробные ответы.