【问题标题】:Difference between dllimport and getProcAddressdllimport 和 getProcAddress 之间的区别
【发布时间】:2010-07-13 23:27:29
【问题描述】:

首先,我知道直接比较 dllimport 属性和 getProcAddress 函数是没有意义的。相反,我有兴趣比较两段代码,它们基本上实现了相同的事情——调用 dll 中的函数——通过使用 dllimport 属性或 getProcAddress 函数导入函数。具体来说,我正在编写一个 C# 应用程序,它使用我编写的 dll 中的某些函数。起初我使用以下代码访问了我的 dll 函数:

class DllAccess
{
    [DllImport("kernel32.dll", SetLastError = true)]
    private extern IntPtr LoadLibrary(String DllName);

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    private delegate Bool BarType(Byte arg); // return value indicates whether function call went well or not.

    Bool Bar(Byte arg)
    {
        Bool ok = false;
        IntPtr pDll= LoadLibrary("foo.dll");
        if (pDll != IntPtr.Zero)
        {
            IntPtr pfunc = GetProcAddress(pDll, "bar");
            if (pFunc != IntPtr.Zero)
            {
                BarType bar = (BarType)Marshal.GetDelegateForFunctionPointer(pFunc, typeof(BarType));
                ok = bar(arg);
            }
            FreeLibrary(pDll);
        }
        return ok;
    }
}

但是,我后来需要获取 lastError 值,如果它是在 dll 调用期间设置的,所以我将代码更改为:

class DllAccess
{
    [DllImport("foo.dll", EntryPoint = "bar", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
    private extern Bool DllBar(Byte arg); // return value indicates whether function call went well or not.

    Bool Bar(Byte arg)
    {
        return DllBar(arg);
    }
}

这当然更整洁,并且如前所述,它设置了 lastError 代码。显然,我的第一段代码让我可以在运行时更改 dll 和函数调用,但目前这不是必需的。所以我的问题是:如果我确定我不会使用另一个 dll 或另一个函数,是否有任何理由使用第一个公式?

【问题讨论】:

    标签: c# pinvoke dllimport getprocaddress


    【解决方案1】:

    使用 GetProcAddress 的唯一真正优点是您可以手动卸载 DLL 以及调用函数,并且您可以在运行时轻松更改命名。

    但是,第二个选项为您提供了大量的好处。除了“更整洁”之外,它还为您处理大部分数据类型的编组 - 这对于某些 API 变得非常重要。

    话虽如此,如果您按照您首先列出的方法进行操作,您也应该确保卸载所有内容。现在基本上每次调用 Bar() 都在泄露地址……详情看FreeLibrary

    【讨论】:

    • 感谢您的回答。在我的代码中,我实际上在构造函数中加载了库,在析构函数中释放了库,并将整个东西用作单例,因为我不知道多次加载库是否会导致麻烦。为了正确起见,我编辑了我的帖子以释放图书馆。
    • @Boris: LoadLibraryFreeLibrary 进行引用计数,所以多次调用往往会正常。
    • “泄露地址”是什么意思? DLL 只加载一次,内存中只存在一个函数副本,并且委托被垃圾回收。
    • @Ben:不过,它实际上在内存中保留了额外的指针计数 - 这没什么大不了的,因为库仅由于引用计数而加载了 1 次,但您实际上确实泄漏了一个指针,而且它是如果您无论如何都不打算继续使用它,可能最好卸载该库...
    【解决方案2】:

    GetProcAddress 的最大优势可能是它可以让您控制 DLL 的搜索路径。例如,您可以自动加载 32 位或 64 位版本的本机 DLL。使用DllImportAttribute,这是不可能的。

    【讨论】:

    猜你喜欢
    • 2014-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    • 2021-12-25
    • 2020-05-10
    • 2014-09-20
    相关资源
    最近更新 更多