我有一个 .NET 项目,我在其中从资源中提取,在运行时并基于平台位,包含我需要使用的函数的本机代码 .DLL。我使用 LoadLibrary、GetProcAddress 和 FreeLibrary 来管理我的托管代码中库的加载和使用。
使用完本机库后,我想将其删除。下面是一些伪代码,显示了当前实现的工作流程:
internal class 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);
}
}
Run Code Online (Sandbox Code Playgroud)
这在使用 IntPtr 类型的变量时工作正常。盛行的智慧(最佳实践?)表明 SafeHandle 可能是更好的方法。但是,我的理解是,在使用 SafeHandle 时,不会确定性地调用 ReleaseHandle() 方法。也就是说,在 SafeHandle 上调用 Close() 或 Dispose() 方法只会标记该类进行垃圾回收;在收集对象之前,它不会调用 ReleaseHandle。这对我来说是个问题,因为在卸载之前我无法删除我的本机代码 .DLL。如果我在 ReleaseHandle 期间调用 FreeLibrary,我怎样才能确定性地等待库被释放(不诉诸诸如调用 GC.Collect() 之类的技巧)?
编辑我已经更新了示例以更能代表我的实际代码的结构。请注意,此示例中发布的代码并不完整。我在我的生产代码中包含了必要的错误检查和异常处理。
不,这不准确。SafeHandle 负责在您的代码忘记释放句柄时释放句柄。只有那会发生不确定性,代码,终结器线程上运行。调用 Dispose() 是高度确定的。
作为写你的代码是不是安全的,它会永久泄漏模块句柄时,炸弹上的异常。您应该使用 finally 块来确保释放句柄。这已经足够好了,这里不需要 SafeHandle,因为您将句柄保留为局部变量,并且始终可以确定性地释放它。