加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 为什么在关闭时不执行包的任何单元定型部分中的代码?

发布时间:2020-12-15 09:22:42 所属栏目:大数据 来源:网络整理
导读:我有一个应用程序,它使用静态链接的运行时包以及使用它们的设计时包.由于某种原因,任何单元终结部分中的代码都没有在运行时运行(我无法分辨何时开始发生). finalization ShowMessage('Goodbye');end. 关闭Delphi会显示消息,但不会在我的应用程序关闭时显示.
我有一个应用程序,它使用静态链接的运行时包以及使用它们的设计时包.由于某种原因,任何单元终结部分中的代码都没有在运行时运行(我无法分辨何时开始发生).

finalization
  ShowMessage('Goodbye');
end.

关闭Delphi会显示消息,但不会在我的应用程序关闭时显示.如果我在ShowMessage上设置一个断点,它会在那里中断,但不执行该行,这更令人讨厌.如果最终化中有多行,则调试器在第一行停止,不执行它然后跳转到结尾.

procedure ProcOne;
begin
  SomeObject.Free; // Debugger does not enter or stop here
  SomeObject := nil;
end;

finalization
  ProcOne; // Debugger stops here,doesn't execute,jumps to "end."
  ProcTwo; // Every line has a blue dot
  ShowMessage('Bye');
end.

ProcOne断点上的调用堆栈显示@ Halt0 => FinalizeUnits => MyPackage.MyUnit.Finalization.

如果我将该单元包含在不使用包的应用程序中,则一切都正常执行.

有谁知道可能导致这种情况的原因是什么?

编辑:

感谢Allen Bauer的评论指向了正确的方向,我已经设法解决了这个问题.如果使用运行时包构建应用程序,然后动态加载另一个也引用该包和单元的包,则似乎会出现问题.

我创建了一个演示问题的测试项目:TestFinalization

有谁知道这个和/或解决方法的原因?在您注意到外部资源未被清除之前,您通常可能不会注意到您的终结未运行.

解决方法

确保在关闭之前为每个动态加载的包调用UnloadPackage.如果您只是调用UnloadLibrary(或者只是依靠操作系统来卸载它们),那么就不会调用该包中的单元和其他包中的所有单元的最终结果.使用引用计数系统完成初始化和完成,因为面对动态加载的包,无法知道将初始化哪些单元以及何时初始化.只有当您使用初始化调用平衡终结调用时,最后的终结调用才会实际执行完成部分中的代码块.同样,只有第一次调用初始化部分才会实际执行代码块.

使用编译器生成的表为给定模块完成初始化/完成.当您构建与包链接的exe或dll时,此表包含对实际使用的所有单元的引用,甚至包括来自链接包的那些单元.请注意,实际上仅实际引用的单元已初始化. IOW,如果您在PackageA中有100个单位且exe只引用其中一个单位,则只会初始化该单位及其使用的任何单位.

对于动态加载的包,实际上无法知道实际使用哪些单元,因此编译器会生成init / finit表,就好像每个单元都已初始化一样.在调用LoadLibrary期间加载包时不处理此表,而是通过调用名为Initialize()的特殊导出来处理. LoadPackage函数确保调用此函数.此表仅确保初始化加载包中的所有单元.初始化只有实际触及任何其他包的单元,类似于我上面提到的exe / dll情况. UnloadPackge执行相反的操作,并在调用UnloadLibrary()之前调用特殊导出Finalize().

最后,如果您对使用任何打包单元的列表进行了更改并且仅重建了包,则可能会遇到令人困惑的情况,即使给定包中的单元正确地“相互使用”,也可能无法调用初始化/终结.这是因为init / finit由加载模块控制而不是从其自身内部控制.仅在使用LoadPackage显式加载包的情况下,才会初始化/最终确定该包中的每个单元(以及该包).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读