当我们得到实际的.dll实现时,为什么还需要一个.lib存根文件?

时间:2009-08-18 22:56:45

标签: dll linker implicit explicit

我想知道为什么链接器不能简单地通过查询获得实际实现代码的实际.dll文件中的信息来完成它们的工作?我的意思是为什么链接器仍然需要.lib文件来进行隐式链接?

不是导出和相对地址表足以进行此类链接吗?

无论如何,只使用.dll而没有.lib存根/代理文件的人可以进行隐式链接吗?

我认为windows可执行加载器只是代表程序执行LoadLibrary / LoadLibraryEx调用(因此名称隐式链接),这是显式链接的主要区别。如果这是真的,那么在没有.lib的情况下明确地执行它应该表明它是可行的,如果没有隐式,对吧?或者我只是说无意义?

感谢任何帮助,非常感谢:)

geeko

1 个答案:

答案 0 :(得分:7)

我可以想到几个原因。

  • 使用.lib文件意味着您可以构建不同版本的DLL,而不是在系统上构建,只要您安装了正确的SDK即可。
  • 编译器&链接器需要支持跨平台编译 - 您可能正在为32位平台上的64位目标构建,反之亦然,并且没有正确的架构DLL。
  • .lib文件使您可以“隐藏”实现的某些部分 - 您可以拥有未在.lib中显示但可通过GetProcAddress发现的私有导出。您也可以执行序数导出,在这种情况下,他们没有导出友好名称,但在.lib中会有一个友好名称。
  • 原生DLL没有强名称,因此可能会选择错误版本的DLL。
  • 最重要的是,这项技术是在20世纪80年代设计的。如果它是今天设计的,它可能更接近您描述的内容 - 例如,.NET您只需要引用目标程序集,并且拥有使用它所需的一切。

我不知道有任何方法只使用DLL隐式链接 - 快速搜索显示了几个工具,但我没有使用过任何工具。

在这种情况下,我将创建一个单独的源文件,其中包含您需要使用的函数,并动态加载DLL并根据需要绑定它们。例如:

// using global variables and no-error handling for brevity.

HINSTANCE theDll = NULL;
typedef void (__stdcall * FooPtr)();
FooPtr pfnFoo = NULL;
INIT_ONCE initOnce;

BOOL CALLBACK BindDLL(PINIT_ONCE initOnce, PVOID parameter, PVOID context)
{
    theDll = LoadLibrary();
    pfnfoo = GetProcAddress(dll, "Foo");

    return TRUE;
}

// Export for foo
void Foo()
{
    // Use one-time init for thread-safe lazy initialization
    InitOnceExecuteOnce(initOnce, BinDll, NULL, NULL)
    pfnFoo();
}