Здраствуйте. По прежнему пишу свою программу, она уже давно работает, но есть ряд проблемм.
В роли клиентской части выступает программа, пользовательский интерфейс которой основан на Win32API MDI (без использования MFC). По некоторым причинам, там используется многопоточность и каждое дочернее окно MDI приложение работает в своем потоке. Проблемма в том, что в дочерних окнах не работает переключение раскладок, и для того, чтобы сменить раскладку на русскую, пользователю приходится перенести фокус на главное окно, переключить раскладку и вернуться к дочернему окну.. это не слишком удобно (хотя пользователи и не жалуются - они у меня верх мечтаний
)
Есть предположение, что данный баг вызван неправильной обработкой сообщений в многопоточном приложении. Вот как это примерно происходит (за вычетом несущественных деталей - если чтото покажется неясным, готов дать больше кода):
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
....
LC_KERNEL = new CClientKernel(); // Инациализация ядра программы
....
LC_KERNEL->Start(); // Запуск ядра
delete LC_KERNEL;
...
return ret;
}
DWORD dRes;
CClientKernel::Start() {
...
m_hWnd = ::CreateWindowEx(0, GUI_MAIN_WINDOW_CLASS, "Client",
WS_TILEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_MAXIMIZE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, (LPVOID)(some_info));
// some_info - некая структура, используемая окном для, тут она не важна.
// На самом деле, окно создается не непосредственно в этой функции, а через вызов мембера объекта класса CMainWin,
// описанного в другом файле. Но создание объекта производится в тут.
// (я субклассю окна, и в результате имею обект MainWin.)
// Но если приводить здесь весь код то это будет слишком длинно
...
// Запуск потоков ядра. В одном из этих потоков создаются сеансы
...
MSG msg;
while (GetMessage(&msg,hWnd,0,0)>0) {
if ( msg.hwnd == NULL)
continue;
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
...
return (LRESULT)msg.wParam;
}
Внутри одного из потоков ядра, создается обект сеанса. Сеанс запускает отдельный поток и там создает свое дочернее окно через вызов метода главного окна приложения (приведен код этого метода):
int CMDIMainFrame::MDI_CreateClientWnd(CMenu * WindowMenu) {
// Создание дочернего окна
CLIENTCREATESTRUCT ccs;
ccs.hWindowMenu = WindowMenu->GetHandle();
ccs.idFirstChild = IDM_WINDOWCHILD;
// Create the MDI client window.
m_hWndClient = CreateWindowEx(0, "MDICLIENT", (LPCTSTR) NULL, WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
0, 0, 0, 0, m_hWnd, (HMENU) 0xCAC, App->GetInstance(), (LPSTR) &ccs);
::ShowWindow(m_hWndClient, SW_SHOW);
return true;
}
После чего, в этом потоке сеанса запускается цикл обработки соообщений:
MSG msg;
while (GetMessage(&msg,hWnd,0,0)>0) {
if ( msg.hwnd == NULL)
continue;
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
return (LRESULT)msg.wParam;
Таким образом, главное окно (FRAME) и дочерние окна (MDI_CHILD) работают каждое в своем потоке и у всех есть свой цикл обработки сообщений.. Никакого упоминания о том, как производить обработку сообщений в многопоточных MDI приложениях, в MSDN я не нашел, однако меня смущает то, что во всех случаях циклы обработки ничем не отличаются.
По поводу переключения раскладок. Spy++ показал следующее (для поля вводе на дочернем окне при попытке сменить раскладку):
<00115> 076A05A4 P WM_KEYDOWN nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00116> 076A05A4 P WM_KEYDOWN nVirtKey:VK_SHIFT cRepeat:1 ScanCode:2A fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00117> 076A05A4 P WM_INPUTLANGCHANGEREQUEST fSysCharset:True hkl:04190419
<00118> 076A05A4 S ..WM_IME_NOTIFY dwCommand:00000001 dwData:00000000
<00119> 076A05A4 R ..WM_IME_NOTIFY
<00120> 076A05A4 S ..WM_IME_NOTIFY dwCommand:00000002 dwData:00000000
<00121> 076A05A4 R ..WM_IME_NOTIFY
<00122> 076A05A4 S WM_INPUTLANGCHANGE charset:204 hkl:04190419
<00123> 076A05A4 S .WM_IME_NOTIFY dwCommand:0000000A dwData:00000000
<00124> 076A05A4 R .WM_IME_NOTIFY
<00125> 076A05A4 R WM_INPUTLANGCHANGE
<00126> 076A05A4 P WM_KEYUP nVirtKey:VK_SHIFT cRepeat:1 ScanCode:2A fExtended:0 fAltDown:0 fRepeat:1 fUp:1
<00127> 076A05A4 P WM_INPUTLANGCHANGEREQUEST fSysCharset:True hkl:04090409
<00128> 076A05A4 S ..WM_IME_NOTIFY dwCommand:00000001 dwData:00000000
<00129> 076A05A4 R ..WM_IME_NOTIFY
<00130> 076A05A4 S ..WM_IME_NOTIFY dwCommand:00000002 dwData:00000000
<00131> 076A05A4 R ..WM_IME_NOTIFY
<00132> 076A05A4 S WM_INPUTLANGCHANGE charset:0 hkl:04090409
<00133> 076A05A4 S .WM_IME_NOTIFY dwCommand:0000000A dwData:00000000
<00134> 076A05A4 R .WM_IME_NOTIFY
<00135> 076A05A4 R WM_INPUTLANGCHANGE
<00136> 076A05A4 P WM_KEYUP nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:1 fUp:1
А вот - что он же выдает при смене раскладки на главном окне (там есть листбокс):
<00178> 03820560 P WM_KEYDOWN nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00179> 03820560 P WM_KEYDOWN nVirtKey:VK_SHIFT cRepeat:1 ScanCode:2A fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00180> 03820560 P WM_INPUTLANGCHANGEREQUEST fSysCharset:True hkl:04090409
<00181> 03820560 P WM_KEYUP nVirtKey:VK_SHIFT cRepeat:1 ScanCode:2A fExtended:0 fAltDown:0 fRepeat:1 fUp:1
<00182> 03820560 P WM_INPUTLANGCHANGEREQUEST fSysCharset:True hkl:04090409
<00183> 03820560 S ..WM_IME_NOTIFY dwCommand:00000001 dwData:00000000
<00184> 03820560 R ..WM_IME_NOTIFY
<00185> 03820560 S ..WM_IME_NOTIFY dwCommand:00000002 dwData:00000000
<00186> 03820560 R ..WM_IME_NOTIFY
<00187> 03820560 S WM_INPUTLANGCHANGE charset:0 hkl:04090409
<00188> 03820560 R WM_INPUTLANGCHANGE
<00189> 03820560 P WM_KEYUP nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:1 fUp:1
ПС. Кстати интересная деталь - данный баг наблюдается при запуске клиента в WinXP. Когда программа была запущена под Win2k такой проблеммы не было!
ППС. Проблемма существует уже давно, однако решить ее никак не удается. Я уже два раза открывал топик на эту тему, но это ничего не дало
. Буду признателен за любые мысли