【问题标题】:Collection of DLL's in another Designated Folder?DLL 在另一个指定文件夹中的集合?
【发布时间】:2011-12-13 22:05:42
【问题描述】:

首先,请原谅我不知道正确的术语,我确信有一个非常常见的技术名称,我可以简单地谷歌寻求帮助 - 但如果我不知道,我无法找到帮助开头的词。

我正在用 Delphi 7 构建一个模块化系统。有一些应用程序和一堆 DLL。所有应用程序共享这些 DLL,以及一些 DLL 使用其他 DLL。 DLL 当前保存在与应用程序相同的位置。相反,我想将所有这些 DLL 放在一个子文件夹中(EXE 的其他位置),但当然 Delphi 不知道如何找到它们。

有没有办法让我的 Delphi 应用程序在某个目录中查找 DLL?它不能使用常量,因为会有一个选项来指定 DLL 的存储位置。

这些 DLL 只是一个简单的 StdCall 函数集合,没什么特别的。

编辑:

解释我为什么要将 DLL 保存在它们自己的文件夹中的原因:我正在构建的这个系统将这些 DLL 视为附加组件。默认情况下,系统甚至可能没有任何附加组件。另一方面,它还允许不同的供应商构建其他 DLL 并将它们作为附加组件包含在内。然后每个需要这些附加组件的应用程序将被定向到找到它们的文件夹。 应用程序本身将具有自己的 DLL,这些 DLL 将与应用程序位于同一目录中。但是供应商的 DLL 我想分开。

正如下面的答案中提到的,我最好的办法是实现 DLL 导入方法,因为 A)我可以为它正在导入的每个 DLL 指定一个路径,B)我可以更好地控制每个 DLL 的使用(是吗?是否需要加载?)和 C)每个 DLL 在技术上可以单独位于单独的文件夹中(供应商可能希望构建自己的文件夹结构)。这个系统还很不成熟,但我打算进一步提高它的灵活性。

【问题讨论】:

  • 你可能想set the PATH
  • @PeterTurner 不,这无济于事,因为我有许多不同的 DLL - 有些可能位于与其他不同的目录中。另外,我在上面的问题中添加了更多内容来解释原因。

标签: delphi dll delphi-7


【解决方案1】:

如果您在代码中动态加载 DLL,则可以将它们存储在任何您想要的位置,因为无论如何您都必须将完整路径传递给 LoadLibrary/Ex()。如果您改为静态链接到 DLL,则可以使用 SetDllDirectory() 指定要包含在操作系统的 DLL 搜索路径中的附加路径。

【讨论】:

  • SetDllDirectory 仅在您在某处调用 LoadLibrary 时才有用。不适合从 exe 进行隐式链接。
  • 如果他使用 DLL 来实现附加组件,他就不能使用静态链接。
  • SetDllDirectory() 适用于动态加载和静态链接。 DLL 搜索路径始终用于静态链接,因为操作系统加载程序只有 DLL 名称但没有其路径,因此它必须搜索文件。对于动态加载,搜索路径仅适用于非绝对路径传递给LoadLibrary/Ex()
  • @Remy - 在操作系统加载程序尝试定位库之前,用户代码是否有机会调用它?
  • @SertacAkyuz:这取决于。对于主要应用程序,没有。您必须使用重定向或清单来指定 DLL 路径。如果您动态加载自己加载其他 DLL(静态或动态)的 DLL,则可以在主应用程序的代码中使用 SetDllDirectory()
【解决方案2】:

您可以使用 PATH 执行此操作,但我建议您不要这样做。这是一种残酷和不灵活的方法。当然,您需要更改系统范围的 PATH 才能使其在可执行文件加载时产生任何影响。

您可以使用LoadLibraryGetProcAddress 显式加载您的DLL。如果有很多进口商品,那就不好玩了,否则它可能是一个不错的选择。请记住,如果您沿着这条路线走,每个 DLL 都必须切换到显式链接。

有一个叫做DLL Redirection 的东西,但是MS 不建议你使用它。他们建议您使用并排组件。话虽如此,Visual Studio 团队远离 VS2010 中的 MSVC 运行时并排组件,因为在以前的版本中并排带来了痛苦。

因此,尽管有所有选项,但我真的认为最好的解决方案是将所有 DLL 与可执行文件放在同一目录中。如果您可以克服看起来不整洁的文件夹,那么它将使生活变得更加简单。这是一个不费吹灰之力的简单解决方案。

更新

