windows 如何在工作线程(非 UI 线程)中创建模态对话框?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1968862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 13:39:21  来源:igfitidea点击:

How do I create Modal dialog in worker thread(Non-UI thread)?

c++windowsmfcwinapimodal-dialog

提问by aJ.

I have written a sample MFC application in which there are two threads: -Main thread ( UI thread) -Worker thread ( non-UI thread)

我编写了一个示例 MFC 应用程序,其中有两个线程:-主线程(UI 线程)-Worker 线程(非 UI 线程)

I have a specific requirement to create a Modaldialog in Non-UI ( worker thread). When I create the CDialogobject and call DoModalon the same, it works. The dialog gets created and acts as Modal to the application. ( Win XP SP2 machine) But this does not work in Windows 2003 server machine. The behavior in 2003 server is that, the Modal Dialog goes behind the application main Window and dialog will be brought to front only when I click on Main Window. It is not acting as Modal dialog to my application.

我有Modal在非 UI(工作线程)中创建对话框的特定要求。当我创建CDialog对象并调用DoModal它时,它可以工作。对话框被创建并作为应用程序的模态。(Win XP SP2 机器)但这在 Windows 2003 服务器机器上不起作用。2003 服务器中的行为是,模态对话框在应用程序主窗口后面,只有当我单击主窗口时,对话框才会出现在前面。它不充当我的应用程序的模态对话框。

What could be the problem -- any ideas?

可能是什么问题 - 有什么想法吗?

If creating UI controls in non-UI thread is the issue then is there any Win32 API which will allow me to link my worker thread to Main UI thread such that DoModalhappens in Main thread. I tried AttachThreadInputbut it is not working.

如果在非 UI 线程中创建 UI 控件是问题,那么是否有任何 Win32 API 允许我将我的工作线程链接到主 UI 线程,DoModal这样在主线程中发生。我试过AttachThreadInput但它不起作用。

回答by atzz

First of all, I'd like to agree with other posters that it's probably better to show the dialog on the main UI thread.

首先,我想同意其他海报,在主 UI 线程上显示对话框可能更好。

However, if you must, you can make a dialog on another thread modal with the following steps:

但是,如果必须,您可以通过以下步骤在另一个线程模态上创建对话框:

  1. Pass your active window as an owner when creating the dialog.
  2. When dialog is showing, iterate over your other windows and do them EnableWindow(FALSE). When the dialog is hiding, do the reverse. You will probably have to remember windows' enabled state and restore the original state, not just EnableWindow(TRUE).
  3. Ensure that accelerators and other global commands will be ignored while the dialog is shown.
  1. 创建对话框时,将活动窗口作为所有者传递。
  2. 当对话框显示时,遍历其他窗口并执行它们EnableWindow(FALSE)。当对话框隐藏时,执行相反的操作。您可能必须记住 Windows 的启用状态并恢复原始状态,而不仅仅是EnableWindow(TRUE).
  3. 确保在显示对话框时将忽略加速器和其他全局命令。

Note that (2) shouldn't be necessary provided that you do (1), but you've mentioned MFC, and I don't remember exactly how it behaves. It has it's own modal dialog implementation which may not exactly match Win32. If you're lucky, (1) and (3) will be enough.

请注意,如果您执行(1),则不需要(2),但是您已经提到了 MFC,我不记得它的确切行为。它有自己的模式对话框实现,可能与 Win32 不完全匹配。如果幸运的话,(1)和(3)就足够了。

回答by IInspectable

There is no reliable way to spread GUI modality across multiple threads. Every window is represented by an object referenced through a HWNDwhich in turn has thread affinity. This is a left-over from the 16-bit days of Windows, where there was no multi threading. Consequently the HWNDs are not protected against concurrent access. The Old New Thinghas an excellent series on "Thread affinity of user interface objects" (Part 123Addendum).

没有可靠的方法来跨多个线程传播 GUI 模式。每个窗口都由一个通过 a 引用的对象表示,该对象HWND又具有线程关联性。这是 Windows 的 16 位时代遗留下来的,当时没有多线程。因此,HWNDs 不受并发访问保护。Old New Thing有一个关于“用户界面对象的线程亲和性”的优秀系列(第1 2 3部分附录)。

Modality is implemented by first enabling the dialog window and then disabling its parent. The first step is safe while the second attempts to disable a window from a thread which is not the window's owning thread. Since en-/disabling windows modifies the object referenced through the HWNDit represents a race condition.

模态是通过首先启用对话窗口然后禁用其父级来实现的。第一步是安全的,而第二步尝试从不是窗口拥有线程的线程禁用窗口。由于启用/禁用窗口会修改通过HWND它引用的对象,因此它表示竞争条件。

The suggested solution is to confine your GUI to a single thread and communicate from your worker thread to the GUI thread to have it perform user interaction on the worker thread's behalf. The easiest way to accomplish this is to call SendMessagefrom the worker thread to block until the GUI thread's message handler returns. If the worker thread should continue to run while the dialog is displayed you could use PostMessageinstead and communicate back to the worker thread using PostThreadMessageor signaling a synchronization object like an Event Object.

建议的解决方案是将您的 GUI 限制在单个线程中,并从您的工作线程与 GUI 线程通信,让它代表工作线程执行用户交互。完成此操作的最简单方法是从工作线程调用SendMessage以进行阻塞,直到 GUI 线程的消息处理程序返回。如果在显示对话框时工作线程应继续运行,您可以改用PostMessage并使用PostThreadMessage或用信号通知同步对象(如Event Object)与工作线程通信。

回答by Georg Fritzsche

While i don't know about the specifics of dialog handling on Server 2003, the simplest workaround to get on the main thread would be to use a custom window message, do ::SendMessage()and display the dialog in the message handler.

虽然我不知道 Server 2003 上对话框处理的细节,但进入主线程的最简单的解决方法是使用自定义窗口消息,::SendMessage()在消息处理程序中执行并显示对话框。

回答by Pavel Radzivilovsky

I recommend you not to do what the question subject suggests, and confine all UI to one thread. If you need the other thread to communicate with the user, create some messaging mechanism that will ask the UI thread to do it, and transport the results back.

我建议您不要按照问题主题的建议进行操作,并将所有 UI 限制在一个线程中。如果您需要另一个线程与用户进行通信,请创建一些消息机制来要求 UI 线程执行此操作,并将结果传回。