Устранение ошибки C3821: управляемый тип или функция не могут быть использованы в неуправляемой функции

#.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. Всегда ценю ваши подробные ответы.