Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolving error C3821: managed type or function cannot be used in an unmanaged function

I'm writing a C++/CLI layer to handle some interop.

The native API populates a complex structure involving fixed arrays, unions, anonymous structures, etc:

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

I'm trying to translate this data structure to more "sane" .NET class, for consumption by C#. The problem is, I can't use this legacy structure, and gcnew my new class in the same function:

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;
}

Doing so gives the error:

Error 2 error C3821: 'void Test::GetFoo(HANDLE)': managed type or function cannot be used in an unmanaged function

If a native structure and a gcnew cannot exist in the same function, how can one ever hope to (even manually) marshall data between the two?

Many Q/A here involve wrapping unmanaged classes, which seems to be irrelevant here.

like image 409
Jonathon Reinhart Avatar asked Jun 22 '14 20:06

Jonathon Reinhart


1 Answers

Aligned data types not supported in managed code

That's the real error message, unfortunately it does not show up in the Error List window. You can only see it in the Output window. Something to keep in mind when compiler error messages look bizarre.

And yes, it is accurate, managed code doesn't run with the stack alignment guarantees that are needed to get this structure aligned. 32-bit code runs with an alignment of 4, 64-bit code can provide 8. Not good enough to get 16. Nothing the compiler can do about it either, the usual stack pointer manipulations are not available in IL, that screws up the metadata that the jitter generates that tells the garbage collector where the look for object references when it walks the stack.

So, no can do, you cannot make it a local variable. You've got choices, the most straight-forward way is to allocate it:

#include <malloc.h>
....

    FOO* value = (FOO*)_aligned_malloc(sizeof(FOO), __alignof(FOO));
    try {
        // etc...
    }
    finally {
        _aligned_free(value);
    }
like image 167
Hans Passant Avatar answered Oct 18 '22 17:10

Hans Passant