views:

748

answers:

3

Bit of a history lesson here. I'm working on a legacy C++/MFC application and am trying to start a incremental modernization by pushing components written in C# (WinForms and later WPF).

I'm stucking using .Net/1.1 and VS/2003 for many reasons which are impossible to resolve in the near future.

Currently, as a proof of concept, something like this works:

#pragma push_macro("new")
#undef new

WinFormA::Form1* myform;
myform = __gc new WinFormA::Form1();
myform->ShowDialog();

#pragma pop_macro("new")

The problem I'm having is this - I need the unmanaged C++/MFC code to pass a callback pointer into the managed C# WinForm code so that I can capture user interactions and have them processed by the application.

I've looked at some articles such as this MSDN article but it doesn't work in VS/2003 (the compiler doesn't like the delegate syntax).

Are there any other options? I don't think I can use DLLImport since I need to interact with the specific application instance not a flat API.

Thanks!

A: 

I already forgot .NET 1.*, but:

Define necessary interfaces and register your .NET components as COM objects. .NET utilities will usually provide reasonably good marshaling code.

If possible, access them as COM objects from C++ application without any Managed C++ at all. (Use interface pointers instead of functions for callbacks).

If COM is not an option, use .NET Reflector to see what's going on inside auto-generated interop assemblies - this might give an insight on how to do the same thing manually.

ima
A: 

I have never tried it by myself, but did you check RuntimeMethodHandle struct which is definitely exists in .net1?

SomeDelegate Handler = new SomeDelegate(SomeMethod);
IntPtr HandlerPtr = Handler.Method.MethodHandle.GetFunctionPointer();

And some copy-paste from MSDN's description .net2 Marshal::GetDelegateForFunctionPointer Method:

In versions 1.0 and 1.1 of the .NET Framework, it was possible to pass a delegate representing a managed method to unmanaged code as a function pointer, allowing the unmanaged code to call the managed method through the function pointer. It was also possible for the unmanaged code to pass that function pointer back to the managed code, and the pointer was resolved properly to the underlying managed method.

arbiter
A: 

If the other answers don't work out, you could always write a C wrapper to flatten the classes. For example, if the C++ class is:

class TheClass {
  public:
    TheClass(int Param);
    ~TheClass();

    bool SomeFunction(int Param1,int Param2);
};

I'll write a wrapper:

extern "C" void *TheClass_Create(int Param) {
  return (void*) new TheClass(Param);
}

extern "C" void TheClass_Destroy(void *This) {
  delete (TheClass*) This;
}

extern "C" bool TheClass_SomeFunction(void *This,int Param1,int Param2) {
  return ((TheClass*) This)->SomeFunction(Param1,Param2);
}

Because the wrapper is straight C, you can P/Invoke in C# to your heart's content (the void *This should become an IntPtr to ensure compatibility if you move to 64-bit). Sometimes, if I'm really ambitious, I'll actually write a C# wrapper around the P/Invokes to 're-classify' the thing.

Marc Bernier