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.

__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;
}