我正在尝试从C#程序中卸载C ++ DLL,然后重新加载它并使用函数。 卸载部分我用这个答案: Unload a DLL loaded using DllImport
为了重新加载它,我使用了LoadLibrary函数。 这是我的代码:
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
internal class Program
{
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FreeLibrary(IntPtr hModule);
[DllImport("TestLibrary.dll", SetLastError = true)]
private static extern int GetValue();
private static void Main(string[] args)
{
int val = GetValue();
IntPtr p2 = LoadLibrary("TestLibrary.dll");
bool isFree = FreeLibrary(p2);
isFree = FreeLibrary(p2);
p2 = LoadLibrary("TestLibrary.dll");
val = GetValue();
}
}
}
奇怪的是,当我重新加载模块时,pinvoke仍然有用 是不是应该将模块加载到内存的不同部分? 我可以按照我的方式做,或者我会遇到麻烦吗?
答案 0 :(得分:4)
当您卸载并重新加载模块时,它可能会加载到不同的地址。或者它可能会加载到同一地址。由系统决定加载模块的位置。重新加载时,您需要再次为导入的每个函数调用GetProcAddress
,因为如果模块已加载到不同的地址,则函数的地址可能已更改。
当然,您的代码中完全没有该部分。您为导入的每个函数调用GetProcAddress
的部分。如果你想重新加载,你必须这样做。否则,模块可能会加载到不同的地址,然后一切都会崩溃,如您链接的主题所述。
看起来好像你运气不好,模块被重新加载到同一个地址。我说不走运,因为你无法观察故障模式,所以错误地试图相信你的代码是正确的。
所以你必须通过调用GetProcAddress
来停止p /直接调用模块并获取所有函数指针。将这些转换为Marshal.GetDelegateForFunctionPointer
的代理人。