解决错误C3821:托管类型或功能不能在非托管功能中使用

Jon*_*art 5 .net windows interop c++-cli

我正在编写一个C++/CLI层来处理一些互操作.

本机API填充了涉及固定数组,联合,匿名结构等的复杂结构:

typedef struct DECLSPEC_ALIGN(16) _FOO {
    union {
        BAR Bar;
        struct {
           POP   Array[8];
           DWORD More;
        };
    };
} FOO, *PFOO;
Run Code Online (Sandbox Code Playgroud)

我正在尝试将此数据结构转换为更"理智"的.NET类,供C#使用.问题是,我不能使用这个遗留结构,而gcnew我的新类在同一个函数中:

Foo^ Test::GetFoo(HANDLE h)
{
    FOO foo;                              // Necessarily unmanaged

    if (!::GetFoo(h, &foo))
        throw gcnew Exception("GetFoo failed");

    Foo^ result = gcnew Foo();            // Necessarily managed

    // populate result

    return result;
}
Run Code Online (Sandbox Code Playgroud)

这样做会给出错误:

错误2错误C3821:'void Test :: GetFoo(HANDLE)':托管类型或函数不能在非托管函数中使用

如果本机结构和a gcnew不能存在于同一个函数中,那么人们怎么能希望(甚至手动)对两者之间的数据进行编组?

这里有许多Q/A涉及包装非托管类,这似乎与此无关.

Han*_*ant 12

托管代码中不支持对齐的数据类型

这是真正的错误消息,遗憾的是它没有显示在错误列表窗口中.您只能在"输出"窗口中看到它.编译器错误消息看起来很奇怪时要记住一些事情.

是的,它是准确的,托管代码不会与堆栈对齐保证一起运行,以保证这种结构对齐.32位代码运行,对齐为4,64位代码可以提供8.不够好得到16.编译器也无法做到这一点,通常的堆栈指针操作在IL中不可用,这搞砸了抖动生成的元数据,告诉垃圾收集器在堆栈行走时对象的引用位置.

所以,没有办法,你不能把它变成局部变量.你有选择,最直接的方法是分配它:

#include <malloc.h>
....

    FOO* value = (FOO*)_aligned_malloc(sizeof(FOO), __alignof(FOO));
    try {
        // etc...
    }
    finally {
        _aligned_free(value);
    }
Run Code Online (Sandbox Code Playgroud)

  • Hans,我始终可以信赖您来回答我的 .NET 互操作问题。始终感谢您详尽的回答。 (2认同)