为啥 IsDialogMessage() 可能永远不会返回?
Posted
技术标签:
【中文标题】为啥 IsDialogMessage() 可能永远不会返回?【英文标题】:Why might IsDialogMessage() never return?为什么 IsDialogMessage() 可能永远不会返回? 【发布时间】:2009-11-11 16:58:34 【问题描述】:我正在调试一个应用程序,该应用程序在其消息循环中调用IsDialogMessage()。有时, IsDialogMessage() 永远不会返回(其中 never 是大于 1 小时的间隔)。根据 Microsoft 符号服务器提供的 user32.dll 的符号,它似乎卡在 GetNextDlgGroupItem()(或相同的内部变体)中,在某些窗口集上进行迭代。
应用程序是多线程的,并且经常接收作为 DCOM 调用到达的外部事件通知。我怀疑这样的调用以破坏某些窗口状态的方式被错误地处理。如果我可以了解哪种状态损坏可能导致 IsDialogMessage() 中的无限循环,我想我将能够更轻松地识别损坏的来源。
【问题讨论】:
【参考方案1】:我知道这是旧的,但为后代回答,因为这里没有人提到它。
很可能发生的情况是 Windows 管理器无法确定将消息转发到何处。如果您有一个窗口层次结构,就像您可能做的那样,那么您需要确保包含控件本身的非***窗口必须具有 WS_EX_CONTROLPARENT 样式集。如果是对话框,则使用 DS_CONTROL 样式。这些标志的存在会修改 IsDialogMessage 的行为;他们将窗口识别为具有自己的控件,这些控件可以接收焦点和处理 Tab 键顺序等,而不仅仅是控件本身。
例如,如果你有一个主框架窗口,它有一个带有 WS_EX_CONTROLPARENT 的子窗口,它有一个子窗口没有 WS_EX_CONTROLPARENT,它有一个有焦点的子窗口,然后你点击 TAB ,您可能会在您提到的同一个地方遇到无限循环。
将第二个孩子的扩展样式设置为包含 WS_EX_CONTROLPARENT 将解决此问题。
【讨论】:
【参考方案2】:您是否可能禁用控件(使用::EnableWindow()
)而不首先检查该控件是否具有焦点?如果是,那么焦点会丢失并且 GetNextDlgGroupItem() 会混淆。
【讨论】:
这是可能的;有许多控件在起作用,有些可能会被禁用。【参考方案3】:发生这种情况的另一个原因是,如果您重新设置了无模式对话框的父级。至少 wxWidgets 会发生这种情况...
【讨论】:
【参考方案4】:我做了一些调查,试图回答这个问题。但仅在父窗口位于本机 MFC 项目中且子窗口是托管 C# Windows 窗体的情况下。如果您有这种情况,那么您可以尝试 3 个解决方案:
-
在 Windows 窗体端运行 MFC 对话框消息循环。这里有更多信息:Integrate Windows Forms Into Your MFC Applications Through C++ Interop
创建 2 个线程:一个用于 Windows 窗体对话框,一个用于本机对话框。在这里,您可以在 Windows 窗体中创建对话框,然后使用 SetParent() 将其父级设置为本机对话框。但请注意:如果将 TabControl 添加到 Windows 窗体,则会出现“IsDialogMessage() never return”挂起。
为 Windows 窗体对话框制作一个包装器以在本机项目中使用。例如,包装器可能是 WPF,请参见此处:Windows Form as child window of an unmanaged app
我的信息主要来自:http://msdn.microsoft.com/en-us/library/ms229600.aspx
暂时的治疗方法可以是改变焦点行为。例如,禁用它们,或仅将 SetFocus() 禁用到父窗口或子窗口。但我强烈建议调查真正的原因,为什么 IsDialogMessage() 在您的情况下永远不会返回。
【讨论】:
以上是关于为啥 IsDialogMessage() 可能永远不会返回?的主要内容,如果未能解决你的问题,请参考以下文章
我的渲染技术进阶之旅你可能永远猜不到为什么Filament项目命名为TNT?
我的渲染技术进阶之旅你可能永远猜不到为什么Filament项目命名为TNT?
我的渲染技术进阶之旅你可能永远猜不到为什么Filament项目命名为TNT?