Сделать это средствами обычных диспетчеров SObjectizer не представляется возможным, т.к. обработчики событий агентов вызываются на контекстах рабочих нитей диспетчера. А методы объекта-окна желательно вызывать на контексте главной нити приложения (либо нити, на которой осуществляется выборка и диспетчеризация оконных сообщений).
Диспетчер so_4::disp::win_ui предназначен для того, чтобы объекты-окна можно было делать агентами. Вызов обработчиков событий этих агентов будет осуществляться на контексте главной нити.
Диспетчер so_4::disp::win_ui нуждается в дополнительном диспетчере, который будет использоваться для диспетчеризации событий обычных агентов, а так же обслуживанием отложенных и переодических сообщений.
Когда создается объект диспетчера so_4::disp::win_ui автоматически создается невидимое окно и отдельная очередь заявок для диспетчеризации событий.
При диспетчерезации события диспетчер so_4::disp::win_ui определяет, является ли агент-владелец события агентом главной нити. Если нет, то событие диспетчеризируется дополнительным диспетчером. Если же событие относится к агенту главной нити, то событие помещается в отдельную очередь заявок, а невидимому окну отсылается специальное оконное сообщение. Получив такое сообщение функция невидимого окна проходит по отдельной очереди заявок и выполняет все заявки, которые в ней оказались.
Невидимое окно создается при создании объекта диспетчера. Поэтому важно, чтобы вызов so_4::disp::win_ui::create_disp осуществлялся на контексте главной нити приложения (либо на контексте той нити, на которой осуществляется выборка и диспетчерезация оконных сообщений). Но вызов so_4::api::start() нужно осуществлять на контексте любой другой нити, т.к. возврат из so_4::api::start() осуществляется только при завершении работы run-time SObjectizer. Поэтому, если вызвать so_4::api::start() на контексте главной нити, то приложение остановится в месте вызова so_4::api::start().
libs += "lib/so_disp_win_ui_4" + so_version;
// mfc_client.cpp : Defines the class behaviors for the application. // #include <sample/distribute/mfc_client/stdafx.h> #include "mfc_client.h" #include "mfc_clientDlg.h" #include <memory> #include <so_4/rt/h/rt.hpp> #include <so_4/api/h/api.hpp> #include <so_4/mutex/h/mutex.hpp> // // В качестве обычного диспетчера будет использоваться // диспетчер с активными объектами. В качестве нити // таймера -- простейшая нить таймера. // #include <so_4/timer_thread/simple/h/pub.hpp> #include <so_4/disp/active_obj/h/pub.hpp> #include <so_4/disp/win_ui/h/pub.hpp> #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // CMfc_clientApp BEGIN_MESSAGE_MAP(CMfc_clientApp, CWinApp) //{{AFX_MSG_MAP(CMfc_clientApp) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code! //}}AFX_MSG ON_COMMAND(ID_HELP, CWinApp::OnHelp) END_MESSAGE_MAP() // CMfc_clientApp construction CMfc_clientApp::CMfc_clientApp() { // TODO: add construction code here, // Place all significant initialization in InitInstance } // The one and only CMfc_clientApp object CMfc_clientApp theApp; // // Нить, на которой будет происходить запуск SObjectizer-а // // Конструктор этого объекта создает диспетчеры. Поэтому // объект sobj_thread_t должен создаваться на контексте // главной нити. // class sobj_thread_t : public so_4::mutex::thread_t { public : sobj_thread_t(); virtual ~sobj_thread_t(); protected : std::auto_ptr< so_4::timer_thread::timer_thread_t > m_timer_ptr; std::auto_ptr< so_4::rt::dispatcher_t > m_disp_ptr; std::auto_ptr< so_4::rt::dispatcher_t > m_main_disp_ptr; virtual void body(); }; sobj_thread_t::sobj_thread_t() : // Создания нити таймера. m_timer_ptr( so_4::timer_thread::simple::create_timer_thread() ), // Создание дополнительного диспетчера, который будет // использовать нить таймера. m_disp_ptr( so_4::disp::active_obj::create_disp( *m_timer_ptr ) ), // Создание диспетчера главной нити. Он использует // дополнительный диспетчер для работы с обычными агентами. m_main_disp_ptr( so_4::disp::win_ui::create_disp( *m_disp_ptr ) ) { } sobj_thread_t::~sobj_thread_t() { } void sobj_thread_t::body() { // Этот метод вызывается на контексте новой нити. // Можно запустить диспетчер главной нити. so_4::ret_code_t rc = so_4::api::start( *m_main_disp_ptr, 0 ); if( rc ) { std::cerr << "start: " << rc << std::endl; } } // CMfc_clientApp initialization BOOL CMfc_clientApp::InitInstance() { // Приложение стартовало. Метод InitInstance вызывается // на контексте главной нити. Самое время создать диспетчер // и запустить SObjectizer. sobj_thread_t sobj_thread; sobj_thread.start(); CMfc_clientDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } // Завершаем работу SObjectizer... so_4::api::shutdown(); // ... и ждем, пока завершится вспомогательная нить. sobj_thread.wait(); // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application's message pump. return FALSE; }