Saturday, October 24, 2009

"I thought you were still there..."


NTSTATUS: STATUS_IS_NOT_WIN32



This has to do with the .net CLR loading assemblies dynamically. Sure, it's not a Win32 thing, but it is related when I went about trying to achieve what I normally would in native Win32 apps.

The story begins quite simply, in implementing basic plug-in type architectures. When one did it in regular (native) Win32 apps with C/C++, you'd just use LoadLibrary() and FreeLibrary() to load and unload the relevant DLL's that would function as plug-ins.

Trying to achieve the same in .net, the methods from the Assembly class LoadFrom() and LoadFile() can be used to load an assembly at runtime. However, what's obviously missing is any method to unload those assemblies. After a little searching, we come across this. Apparently, there are plenty of reasons not to. So, this clearly begs the question, why it can be done in native Win32, and not in the .net CLR. From what I can tell, it's basically a case of trying to stop people from shooting themselves in the foot. In my case, I know exactly what I'm doing, and it's exactly what I intend to do. But too bad, everyone gets the same treatment.

It seems the closest is to read the entire assembly binary into memory, and use Assembly.Load(). Effectively, this gets the job done. So, problem solved. However, it wasn't so for me. The problem laid in WPF. This 'bug' is related to user controls and assembly loading, and I will write about that in a subsequent post.

So anyway, I wanted to see what would happen if I manually unloaded a .net assembly. I did the obvious thing having the assembly's path:

IntPtr hModule = Win32.GetModuleHandleW(assemblyPath);

if (hModule != null)
{
if (Win32.FreeLibrary(hModule))
{
Debug.WriteLine("DLL released...");
}
else
{
// failed
Debug.WriteLine("Failed to release DLL...");
}
}


Win32 in the above code is a class in which I declared the Win32 API functions. In any case, the assembly is unloaded from the process, piece of cake. So, the question now is, does anybody know about it? Obviously, the answer is NO. I suppose it is not reasonable for the .net CLR to check if the assembly is still there anytime it wanted anything from it. Heck, I wouldn't do that either since I did not let anybody else but myself do it.

Calling the code to load the assembly again does not result in the assembly being loaded again. Simply a matter of replacing the assembly with one with different content/code, and loading it again. As far as the CLR is concerned, it's already loaded. Fair enough. So the next time you called anything in the assembly, BOOM! It crashes as expected.

Oh, do note that there would still be a handle to the assembly (the DLL) in the process. It is no easy task to find the handle and close it, so I wasn't bothered as it wouldn't make any difference.

Freeing the .net DLL manually was really just a case of 'let's see what happens'. Not recommended for .net assemblies, but it's just regular for native Windows Win32 DLL's if you're working with them.

No comments:

Post a Comment