您的问题的更新提供了这些 DLL 是可选附加组件的额外信息。在这种情况下,您别无选择,只能使用LoadLibraryGetProcAddress 的显式链接。

【讨论】:

  • +1 感谢您提供信息 - 鉴于该项目的特定场景(我将在澄清问题时添加评论),最好的解决方案是使用导入方法。
  • 请记住,您需要将每个procedure ... external 替换为保存过程的变量、对LoadLibrary 的调用和对GetProcAddresss 的调用以及错误检查。如果你沿着这条路线走,那么将它包装在一个类中以避免重复。我有这样一个库,用于无法避免GetProcAddress 的情况。
  • 这是我喜欢接受的完美挑战:D
【解决方案3】:

我强烈建议您将 DLL 保留在与应用程序相同的文件夹中。

如果您真的想将 DLL 放在单独的文件夹中,那么您需要知道是否可以使用允许指定路径的 LoadLibrary API 加载 DLL。但是,如果 DLL 是静态加载的,那么执行搜索的是 Windows。 Windows 搜索首先在应用程序文件夹中查找,然后搜索 Windows PATH。此外,由于 Delphi 7 仅创建 32 位应用程序,因此在 Windows 64 位下可能会变得混乱。

【讨论】:

  • 我可以看到的 64 位窗口没有问题。否则我不能再同意了。
  • 这只是回答了我的问题——我的结论是实现导入它们的能力(在我的特定情况下,这实际上是一个更好的选择)。
  • @David:过去我们将共享 DLL 放入 windows\system32 文件夹。在 Windows 64 位中,32 位应用程序无权访问 system32。有关更多信息,请参阅此链接:msdn.microsoft.com/en-us/library/aa384187%28v=vs.85%29.aspx
  • 但其实也一样清晰。如果您将 32 位 DLL 放在 64 位系统文件夹中,那么您犯的不是一个错误,而是两个错误。把它去掉,生活就变得微不足道了。
  • @Steve:不要将 anything 放入 Windows 系统文件夹,特别是如果它只是应用程序代码而不是系统扩展。将它们视为操作系统私有文件夹。这是 Windows 3.x 中使用的一个坏习惯,因为缺少 ACL 和更好的选择。恕我直言,Windows 不应该允许在此处编写除 Microsoft 批准之外的任何内容。
【解决方案4】:

在 Windows 上,有一个“DLL search order”。其中一个搜索路径是The directory from which the application loaded,这就是为什么将它们与 EXE 放在同一文件夹中的原因。

如果您静态链接到 DLL,则必须在 EXE 加载到内存时加载它们。这是在执行第一行代码之前。因此,您依赖位于搜索路径之一中的 DLL。在这种情况下,您只能设置路径,并且必须在程序加载之前设置它。

如果您要动态链接到 DLL,那么您可以使用 LoadLibrary/LoadLibraryEx 在运行时在代码中加载 DLL。使用这些函数,您必须指定 DLL 的路径,因此 DLL 可以在任何地方。在这种情况下,我觉得将 DLL 放在单独的文件夹中以保持整洁是有效的。只要您不将 DLL 放入共享位置,例如 Windows System32 文件夹,就可以避免很多麻烦。

【讨论】:

  • 如果您提供的只是搜索词和链接,则应改为评论。
  • @KenWhite 实际上,在这种情况下,搜索词和/或链接作为答案非常好,问题开始提到我会自己搜索,如果我知道要搜索什么词。但是话又说回来,这个答案仍然不一定能解决我的问题,它只是为主题提供一些有用的信息。
  • @Ken,请在 cmets 与答案上发布此政策的链接,以便我进行自我教育。
  • @David,我已添加到我的答案中,请相应地调整您的投票,并感谢肯在投票前的警告。
  • 实际上,这两种方法都不起作用。 :) 发布的链接没有回答所提出的问题,如果您删除了链接,则答案比以前更少。但无需进一步讨论;我已经发布了建议阅读,我想我们只是不同意您原始答案的有用性。 :) 而 cmets do 与答案不同;他们习惯于对原始问题评论,或要求澄清或补充信息,或提供不符合实际答案的建议(就像我认为你的那样)。
【解决方案5】:

临时解决方案是:

您可以在应用程序的快捷方式中设置您的 DLL 路径(在“开始于”框中)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-13
    • 2014-05-20
    • 1970-01-01
    • 2020-11-04
    • 2019-04-25
    • 2018-11-30
    • 2022-11-04
    相关资源
    最近更新 更多