Как создать модальное диалоговое окно в рабочем потоке (поток без пользовательского интерфейса)?

Я написал образец приложения MFC, в котором есть два потока: - основной поток (поток пользовательского интерфейса) - рабочий поток (поток, не связанный с пользовательским интерфейсом).

У меня есть особое требование создать диалоговое окно Modal в Non-UI (рабочий поток). Когда я создаю объект CDialog и вызываю для него DoModal, он работает. Диалоговое окно создается и действует как модальное для приложения. (Машина Win XP SP2) Но это не работает на сервере Windows 2003. Поведение на сервере 2003 заключается в том, что модальное диалоговое окно выходит за главное окно приложения, и диалоговое окно будет отображаться на переднем плане только тогда, когда я нажимаю на главное окно. Он не действует как модальный диалог для моего приложения.

В чем может быть проблема, есть идеи?

Если проблема заключается в создании элементов управления пользовательского интерфейса в потоке, отличном от пользовательского интерфейса, то существует ли какой-либо API Win32, который позволит мне связать мой рабочий поток с основным потоком пользовательского интерфейса, чтобы DoModal происходило в основном потоке. Я попробовал AttachThreadInput, но это не работает.


person aJ.    schedule 28.12.2009    source источник


Ответы (4)


Прежде всего, я хотел бы согласиться с другими авторами, что, вероятно, лучше показывать диалог в основном потоке пользовательского интерфейса.

Однако, если необходимо, вы можете сделать диалог в другом потоке модальным, выполнив следующие действия:

  1. Передайте активное окно в качестве владельца при создании диалога.
  2. Когда отображается диалоговое окно, перебирайте другие окна и выполняйте их EnableWindow(FALSE). Когда диалоговое окно скрыто, сделайте обратное. Вам, вероятно, придется запомнить включенное состояние Windows и восстановить исходное состояние, а не только EnableWindow(TRUE).
  3. Убедитесь, что ускорители и другие глобальные команды будут игнорироваться во время отображения диалогового окна.

Обратите внимание, что (2) не обязательно, если вы выполняете (1), но вы упомянули MFC, и я точно не помню, как он себя ведет. Он имеет собственную реализацию модального диалога, которая может не совсем соответствовать Win32. Если вам повезет, (1) и (3) будет достаточно.

person atzz    schedule 28.12.2009

Не существует надежного способа распространения модальности графического интерфейса на несколько потоков. Каждое окно представлено объектом, на который ссылается HWND, который, в свою очередь, имеет сходство с потоком. Это пережиток 16-битных дней Windows, где не было многопоточности. Следовательно, HWND не защищены от одновременного доступа. В The Old New Thing есть отличная серия статей о сходстве потоков объектов пользовательского интерфейса» (Часть 1 2 3 Дополнение).

Модальность реализуется путем включения сначала диалогового окна, а затем отключения его родителя. Первый шаг безопасен, в то время как второй пытается отключить окно из потока, который не является потоком, владеющим окном. Поскольку включение/отключение окон изменяет объект, на который ссылается HWND, это представляет собой состояние гонки.

Предлагаемое решение состоит в том, чтобы ограничить ваш графический интерфейс одним потоком и обмениваться данными из вашего рабочего потока с потоком графического интерфейса, чтобы он выполнял взаимодействие с пользователем от имени рабочего потока. Самый простой способ сделать это — вызвать SendMessage. из рабочего потока для блокировки, пока не вернется обработчик сообщений потока GUI. Если рабочий поток должен продолжать работать, пока отображается диалоговое окно, вы можете использовать PostMessage и обмениваться данными с рабочим потоком, используя PostThreadMessage или сигнализация объекта синхронизации, например Объект события.

person IInspectable    schedule 16.12.2012

Хотя я не знаю об особенностях обработки диалогов на сервере 2003, самым простым обходным путем для доступа к основному потоку будет использование пользовательского оконного сообщения, выполнение ::SendMessage() и отображение диалога в обработчике сообщений.

person Georg Fritzsche    schedule 28.12.2009

Я рекомендую вам не делать то, что предлагает тема вопроса, и ограничить весь пользовательский интерфейс одним потоком. Если вам нужен другой поток для связи с пользователем, создайте какой-нибудь механизм обмена сообщениями, который попросит об этом поток пользовательского интерфейса и передаст результаты обратно.

person Pavel Radzivilovsky    schedule 28.12.2009