I would like to have a way to make a call to a method of a reference class which takes a native argument. Creating a delegate seems the most obvious choice but it doesn't work with such methods.
Please have a look at following snippet
#pragma managed(push, off)
struct Native{};
#pragma managed(pop)
#pragma managed(push, on)
ref struct Managed{
// methods of managed class can take...
void method1(int){} // ...value types as an argument
void method2(System::String^){} // ...reference types as an argument
void method3(Native){} // ...native types as an argument, NICE!
};
int main(array<System::String ^>^ /*args*/) {
Managed^ m = gcnew Managed;
auto del1 = gcnew System::Action<int>(m, &Managed::method1); // ok
auto del2 = gcnew System::Action<System::String^>(m, &Managed::method2); // ok
auto del3 = gcnew System::Action<Native>(m, &Managed::method3); // error C3225: generic type argument for 'T' cannot be 'Native', it must be a value type or a handle to a reference type
}
#pragma managed(pop)
The error message says:
error C3225: generic type argument for 'T' cannot be 'Native', it must be a value type or a handle to a reference type
It's not saying you can't make a delegate out of that method, just that you can't represent it as an Action<Native>
.
You can either declare your own delegate type, or use a parameter that's valid to use in a generic.
public delegate void ActionOfNative(Native n);
auto del3 = gcnew ActionOfNative(m, &Managed::method3); // ok
This does change the semantics of the parameter you're passing, but you could pass a pointer instead. The IntPtr
type is effectively the same as a void*
. You can use that as your parameter type. You do have to convert the IntPtr
back to a Native*
yourself, though.
void method4(IntPtr ip){Native* np = (Native*)ip.ToPointer(); }
auto del4 = gcnew System::Action<IntPtr>(m, &Managed::method4); // ok
// Here's how you call del4.
Native n;
Native* np = &n;
IntPtr ip = IntPtr(np);
del4(IntPtr(&n));
del4(IntPtr(np));
del4(ip);