微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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显式加载包的情况下,才会初始化/最终确定该包中的每个单元(以及该包).

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