简体   繁体   中英

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

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

I have a specific requirement to create a Modal dialog in Non-UI ( worker thread). When I create the CDialog object and call DoModal on 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.

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 DoModal happens in Main thread. I tried AttachThreadInput but it is not working.

There is no reliable way to spread GUI modality across multiple threads. Every window is represented by an object referenced through a HWND which 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 HWND s are not protected against concurrent access. The Old New Thing has an excellent series on "Thread affinity of user interface objects" (Part 1 2 3 Addendum ).

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 HWND it represents a race condition.

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 SendMessage from 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 PostMessage instead and communicate back to the worker thread using PostThreadMessage or signaling a synchronization object like an Event Object .

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.

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.

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.

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM