Can I use the .NET SafeHandle class and deterministically free the handle therein?
I have a .NET project in which I extract from a resource, at runtime and based on platform bit-ness, a native code .DLL which contains functions I need to use. I use LoadLibrary, GetProcAddress, and FreeLibrary to manage loading and use of the library in my managed code.
After I'm done with the native library, I'd like to delete it. Here's some pseudo-code showing the workflow as currently implemented:
internal class开发者_JAVA技巧 MyClass()
{
string nativeLibraryPath = "C:\my\path\to\extracted\library.dll";
IntPtr nativeLibraryHandle = IntPtr.Zero;
public void Load()
{
nativeLibraryHandle = NativeMethods.LoadLibrary(nativeLibraryPath);
}
public void ExecuteFunction()
{
IntPtr functionPointer = NativeMethods.GetProcAddress(nativeLibraryHandle, "MyFunctionName");
// assume MyManagedDelegate is defined as the correct delegate type.
MyManagedDelegate managedFunction = Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(MyManagedDelegate)) as MyManagedDelegate;
managedFunction("foo", "bar");
}
public void Unload()
{
NativeMethods.FreeLibrary(nativeLibraryHandle);
File.Delete(nativeLibraryPath);
}
}
This works fine when using variables of type IntPtr. Prevailing wisdom (best practices?) indicate that a SafeHandle might be a better approach. However, my understanding is that when using a SafeHandle, the ReleaseHandle() method is not called deterministically. That is, calling the Close() or Dispose() method on a SafeHandle only marks the class for garbage collection; it doesn't call ReleaseHandle until the object is collected. This is a problem for me because I can't delete my native code .DLL until it's unloaded. If I call FreeLibrary during ReleaseHandle, how can I deterministically wait for the library to be released (without resorting to hackery such as calling GC.Collect())?
EDIT I've updated the example to be more representative of how my actual code is structured. Note that the code posted in this example is not complete. I am including the necessary error checking and exception handling in my production code.
No, that's not accurate. SafeHandle takes care of releasing the handle when your code forgets to do so. Only that will happen non-deterministically, code that runs on the finalizer thread. Calling Dispose() is highly deterministic.
Your code as written is not safe, it will permanently leak the module handle when it bombs on an exception. You should use a finally block to ensure the handle is released. Which is quite good enough, you don't need SafeHandle here since you keep the handle as a local variable and can always deterministically release it.
You are incorrect.
Calling Close()
will free the handle.
However, it will only close the handle when its reference count is zero (this is maintained by the handle; the GC doesn't use ref-counts)
精彩评论