【问题标题】:delphi finalizalization code in a DLLDLL中的delphi最终化代码
【发布时间】:2011-01-11 18:08:51
【问题描述】:

我正在将一些函数移动到一个共享的 DLL 中(我希望将一些函数称为 Windows 挂钩)。

实际函数目前在unit中,恰好有一些initialization和一些finalization代码。

我最初考虑将unit 直接转换为library。所以我将initialization 代码移到了主beginend. 之间。但后来我意识到我没有地方可以移动finalization 代码。相反,我应该创建并注册一个特殊的 DLL 入口点。

我的问题是。我可以保留unit 的所有功能以及initializationfinalization 代码,只创建一个library 存根uses 单元吗? finalizationit 会被调用吗?

【问题讨论】:

    标签: delphi dll


    【解决方案1】:

    DLL 中单元的初始化部分中的代码将在 DLL 首次加载到进程中时运行。当 DLL 从进程中卸载时,终结部分会触发。

    Eugene 是对的,您可以使用 DLLProc 进行更细粒度的控制,但这通常仅适用于每个线程的资源,例如线程本地存储。

    我要指出,在DLLMain 期间可以做的事情有严重的限制,这最终是这些初始化/完成部分在库中的起源。 MSDN 文档基本上说您可以做一些事情,但没有可接受的行为列表。最接近的是说您可以在 kernel32 中调用函数。否则,所有赌注都取消!

    网上有很多文章描述了这个问题,但除了我上面链接的 DLLMain 的 MSDN 主题之外,我建议阅读 Microsoft 的 Best Practices for Creating DLLs

    MSDN 提供的有用建议是,该库可以强制其用户在使用 DLL 之前调用初始化函数。完成 DLL 后,将调用相应的终结函数。 comctl32.dll的使用就是采用这个成语,见InitCommonControlsEx

    在我自己的代码中,我更喜欢另一种方法。我所有单元的初始化部分都注册了初始化和终结方法。然后,在第一次调用我的库中的任何导出函数时,初始化方法会按照它们注册的顺序运行。这对我来说不是问题,因为我已经控制了我的库的所有入口/出口点。

    我知道这超出了您的要求,但您可能会发现这有助于避免一些难以调试的问题。

    【讨论】:

    • +1。简而言之,完成部分中的代码被调用,但由于操作系统加载程序锁定,您可能不希望它这样做。避免可能的死锁:导出显式初始化和终结函数以供宿主进程调用。
    • @Jeroen 我本来打算链接到那篇文章,但这有点像牧师的鸡蛋,Raymond 链接的文章似乎已被 MS 链接腐烂吃掉了。我找到的最佳参考是microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx
    • 太棒了;感谢您挖掘这篇更好的文章。希望我能两次 +1。
    【解决方案2】:

    一个单元的初始化将被调用,如果它是一个程序,如果它是一个库。

    最终确定也是如此。

    所以是的,您可以保留该单元并导出所需的功能。

    【讨论】:

      【解决方案3】:

      我建议您实现一个 DLLMain 并通过为每种情况调用专用过程/函数来处理不同的情况(进程附加、线程附加等)。然后,如果您需要从 DLL 切换到单元,则可以从初始化和完成调用所需的过程/函数。原因是当 DLL 与线程连接/分离时,您可能需要一些细粒度的控制(这将在您设置系统范围的挂钩时发生)。

      【讨论】:

      • 你不应该这样做,旧新事物解释了原因:blogs.msdn.com/b/oldnewthing/archive/2004/01/27/63401.aspx
      • @Jeroen 这就是文字。事实上,在很多情况下实现系统范围的钩子(我写了一堆)时,您需要使用 DLLMain 并跟踪线程附件。这是由于系统范围的钩子的性质造成的。
      【解决方案4】:

      这也发生在我身上。 我发现我有一个单元,即在注册 dll 时创建线程或做一些事情的初始化部分。

      我已经删除了这个初始化部分,它工作正常。

      因为 .exe 应用程序需要初始化,而 dll 应用程序不需要初始化, 系统实用程序中有一个变量标志,称为 ModuleIsLib 做吧:

      initialization
      
      if not ModuleIsLib then
       begin
      // initialization stuff for .exe file
       end;
      

      这也可以用于完成部分。

      希望它有所帮助..!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-26
        • 1970-01-01
        • 2016-06-01
        • 1970-01-01
        • 2011-07-20
        • 2010-09-28
        相关资源
        最近更新 更多