Delphi:注销应用程序时表单无法释放时该怎么办
我正在使用 Delphi (7-2010) 并试图找出一种在释放应用程序形式的同时处理异常的好方法。应用程序有多个由 Application 对象拥有的表单。当用户注销时,我需要释放所有现有表单,以便不维护用户状态,然后为下一个登录的用户显示登录对话框。
有时,在尝试释放其中一个表单时会发生异常。这会将表单留在内存中,但处于未知/不可用状态,因此我无法为下一个用户重新使用该表单,而且我也无法将其从内存中删除。因为表单归应用程序所有,所以我无法直接为下一个用户创建表单的新版本,因为这会导致 VCL 出现“名为 MyForm 的组件已存在”错误,而且我有点不喜欢无论如何,在内存中保留旧的表单实例。
我想看看其他人在这种情况下会做什么。这里有一些想法:
- 当您遇到这些异常时,终止应用程序,这样您就可以将所有的记录都擦干净。无论如何,用户都会退出,因此他们可能已经完成了该应用程序的操作。如果需要,可以选择重新启动应用程序。
- 使表单不属于应用程序,以便您可以创建它们的多个实例,并确保至少隐藏任何不可释放/损坏的表单。
- 动态生成每个表单的名称,或将其设置为空白,因此永远不会有重复的名称,并且 VCL 不会出现“已存在”错误。
- 将应用程序编写得很好,以便在释放对象时永远不会出现异常(不现实 - 我需要针对意外错误制定应急计划)。
My Solution was one of the original ideas above. I added a try/except block around the loop that frees the forms, and if there is an exception, I show the error message to the user without raising it, and then call ExitProcess(0) to immediately kill the application.
I'm using Delphi (7-2010) and trying to figure out a good way to handle exceptions while freeing forms of an application. The application has several forms that are owned by the Application object. When the user logs out, I need to free all of the existing forms so no user state is maintained and then show the login dialog for the next user who logs in.
Occasionally, an exception happens while trying to free one of the forms. That leaves the form in memory, but in an unknown/unusable state, so I can't re-use the form for the next user, and I also can't get rid of it from memory. Because the forms are owned by the application, I can't directly create a new version of the form for the next user, since it would cause the "A component named MyForm already exists" error from the VCL, and I'm bit averse to having old form instances in memory anyway.
I'd like to see what others would do in this case. Here are some ideas:
- Terminate the application when you get these exceptions, so you are sure to wipe the slate clean. The user is logging out anyway, so they are likely done with the app. Optionally restart the app if desired.
- Make the forms not owned by the Application, so you can create multiple instances of them, and make sure any non-freeable/broken forms are at least hidden.
- Dynamically generate the name of each form, or set it to blank, so there are never duplicate names, and no "already exists" errors from the VCL.
- Write an application so well that there are never exceptions when freeing objects (unrealistic - I need a contingency plan for unexpected errors).
My Solution was one of the original ideas above. I added a try/except block around the loop that frees the forms, and if there is an exception, I show the error message to the user without raising it, and then call ExitProcess(0) to immediately kill the application.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
确实没有好的方法来处理析构函数中引发的异常。我不会认为期望它们永远不会被引发是“不现实的”,因为析构函数不应该做任何可能导致异常的事情。如果您除了释放内存或其他清理(释放句柄、关闭连接等)之外正在执行任何操作,那么您几乎肯定做错了什么。
顺便说一句,是什么导致了异常?您能够一致地重现该错误吗?您最好的行动方案就是修复错误。他们的数量不应该太多。
There's really no good way to handle exceptions raised from within a destructor. And I wouldn't call it "unrealistic" to expect them never to be raised, since a destructor shouldn't do anything that can cause an exception. If you're doing anything except freeing memory or other cleanup, (releasing handles, closing connections, etc.) you're almost certainly doing something wrong.
What's causing the exceptions, BTW? Are you able to reproduce the error consistently? Your best course of action is to just fix the errors. There shouldn't be too many of them.
大多数时候,销毁表单时会发生错误,因为仍有一些事件处理程序正在执行并引用已销毁的对象。
这就是为什么在这种情况下创建
TForm.Release
来代替TForm.Free
的原因。来自帮助:
使用 Release 来销毁表单并释放其关联的内存。
在窗体的所有事件处理程序和窗体上组件的事件处理程序执行完毕之前,Release 不会销毁窗体。释放还保证在释放表单之前处理表单事件队列中的所有消息。窗体或其子窗体的任何事件处理程序都应使用 Release 而不是 Free (Delphi) 或删除 (C++)。否则可能会导致内存访问错误。
Most of the time, errors happen when destroying forms because there is still some event handler executing and referring to an already destroyed object.
That's why
TForm.Release
has been created to be used in place ofTForm.Free
in such cases.From the help:
Use Release to destroy the form and free its associated memory.
Release does not destroy the form until all event handlers of the form and event handlers of components on the form have finished executing. Release also guarantees that all messages in the form's event queue are processed before the form is released. Any event handlers for the form or its children should use Release instead of Free (Delphi) or delete (C++). Failing to do so can cause a memory access error.