【问题标题】:"Declare" statement as yet an other way to circumvent the .dll hell?“声明”声明是绕过 .dll 地狱的另一种方式?
【发布时间】:2026-01-22 11:20:09
【问题描述】:

令我惊讶的是,我发现 VB6 代码使用 Declare 语句来定义位于程序文件夹中的 .dll 中的函数,而无需在 Windows 上注册。这似乎是避免 .dll 地狱的一种超级简单的方法,而不必求助于并排清单。我可以在某处阅读更多关于此的内容吗?有障碍吗?

【问题讨论】:

    标签: vb6 dll


    【解决方案1】:

    Declare 语句用于“及时”绑定到非 ActiveX DLL。在您的程序“接触”一个声明的入口点之前,不会尝试加载该库。

    基本上和DLL Hell的话题一点关系都没有。

    思维混乱甚至会导致人们将 ActiveX DLL 放在“EXE 旁边”,这实际上会导致 DLL Hell,因为倾向于这样做的人也会使用糟糕的技术来安装和卸载应用程序。

    1. 设计不佳的应用程序部署会在 EXE 旁边放置一个常用共享的 DLL 或 OCX。
    2. 运行设计不佳的应用程序,VB6 运行时在注册表中找不到类,使用 Windows 启发式搜索 DLL,立即找到 EXE 旁边的 DLL 并调用其自注册入口点。
    3. 稍后安装使用相同 DLL/OCX 的无辜、设计正确的应用程序 B、C、D,并且它们的安装程序发现该库已注册。
    4. 设计不佳的应用程序 A 会被卸载,通常只需在 Program Files 中删除其文件夹即可。
    5. 应用程序 B、C 和 D(以及任何未来使用该库的应用程序)现在已损坏 - 由于孤立的组件注册指向不存在的库。

    故事的寓意:

    永远,永远,永远不要在安装时将 DLL 放在您的 VB6 应用程序“旁边”。如果您有不与其他应用程序共享的私有 DLL,即便如此,请将它们放入应用程序文件夹下的 libs 等文件夹中。可能的例外可能是非 COM DLL,例如您希望使用 Declare 的那些。

    对于manifest也有很多误解,其中有很多种。您可能想到的是应用程序和程序集清单。

    这些可用于在并行安装的库的不同版本中进行选择,或者它们可用于隔离与 DLL Hell 相关的应用程序和程序集。

    当然,应用程序清单可用于指定 Windows 应如何运行应用程序的许多其他事项。

    【讨论】:

    • 这在一定程度上很有启发性。那么,.dll 注册的,只是在第一次使用?我对您对非 Com .dll 的含义感到有些困惑。我怎么知道 .dll 不是 Com?将自制的 ActiveX-dll 放在应用程序的子文件夹中似乎比将其放入应用程序文件夹本身要好一些:您仍然会在卸载时将其丢弃。
    • @Dabbleml,并不是所有的DLL都被注册了;只有包含 COM 对象的才需要注册。有很多很多与 COM 无关的 DLL(例如,很多 Windows API DLL 本身)。没有简单的方法可以区分它们。您可以检查一下 DLL 是否包含类型库。将您的 DLL 放在 LIB 子文件夹而不是您的应用程序的文件夹中可以防止它们被无意加载;请参阅我在上面的答案中为 LoadLibrary 提供的链接,了解原因(提示:这是函数使用的默认搜索位置)。
    【解决方案2】:

    Windows 在一个有据可查的文件夹序列中搜索LoadLibrary(VB6 在后台使用它来解析Declare 声明)。由于搜索文件夹列表中的第一个位置是应用程序自己的文件夹,因此您的发现非常有意义。

    不过,它在大多数情况下并不能解决“DLL 地狱”问题。例如,它不适用于系统 DLL,因为 Windows 预加载了其中的大部分。此外,如果 DLL 已加载到内存中,Windows 可能会使用该 DLL 的副本(不共享数据,但可以重用代码)。

    这是创建清单的部分原因;它们允许应用程序严格定义所需的系统 DLL 版本,以提供某些功能。 VB6 的技术是老式的(就像 VB6)。

    【讨论】: