Добрый день, Есть проблема - не работает переключение раскладок клавиатуры при фокусе в окне Edit. Родительское окно создаю так: Код (Text): HWND hWnd = CreateWindowExA(WS_EX_APPWINDOW, szWndClassName, "", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 100, 100, 600, 300, hwParent, 0, 0, 0); Edit создается в обработчике WM_CREATE так: Код (Text): g_hwEdit = CreateWindowExA(0, szEdit, 0, WS_CHILD | ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL | WS_VSCROLL, 0, 0, 0, 0, hWnd, (HMENU)(MY_ED_MSG), 0, 0); далее, устанавливаем его размеры: Код (Text): SetWindowPos(g_hwEdit, 0, 25, rect.bottom - YMIN + 320, rect.right - XMIN + 266, 102, SWP_NOZORDER); Spy++ не показывает входящих сообщений WM_INPUTLANGCHANGE ни в родительском окне, ни в Edit'е. Если я создаю диалог, бросаю на него Edit и использую свою оконную функцию (обработчик) как обработчик диалога (с заменой типа функции LRESULT на INT_PTR) - все переключается нормально. Но основная цель - сделать как раз без использования диалогов, поставляемых из ресурсов. Не знаете ли вы, в чем может быть проблема? Спасибо.
единственное что приходит в голову - сравни стили диалогового эдита и твоего каким-нибудь WinSpy. ещё меня настораживает вот эта фраза: ты, случаем WM_INPUTLANGCHANGE не перехватываешь?
maksim_ Не перехватываю. Пробовал - управление туда не приходит Спаем сравнивал - стили совпадают у Edit'ов, но у основного окна при создании в режиме диалога добавляются несколько DS_* стилей: DS_SETFONT | DS_SYSFONT. При этом, если edit создавать на диалоге вручную, то все обрабатывается нормально. А если вызвать контекстное меню в edit, и нажать комбинацию клавиш, переключающих раскладку - то она переключается!
скопировал код из msdn - всё работает норм. Код (Text): LRESULT CALLBACK MainWndProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam) // second message parameter { switch (uMsg) { case WM_CREATE: CreateWindowEx(0, L"edit", L"edit1", WS_CHILD | WS_VISIBLE, 10, 10, 200, 50, hwnd, NULL, NULL, NULL); // Initialize the window. return 0; case WM_PAINT: // Paint the window's client area. return 0; case WM_SIZE: // Set the size and position of the window. return 0; case WM_DESTROY: // Clean up window-specific data objects. return 0; // // Process other messages. // default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } BOOL InitApplication(HINSTANCE hinstance) { WNDCLASSEX wcx; // Fill in the window class structure with parameters // that describe the main window. wcx.cbSize = sizeof(wcx); // size of structure wcx.style = CS_HREDRAW | CS_VREDRAW; // redraw if size changes wcx.lpfnWndProc = MainWndProc; // points to window procedure wcx.cbClsExtra = 0; // no extra class memory wcx.cbWndExtra = 0; // no extra window memory wcx.hInstance = hinstance; // handle to instance wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION); // predefined app. icon wcx.hCursor = LoadCursor(NULL, IDC_ARROW); // predefined arrow wcx.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH); // white background brush wcx.lpszMenuName = L"MainMenu"; // name of menu resource wcx.lpszClassName = L"MainWClass"; // name of window class wcx.hIconSm = (HICON)LoadImage(hinstance, // small class icon MAKEINTRESOURCE(5), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); // Register the window class. return RegisterClassEx(&wcx); } BOOL InitInstance(HINSTANCE hinstance, int nCmdShow) { HWND hwnd; HINSTANCE hinst; // Save the application-instance handle. hinst = GetModuleHandle(0); // Create the main window. hwnd = CreateWindow( L"MainWClass", // name of window class L"Sample", // title-bar string WS_OVERLAPPEDWINDOW, // top-level window CW_USEDEFAULT, // default horizontal position CW_USEDEFAULT, // default vertical position CW_USEDEFAULT, // default width CW_USEDEFAULT, // default height (HWND) NULL, // no owner window (HMENU) NULL, // use class menu hinstance, // handle to application instance (LPVOID) NULL); // no window-creation data if (!hwnd) return FALSE; // Show the window and send a WM_PAINT message to the window // procedure. ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); return TRUE; } BOOL Main() { MSG msg; HINSTANCE hinstance = GetModuleHandle(0); if (!InitApplication(hinstance)) return FALSE; if (!InitInstance(hinstance, SW_SHOWNORMAL)) return FALSE; BOOL fGotMessage; while ((fGotMessage = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0 && fGotMessage != -1) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }
proc Покажите обработчик оконной процедуры. Что происходит, когда приходит WM_INPUTLANGCHANGEREQUEST?
G13 Обработчик оконной процедуры следующий (для уменьшения места и улучшения читабельности не относящиеся к делу фрагменты кода были удалены): Код (Text): LRESULT __stdcall ChatWndFun(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND hwTemp; int iLength; char * pText; NMHDR * hdr; LPNMITEMACTIVATE lpnmia; PAINTSTRUCT ps; HDC dc; LPMEASUREITEMSTRUCT lpmis; LPDRAWITEMSTRUCT lpdis; RECT rect; int i; switch (Msg) { case WM_CREATE: // создать все дочерние окна // непосредственно здесь производится создание Edit g_cChat.Init(); // другая инициализация // ... break; case WM_SHOWWINDOW: // установить курсор SetCursor(LoadCursor(hInst, IDC_ARROW)); // показать окно // здесь производится установка размеров дочерних окон, в том числе и Edit g_cChat.Show(); break; case WM_GETMINMAXINFO: { // установим размеры для окна MINMAXINFO * pInfo = (MINMAXINFO *) lParam; pInfo->ptMinTrackSize.x = g_cChat.GetMinX(); pInfo->ptMinTrackSize.y = g_cChat.GetMinY(); return (0); } case WM_PAINT: dc = BeginPaint(hWnd, &ps); g_cChat.DrawMain(dc); EndPaint(hWnd, &ps); break; case WM_MEASUREITEM: lpmis = (LPMEASUREITEMSTRUCT) lParam; lpmis->itemHeight = plMain.m_iListElHeight; return (TRUE); case WM_DRAWITEM: lpdis = (LPDRAWITEMSTRUCT) lParam; // отрисовка элементов plMain.ProcessDrawItem(lpdis); g_cChat.DrawButtons(lpdis); g_cChat.DrawTabs(lpdis); return (TRUE); case WM_CONTEXTMENU: // ... break; case WM_SIZE: // изменить размеры + показать окно g_cChat.Show(); break; // Здесь идет несколько пользовательских обработчиков со значениями WM_USER + 0x400+ // ... // обработка событий от контролов case WM_NOTIFY: if (LOWORD(wParam) == IDC_CHAT_TABS) { hdr = (LPNMHDR)lParam; if (hdr->code == NM_CLICK) { // переключить на нужного пользователя pText = g_cChat.GetSelectedTabName(); g_cChat.ShowView(pText); } } else if (LOWORD(wParam) == IDC_DT_FROM || LOWORD(wParam) == IDC_DT_TO) { // обрабатываем изменения выборки plMain.SetControlPos(false); InvalidateRect(hWnd, 0, TRUE); } break; case WM_COMMAND: // обработчики нажатия кнопок return (0); case WM_CLOSE: ShowWindow(hWnd, SW_HIDE); break; default: return (DefWindowProc(hWnd, Msg, wParam, lParam)); } return (0); } класс окна я инициализирую так: Код (Text): WNDCLASSA wc; SecureZeroMemory(&wc, sizeof(wc)); wc.lpszClassName = szChatWndClassName; wc.hInstance = hInst; wc.lpfnWndProc = ChatWndFun; wc.style = CS_HREDRAW | CS_VREDRAW; wc.hCursor = LoadCursor(hInst, IDC_ARROW); wc.hbrBackground = CreateSolidBrush(RGB(203, 203, 203)); RegisterClassA(&wc); Обрабатываю очередь сообщений так: Код (Text): HWND hWnd = CreateWindowExA(WS_EX_APPWINDOW, szChatWndClassName, "", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 600, 300, 0, 0, 0, 0); // цикл обработки сообщений окну MSG msg; BOOL bRet; while ((bRet = GetMessage(&msg, hWnd, 0, 0)) != 0) { if (bRet == -1) { DestroyWindow(hWnd); break; } TranslateMessage(&msg); DispatchMessage(&msg); }
G13 WM_INPUTLANGCHANGEREQUEST не приходит, к сожалению. Если бы он приходил, то можно было бы вручную сменить раскладку.
Пробую перехватить функцию обработки окна Edit: Код (Text): LRESULT __stdcall EditWndFun(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { if (Msg == WM_INPUTLANGCHANGEREQUEST) { MessageBox(hWnd, 0, 0, 0); } else return (CallWindowProc(g_cChat.GetOriginalEditWndProc(), hWnd, Msg, wParam, lParam)); } сообщение WM_INPUTLANGCHANGEREQUEST не приходит.
maksim_ В том-то и дело, что работает. За пример - спасибо. Я просто пытаюсь разобраться - с чем связаны проблемы именно в моем коде.
kero Дошло Вы абсолютно правы, заменив hWnd на 0 добился результатов. Большой спасибо вам, а также всем, принимавшим участие в обсуждении. Мне нужно было внимательнее читать msdn: Т.е. сообщение посылается Edit'у непосредственно, а не родительскому окну.
kero Опередил. proc, цитата из MSDN - правильная. Выводы - не совсем. Читаем внимательно описание PostMessage: и GetMessage: