【问题标题】:How to have a DLL work on different Windows versions?如何让 DLL 在不同的 Windows 版本上工作?
【发布时间】:2010-12-17 13:19:59
【问题描述】:

我正在编译由多个.o 文件组成的自己的DLL。 .o 文件之一具有调用 SHLoadLibraryFromItem 的函数,该函数仅在 Windows 7 上受支持。除非使用 DLL 的应用程序在 Windows 7 上运行,否则永远不会调用该函数。(是的,我确定。)

但是,当在旧版本的 Windows(例如 XP)上运行应用程序时,整个应用程序在启动时会崩溃并出现错误“找不到指定的过程”。虽然错误没有指定找不到哪个过程,但如果我注释掉对SHLoadLibraryFromItem的调用,那么一切正常。

问题:

  1. 为什么 Windows 试图找到 SHLoadLibraryFromItem,即使它没有在 XP 上被调用?
  2. 有没有办法让 Windows这样做,即仅在运行 Windows 7 时才找到 SHLoadLibraryFromItem,即某种惰性绑定?
  3. 如果不是,最好的解决方法是什么?

我能想到的唯一方法是:

  1. 使用LoadLibrary加载SHLoadLibraryFromItem所在的Windows DLL,使用GetProcAddress手动获取地址到函数指针中,改用指针调用SHLoadLibraryFromItem
  2. 有两个 DLL:一个包含 Windows 7 支持的函数,只有在 Windows 7 上运行时才会加载。

还有其他想法吗?我真的更喜欢上面提到的某种惰性绑定。

更新

请阅读我实际写的内容。我在第一段中明确指出, SHLoadLibraryFromItem调用的,除非我确定该应用程序实际上是在 WINDOWS 7 上运行的。

仅当 DLL加载时应用程序崩溃。

【问题讨论】:

    标签: windows com dll


    【解决方案1】:

    链接器会在您的模块中嵌入对所使用的每个 API 函数的引用。当 Windows 加载程序加载您的可执行文件及其模块时,它需要将代码中的所有调用“连接”到内存中实际加载 API 函数的位置。如果找不到它们,它将不会继续。

    使用LoadLibraryGetProcAddress 是解决此问题的“标准”方法。

    使用两个 DLL 对您没有帮助,因为只要其中一个加载失败,您的应用程序仍然无法启动。您可以通过使用延迟加载来解决此问题,将依赖于新操作系统的所有代码放在单独的模块中,并将对该模块的所有调用包装在 Win32 SEH 异常处理程序中(延迟加载时会出现 SEH 异常无法加载模块)。优点是您可以使用“自动”链接而不会弄乱函数指针,但异常处理可能非常讨厌。

    This article 解释了一下,并给出了一些如何巧妙地包装的例子。

    【讨论】:

    • 您不能延迟加载单个符号吗? (我习惯于在 Linux 上的 ELF 可执行文件中执行此操作)
    • @Craig Ringer 我不这么认为,链接器的延迟加载参数是一个模块列表。从技术上讲,链接器可以很容易地做到这一点,因为它为每个函数生成一个存根,但我认为没有任何方法可以让它做到这一点。
    • @Craig Ringer 也许我误解了您的问题...如果 DLL 存在,但您引用的函数之一不存在,则链接器生成的延迟加载代码应尝试每个 GetProcAddress()单独调用,所以缺少的会产生异常,但其他的仍然可以工作。
    【解决方案2】:

    为什么 Windows 会尝试查找 SHLoadLibraryFromItem 即使它是 没有在 XP 上调用?

    Windows 在应用程序加载到内存时解析引用,而不是在调用时解析。这称为“动态链接”(与使用链接器的静态链接相反),但它并不是真正的动态链接。因此,它不知道特定方法是否会在运行时被调用。

    【讨论】:

      猜你喜欢
      • 2023-03-29
      • 1970-01-01
      • 2012-07-31
      • 2016-09-19
      • 2014-08-24
      • 1970-01-01
      • 2018-01-19
      • 2018-04-19
      • 1970-01-01
      相关资源
      最近更新 更多