Again thanks Richard for making me think differently :-D
Here's the solution for anyone else:
On the c++/cli side:
...
NativeWorkerObject *nativeWorkerObj = new NativeWorkerObject();
IntPtr managedResultsPointer = Marshal::AllocHGlobal( sizeof( NativeResultsObject * ) );
NativeResultsObject *nativeResultsPointer = ( NativeResultsObject * )managedResultsPointer.ToPointer();
nativeWorkerObj->DoSomeWork( &nativeResultsObj );
Marshal::FreeHGlobal( managedResultsPointer );
delete nativeWorkerObj;
No change required on the native side.
===========================================================
The
Marshal::AllocHGlobal()
allocates memory from the unmanaged memory which is locked in place i.e. the garbage collector can't touch it. This gives you the safe memory for your native pointer.
The
IntPtr.ToPointer()
returns a good old
void *
allowing you to cast the pointer accordingly for your needs.
Don't forget to release any resources used after use :)