views:

106

answers:

4

I'm new to C++/CLI, so please bear with me...

I'm working on a mixed C++/CLI DLL, which should act as a bridge between a Win32 process and a .NET assembly. In the DLL, I need some .NET stuff to be present during the lifespan of the DLL. Initializing is not that big a problem, but I couldn't figure out when can I safely cleanup the .NET stuff. The usual C++ facilities (DLL_PROCESS_DETACH, global variables and static locals d'tors) all seem to be called after the CLR has gone away.

So, what is the way to get notified the DLL is about to detach from the CLR, so I can release the .NET references I hold?

A: 

This might not apply to the C++ side of .NET, but to my knowledge the only way to get the CLR to release a loaded assembly is to dispose of the AppDomain; and unless you've engineered in manual AppDomain management you likely only have the initial AppDomain--making disposal the equivalent of killing your application.

STW
I'm not trying to release an assembly - I'm merely trying to release the references to .NET objects I've created, and have been holding during the lifespan of the DLL...
eran
Are the objects in .NET disposable? In that case you might try dispose() on those objects once you finish the usage.
Kangkan
@Kangkan - telling when the usage is finished is exactly my problem... It's easy to know when the native world is about to end (process detach, globals d'tors etc.) but at that point, the managed world has already ended.
eran
So, do you know when the managed world finishes?
Kangkan
A: 

.NET Dll should be treated as set of separate ref classes. Every instance of ref class has its own lifetime, and resource management is done relatively to the class instance lifetime. Properly implemented Dispose pattern solves all resource management problems.

Every C++/CLI class, which has some native resources, or disposable class members, should have destructor and optional finalizer. Specifically, .NET references are released in the class destructor, which is mapped to C# Dispose method.

Alex Farber
My problem is probably using the wrong pattern, but I can't figure out the right one. Think of my case as a native singleton, which stores a reference to a .NET object in an auto_gcroot. When the singleton is destructed, auto_gcroot tries to release the reference - but it's too late, and results in a crash.
eran
If you're going to keep the object for as long as your DLL is loaded, just "leak" the handle. The garbage collector will take care of it in the extremely unlikely event that the CLR is still running after your DLL unloads.
Ben Voigt
I guess you keep auto_gcroot reference for some kind of callback communication from a native singleton to .NET objects. Maybe it is better to think about another callback algorithm, for example, based on native events?
Alex Farber
+2  A: 

If you need to take care of AppDomain unloads, use the AppDomain.DomainUnload event to do your cleanup.

As STW says, libraries with managed code can never be detached from an AppDomain, the only way to detach it from your process is to unload the AppDomain.

If you aren't managing AppDomains, just leak the managed resource (and properly flush unmanaged resources during process detach). Better yet, design it as crash-only software so that no cleanup is required.

Ben Voigt
DomainUnload seems like a valid path, and I've just started exploring it, but haven't been able to get it to work yet. As for leaking the managed resources, it'd be ok, but it's as hard as the original problem... to prevent them from being gc'ed, I must have references to those objects. I'd love to be able to release those references upon unload, but this has to be done while .NET is still around. Figuring out the right time is exactly my problem...
eran
You can prevent objects from being collected by just calling `GCHandle.Alloc`. The resources will last until a matching call to `GCHandle.Free` or the appdomain gets unloaded.
Ben Voigt
+1  A: 

Well, answering my own question seems awkward, but this wasn't suggested by anyone else, and it is what I was looking for... so:

turns out Microsoft offers an exotic variation of onexit, called _onexit_m, which should be used in mixed-mode DLLs. When using _onexit_m to register a (managed) callback function, that function will be called when the DLL is about to be unloaded, but before the CLR has been shut down. It is similar to AppDomain.DomainUnload, suggested by Ben Voigt, but for some reason I couldn't get DomainUnload to work, and _onexit_m is simpler to use IMHO.

eran