Interop between managed and legacy code

It’s quite common and easy to use legacy code from within a piece of managed code but sometimes it comes in handy to call managed code from legacy code.

To do so, we’ll write a C++ class which will actually use a managed object but that has a plain, legacy interface.
The first thing to do is to tag the class with __declspec(dllexport) and the header file must not contain any reference to managed code:
class __decldspec(dllexport) FooL
{
public:
  void BarL();
...
}

// definition
using namespace MyManaged::Foo;

void FooL::BarL()
{
  Foo^ f = gcnew Foo();
  f->Bar();
}

And this is enough if you want to call managed code from a plain, C++ class. But sometimes you need pointers to managed object because, for example, you don’t want to create/destroy them every time you need to call a managed function. Also, we have to remember that a legacy class that has to be used in a legacy context cannot include managed code (at least, in its .h interface); to keep a reference to a managed object a void* will be fine:

class __decldspec(dllexport) FooL
{
  private:
    void* _foo; // foo is an opaque pointer
  public:
    void FooL();
    void BarL();
    ...
}

The .cpp code will use gcroot classes to wrap and pin the managed objects into memory:

#include <msclr\auto_gcroot.h>

using namespace MyManaged::Foo;

FooL::FooL()
{
  Foo^ f = gcnew Foo(); // managed object
  
  // create a gcroot to keep the managed object in memory as far as we need
  msclr::auto_gcroot<Foo^>* handle = new msclr::auto_gcroot<Foo^>();
  *handle = f;
  _foo = handle;
}

It’s now easier to call the Bar() function whenever we need:

void FooL::BarL()
{
  msclr::auto_gcroot<Foo^>* handle = (msclr::auto_gcroot<Foo^>*) _foo;
  Foo^ f = handle->get();
  f->Bar();
}

Using the pinned object we don’t have to re-create the Foo object each time we call the BarL() function. To release and delete the pinned managed object:

~FooL::FooL()
{
   msclr::auto_gcroot<Foo^>* handle = (msclr::auto_gcroot<Foo^>*) _foo;
   Foo^ f = handle->get();
   if(f != nullptr) delete f;
   delete handle;
   _foo = NULL;
}

Leave a Reply

Your email address will not be published. Required fields are marked *