Question

I am trying to call a managed method from unmanaged code. However, the managed code is requiring that I use the '(__clrcall) calling convention, and my unmanaged C++ code refuses to let me use the __clrcall calling convention without using the /clr option. I don't believe I want to do that as the unmanaged project is not mine to change to managed.

I have gone through constructing all those delegates and function pointer marshaling in the managed side as I have seen on CodeGuru and MSDN but this error still pops up unless I call a static function using a __stdcall convention that cannot be a member of a ref class. The method needs to be an instance of a ref class.

The only way I have been able to get around this is to do my method call from the unmanaged code in assembly skipping the popping of the ESP register (adding 4) after the call (the call has one parameter in the argument thus the '4'). That allows me to effectively do a __clrcall. That option stinks big time.

Anybody have any ideas on how to work around this issue? It must surely be possible. I am missing some simple but vital piece of information.

Here is my delegate definition (all of these belong to a single ref class ManagedSensor):

        delegate void OxpOnReceivedMeasurement(std::vector<OBX> *obxes);

Here is the instance method I want to call

        void LocalOxpMeasurementCallback(std::vector<OBX> *obxes);

And here is the marshaling of the ref class function to the unmanaged function done in the ref class constructor:

    // Now to make the 'delegate' unmanaged function pointer usable for unmanged code
    // The argument is the unmanaged callback.
    OxpOnReceivedMeasurement ^oxpMeasurementCallbackFP = gcnew OxpOnReceivedMeasurement(this, &ManagedSensor::LocalOxpMeasurementCallback);
    // Lock it so the garbage collector doesnt get rid of it or move it
    gch = GCHandle::Alloc(oxpMeasurementCallbackFP);
    // Pass the marshaled function pointer to the unmanaged code
    IntPtr ip = Marshal::GetFunctionPointerForDelegate(oxpMeasurementCallbackFP);
    // fnOnReceiveMeasurement is defined in OxpLibTransports.h which matches the delegate
    // this passes the function pointer to the unmanaged Sensor class to be used when a 
    // measurement is received
    _sensor->RegisterForMeasurementCallback((fnOnReceiveMeasurement)(ip.ToPointer()));

Hope somebody has a nice answer to this issue. I am probably missing something stupid.

Was it helpful?

Solution

That is supported. You can use an attribute to tell the CLR that the thunk it creates for the delegate should use the __cdecl calling convention. Make it look like this:

using namespace System::Runtime::InteropServices;

[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
delegate void OxpOnReceivedMeasurement(std::vector<OBX> *obxes);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top