C#Pinvoke并重新加载DLL

时间:2017-01-03 18:29:33

标签: c# dll pinvoke

我正在尝试从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仍然有用 是不是应该将模块加载到内存的不同部分? 我可以按照我的方式做,或者我会遇到麻烦吗?

1 个答案:

答案 0 :(得分:4)

当您卸载并重新加载模块时,它可能会加载到不同的地址。或者它可能会加载到同一地址。由系统决定加载模块的位置。重新加载时,您需要再次为导入的每个函数调用GetProcAddress,因为如果模块已加载到不同的地址,则函数的地址可能已更改。

当然,您的代码中完全没有该部分。您为导入的每个函数调用GetProcAddress的部分。如果你想重新加载,你必须这样做。否则,模块可能会加载到不同的地址,然后一切都会崩溃,如您链接的主题所述。

看起来好像你运气不好,模块被重新加载到同一个地址。我说不走运,因为你无法观察故障模式,所以错误地试图相信你的代码是正确的。

所以你必须通过调用GetProcAddress来停止p /直接调用模块并获取所有函数指针。将这些转换为Marshal.GetDelegateForFunctionPointer的代理人。