Se você manda o objeto não managed para o código managed, sem problemas, o código managed não vai controlar ele, por isso vem aqueles problemas que citei, onde você, no código managed vai ter que gerenciar o tempo de vida dele e talvez implementar a interface IDisposable para simplificar um pouco o seu trabalho na hora de usar o objeto não managed.
O seu código C# vai ter que dizer ao código C++ que não precisa mais do objeto e o código C++ cuida de destruir ele.
Nos trabalhos que fiz para uma empresa, tinha uma interface C++ +/- assim (supondo aqui que temos um objeto com um nome muito criativo de "Object"):
int ObjectCreate(....);
void ObjectDestroy(int id);
bool ObjectOperationX(int id);
No lado C# criamos uma classe para fazer os acessos na dll:
class ObjectDll
{
[DllImport("ObjectImpl.dll", EntryPoint = "
ObjectCreate",
SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern
Int32 Create();
//demais fucnoes da dll
}
E o uso do objeto era encapsulado numa classe C#:
class Object: IDisposable
{
Int32 mId;
public Object()
{
mId = ObjectDll.Create();
}
~
Object ()
{
this.Dispose(false);
}
public void Dispose()
{
GC.SuppressFinalize(this);
this.Dispose(true);
}
public void Dispose(bool disposing)
{
if (disposing)
{
//no managed
}
if(mId != 0)
{
ObjectDll.Destroy(mId);
mId = 0;
}
}
}
Dessa forma, no codigo C# poderiamos simplemente fazer:
Object obj = new Object();
obj.FazAlgo();
obj.Dispose();
ou então:
using(Object obj = new Object())
{
obj.FazAlgo();
}
O codigo não deve estar 100% correto, fiz de cabeça com copy e paste modificado, mas acho que já da para você ter uma idéia.
Outro detalhe, no nosso caso, era conveniente armazenar no C++ os objetos num array, por isso os objetos eram identificados com inteiros.