What does the marshaler expect from a custom marshaler for a returned value?

左心房为你撑大大i 提交于 2019-12-11 16:46:51

问题


I am trying to implement a custom marshaler for a C# delegate returned value

[return: MarshalAs(UnmanagedType.CustomMarshaler,MarshalType = "MyCustomMarshaler")]
public delegate MSyntax SyntaxCreator();

In C++ the MSyntax type is a normal C++ class.

In C# the MSyntax type is a normal C# class (not a struct) that has an internal pointer (using IntPtr) to the C++ one.

So I wrote the method MarshalManagedToNative like this:

public IntPtr MarshalManagedToNative(Object ManagedObj)
{
    MSyntax msyntax = ManagedObj as MSyntax;
    // GetNativeDataSize() returns what sizeof(MSyntax) returns in C++
    IntPtr ptrBlock = Marshal.AllocCoTaskMem( GetNativeDataSize() );

    unsafe
    {
        byte* ptrDest = (byte *)ptrBlock.ToPointer();
        byte* ptrSource = (byte *)msyntax.GetInternalCPlusPlusPointer();
        for( uint i = 0; i < GetNativeDataSize(); ++i )
        {
            *ptrDest = *ptrSource;
            ++ptrDest;
            ++ptrSource;
        }
    }
    return ptrBlock;
}

As you can see it allocates enough memory using Marshal.AllocCoTaskMem to hold a new instance of a C++ MSyntax then copies the content of the internal C++ MSyntax from ManagedObj to this new instance.

It almost works. In C++ the caller to this delegate/callback function does something like:

MSyntax syntax = CallCallbackFunction();

In normal C++ when this line is executed, C++ creates a new instance of MSyntax, calls the copy constructor of MSyntax passing a reference to the MSyntax returned by "CallCallbackFunction()" then calls the destructor of that reference since it's an intermediate value (probably on the stack).

Now in my situation the call ends up calling my MarshalManagedToNative method, on return the C++ copy constructor of MSyntax is called accordingly and works perfectly fine. If I debug it I can see that the reference passed to the copy constructor is the IntPtr I returned from my MarshalManagedToNative method so that's great. But finally the desctructor of MSyntax is called but the "this" pointer is wrong so it fails miserably... The "this" pointer is not the IntPtr I returned from my MarshalManagedToNative method... It's probably an adress on the stack... no wonder.

So I was wondering how to implement the MarshalManagedToNative method to make this code works fine ? (BTW I'm on win64 so it's the fastcall convention that is used.)

While surfing the web I found that the marshaler has some special expectations from a custom marshaler. For instance if you have a method like this:

void foo( [in: MarshalAs(UnmanagedType.CustomMarshaler,MarshalType = "MyCustomMarshaler")] SomeClass * arg );

The marshaler will take the IntPtr you return from your MarshalManagedToNative method and expect to first find an integer at this memory address that tells how many SomeClass elements follow after the integer (because the SomeClass* pointer argument could be an array).

Do you guys know where all this is documented? Sorry but I couldn't find it :-(
My hope is to find some special information that will dictate how I should implement the method MarshalManagedToNative.

Thanks

来源:https://stackoverflow.com/questions/15094084/what-does-the-marshaler-expect-from-a-custom-marshaler-for-a-returned-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!