当 CDialog.DoModal() 函数无法创建对话框时?

Posted

技术标签:

【中文标题】当 CDialog.DoModal() 函数无法创建对话框时?【英文标题】:When CDialog.DoModal() function fails to create dialog box? 【发布时间】:2012-03-14 13:37:07 【问题描述】:

MSDN 说,对于 CDialog.DoModal() 函数,如果该函数无法创建对话框,则返回值为 –1。它没有说明在哪种情况下它可能无法创建对话框。

对 MFC 源代码的快速调查显示,如果 (LPCDLGTEMPLATE)LockResource(hDialogTemplate) 返回 NULL,则 DoModal 函数可能返回 -1。

由于我的问题在我们的压力测试中无法稳定重现,所以我无法调试程序找到根本原因。有没有人遇到过类似的问题?

【问题讨论】:

不得不使用 MFC,不是吗? @IntermediateHacker,我们不要把它变成“那个 API 很烂,为什么要使用它”的辩论,我们会在这里一整天。 @Moo-Juice 是的,但我对所讨论的 API 有非常糟糕的回忆。它让我毛骨悚然。 抱歉,我忘记了事件日志或 GetLastError 的内容。这是我的错。提出此类问题的最佳方法是将所有错误报告收集在一起并粘贴到此处。谢谢你给了我灵感。 【参考方案1】:

DoModal() 依赖于 CreateDialogIndirect() API 函数。其表弟DialogBox() 的文档指出,函数在以下情况下可能会失败:

无效的参数值, 系统类由不同的模块注册, WH_CBT 挂钩已安装并返回失败代码, 对话框模板中的某个控件未注册,或其窗口过程在WM_CREATEWM_NCCREATE 上失败。

我个人从来没有遇到过前三个原因,但是我被第四个原因咬过一次,因为我的对话框包含一个没有在机器上注册的 ActiveX 控件。也许您遇到了同样的问题。

【讨论】:

MFC 不使用DialogBox,它用其他调用模拟它。不过,此答案中的某些信息仍然有用。 @Mark,你说得对,它使用CreateDialogIndirect() 甚至用于模态对话框,并实现模态状态本身。我想知道为什么,但可能有一个很好的理由。谢谢你的澄清:) 更改区域设置后,DoModal 调用失败:新资源缺少原始资源的一些 ID。我报告这一点,希望能给遇到类似问题的其他人提供提示。【参考方案2】:

我发现根本原因来自用尽的 GDI 对象。我们的软件存在句柄泄漏。 GDI 对象的最大数量可以在注册表中设置。在我们的 Windows XP 中,该值为 16000。我编写了一个程序来创建大量 UI 控件而不是释放它们。通过这种方式我可以模拟GDI句柄耗尽的情况。结果,同样的问题再次重现。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\GDIProcessHandleQuota

参考:http://msdn.microsoft.com/en-us/library/windows/desktop/ms724291%28v=vs.85%29.aspx

那么最终的结论是,当GDI对象用尽时,一些UI控件比如CDialog,会创建失败?

【讨论】:

在 Win32 上运行/调试具有复杂 GUI(CAD、EDA)的应用程序时,句柄耗尽是一个众所周知的问题。在 Win64 上,我们没想到会出现 Out of Handles 问题。

以上是关于当 CDialog.DoModal() 函数无法创建对话框时?的主要内容,如果未能解决你的问题,请参考以下文章

MFC(C++)CDialog DoModal()没有按预期工作

如何准确找到调用了哪个类 DoModal() ?

当他们的构造函数参数被依赖注入时如何实例化子演员?

如何在应用打开时创建一次事件?

Autofac为新线程创建子范围不能按预期工作“无法解析实例,无法创建嵌套生命周期......”

爱创课堂每日一题-Javascript垃圾回收方法?