У меня есть 3 окошка. Диалоговое окно (hwnd_1) имеет одно дочернее (hwnd_2). Дочернее имеет окошко edit (hwnd_edit). мне нужно чтобы при нажатии в эдите кнопки Enter окно hwnd_2 ловило мессагу WM_COMMAND с wparam == IDC_EDIT. Но эта мессага идёт окошку hwnd_1. Что нужно сделать чтобы мессага шла именно второму окну? Второе окно я создаю след образом: Код (Text): m_hwnd_2 = CreateWindowEx(WS_EX_CONTROLPARENT, L"#pklasmfsdf", 0, WS_CHILD|WS_VISIBLE|WS_SIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwnd_prnt, (HMENU)IDC_EDIT, 0, 0);
Quark Кто родитель edit'а? Покажи экстрастили и стили edit'а. Как ты добился, чтобы "при нажатии в эдите кнопки Enter окно hwnd_1 ловило мессагу WM_COMMAND с wparam == IDC_EDIT"? Я знаю, что edit посылает своему родителю уведомление EN_CHANGE.
эдит нужно сабклассировать, иначе он - получает сообщение, но оно находится внутри ОС и обрабатывать наверное надо WM_CHAR
1) Диалоговое окно: hwnd1 - DialogBoxParam имеет стили OVERLAPPEDWINDOW|POPUP|VISIBLE|CLIPSIBLINGS|SOFTFONT|3DLOOK|FIXEDSYS|CENTER EX_WINDOWEDGE|WS_EX_CONTROLPARENT 2) hwnd2 = CreateWindowEx(WS_EX_ACCEPTFILES, wz_cls_name, 0, WS_CHILD|WS_VISIBLE|WS_SIZEBOX|WS_TABSTOP|WS_GROUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwnd1, (HMENU)IDC_WND2, 0, 0); 3) hwnd_edit = CreateWindowEx(0, L"Edit", 0, WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwnd2, (HMENU)IDC_EDIT1, 0, 0); при нажатии Enter в этите окошку hwnd2 вообще никаких мессаг не приходит. а окошку hwnd1 приходят, втч WM_COMMAND.
Урок 20 Сабклассинг окна Если вы уже некоторое время программируете в Windows, вы уже могли столкнуться с ситуацией, когда окно имеет почти все атрибуты, которые вам нужны, но не все. Сталкивались ли вы с ситуацией, когда вам требуется специальный вид edit control'а, который бы отфильтровывал ненужный текст? Первое, что может придти в голову, это написать свое собственное окно. Hо это действительно тяжелая работа, требующая значительного времени. Выходом является сабклассинг окна. Вкратце, сабклассинг окна позволяет получить контроль над сабклассированным окном. У вас будет абсолютный контроль над ним. Давайте рассмотрим пример, что прояснить данное утверждение. Предположите, что вам нужен text box, в котором можно вводить только шестнадцатиричные числа. Если вы будете использовать обычный edit control, максимум, что вы сможете сделать, если юзер введет неверную букву, это стереть исходную строку и вывести ее снова в отредактированном виде. По меньшей мере, это непрофессионально. Фактически вам требуется получить возможность проверять каждый символ, который юзер набирает в text box'е, как pаз в тот момент, когда он делает это. Теперь мы изучим как это сделать. Когда пользователь печатает что-то в text box'е, Windows посылает сообщение WM_CHAR процедуре edit control'а. Эта процедура окна находится внутри Windows, поэтому мы не можем модифицировать ее. Hо мы можем перенаправить поток сообщений к нашей оконной процедуре. Поэтому наша процедура окна первой получит возможность обработать сообщение, которое Windows пошлет edit control'у. Если наша процедура решит обработать сообщение, она так и сделает. Hо если она не захочет его обрабатывать, она может передать его оригинальной оконной процедуре. Таким образом, наша функция будет стоять между Windows и edit control'ом. Посмотрите на условную схему внизу. До сабклассинга Windows ==> процедура edit control'а После сабклассинга Windows ==> наша оконная процедура -----> процедура edit control'а Теперь мы можем рассмотреть то, каким образом происходит сабклассинг окна. Заметьте, что сабклассинг не ограничивается контролами, он может использоваться с любым окном. Давайте подумаем о том, как Windows узнаёт, где находится процедура edit box'а. Hу?.. Поле lрfnWndрroc в структуре WNDCLASSEX. Если мы сможем поменять значение этого поля на адрес собственной структуры, Windows пошлет сообщение нашей процедуре окна вместо этого. Мы можем сделать это, вызвав SetWindowLong. SetWindowLong PROTO hWndWORD, nIndexWORD, dwNewLongWORD hWnd = хэндл окна, чьи свойства мы хотим поменять. nIndex = значение, которое нужно изменить. GWL_EXSTYLE Установка нового расширенного стиля окна. GWL_STYLE Установка нового стиля окна. GWL_WNDPROC Установка нового адреса для процедры окна. GWL_HINSTANCE Установка нового хэндла приложения. GWL_ID Установка нового идентификатора окна. GWL_USERDATA Установка 32-битного значения, ассоциирующегося с окном. У каждого окна есть ассоциированное с ним 32-битное значение, предназначенное для использования приложением в своих целях. dwNewLong = новое значение. Таким образом, наша работа проста: мы создаем процедуру окна, которая будет обрабатывать сообщения для edit control'а и затем вызывать SetWindowLong с флагом GWL_WNDPROC, которому передается адрес нашего окна в качестве третьего параметра. В случае, если вызов функции прошел нормально, возвращаемым значением является прежнее значение замещаемого параметра, в нашем случае - это адрес оригинальной процедуры окна. Hам нужно сохранить это значение, чтобы использовать его внутри нашей процедуры. Помните, что есть сообщения, которые нам не нужно будет обрабатывать. Их мы будем передавать оригинальной процедуре. Мы можем сделать это с помощью вызова функции CallWindowproc. CallWindowproc pROTO lpprevWndFuncWORD, \ hWndWORD,\ MsgWORD,\ wparamWORD,\ lparamWORD lрrevWndFunc = адрес оригинальной процедуры окна. Остальные четыре значения - это те, что передаются нашей процедуре окна. Мы передаем их CallWindowproc. Пpимеp: .386 .model flat,stdcall option casemap:none include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc include \masm32\include\comctl32.inc includelib \masm32\lib\comctl32.lib includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib WinMain PROTO WORD,WORD,WORD,WORD EditWndproc PROTO WORD,WORD,WORD,WORD .data ClassName db "SubclassWinClass",0 AppName db "Subclassing Demo",0 EditClass db "EDIT",0 Message db "You pressed Enter in the text box!",0 data? hInstance HINSTANCE ? hwndEdit dd ? OldWndProc dd ? .code start: invoke GetModuleHandle, NULL mov hInstance,eax invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT invoke Exitprocess,eax WinMain proc hInst:HINSTANCE,hprevInst:HINSTANCE,CmdLine:LpSTR,CmdShowWORD LOCAL wc:WNDCLASSEX LOCAL msg:MSG LOCAL hwnd:HWND mov wc.cbSize,SIZEOF WNDCLASSEX mov wc.style, CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndproc, OFFSET Wndproc mov wc.cbClsExtra,NULL mov wc.cbWndExtra,NULL push hInst pop wc.hInstance mov wc.hbrBackground,COLOR_AppWORKSpACE mov wc.lpszMenuName,NULL mov wc.lpszClassName,OFFSET ClassName invoke LoadIcon,NULL,IDI_AppLICATION mov wc.hIcon,eax mov wc.hIconSm,eax invoke LoadCursor,NULL,IDC_ARROW mov wc.hCursor,eax invoke RegisterClassEx, addr wc invoke CreateWindowEx, WS_EX_CLIENTEDGE, ADDR ClassName, ADDR AppName, WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX\ +WS_MAXIMIZEBOX+WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,350,200, NULL,NULL, hInst,NULL mov hwnd,eax .while TRUE invoke GetMessage, ADDR msg,NULL,0,0 .BREAK .IF (!eax) invoke TranslateMessage, ADDR msg invoke DispatchMessage, ADDR msg .endw mov eax,msg.wparam ret WinMain endp Wndproc proc hWnd:HWND, uMsg:UINT, wparam:WpARAM, lparam:LpARAM .if uMsg==WM_CREATE invoke CreateWindowEx, WS_EX_CLIENTEDGE, ADDR EditClass, NULL, WS_CHILD+WS_VISIBLE+WS_BORDER, 20,20,300,25, hWnd,NULL, hInstance,NULL mov hwndEdit,eax invoke SetFocus,eax ; Subclass it! invoke SetWindowLong,hwndEdit,GWL_WNDPROC,addr EditWndProc mov OldWndProc,eax .elseif uMsg==WM_DESTROY invoke PostQuitMessage,NULL .else invoke DefWindowProc,hWnd,uMsg,wparam,lparam ret .endif xor eax,eax ret WndProc endp EditWndproc PROC hEditWORD,uMsgWORD,wparamWORD,lparamWORD .if uMsg==WM_CHAR mov eax,wparam .if (al>="0" && al<="9") || (al>="A" && al<="F") || (al>="a" && al<="f") || al==VK_BACK .if al>="a" && al<="f" sub al,20h .endif invoke CallWindowProc,OldWndProc,hEdit,uMsg,eax,lparam ret .endif .elseif uMsg==WM_KEYDOWN mov eax,wparam .if al==VK_RETURN invoke MessageBox,hEdit,addr Message,addr AppName,MB_OK+MB_ICONINFORMATION invoke SetFocus,hEdit .else invoke CallWindowproc,OldWndproc,hEdit,uMsg,wparam,lparam ret .endif .else invoke CallWindowproc,OldWndproc,hEdit,uMsg,wparam,lparam ret .endif xor eax,eax ret EditWndproc endp end start Анализ: invoke SetWindowLong,hwndEdit,GWL_WNDpROC,addr EditWndproc mov OldWndproc,qqeax После того, как edit control создан, мы сабклассим его, вызывая SetWindowLong и замещая адрес оригинальной процедуры окна нашим собственным адресом. Заметьте, что мы сохраняем значение адреса оригинальной процедуры, чтобы впоследствии использовать его при вызове CallWindowproc. Заметьте, что EditWndрroc - это обычная оконная процедура. .if uMsg==WM_CHAR mov eax,wparam .if (al>="0" && al<="9") || (al>="A" && al<="F") || (al>="a" && al<="f") || al==VK_BACK .if al>="a" && al<="f" sub al,20h .endif invoke CallWindowproc,OldWndproc,hEdit,uMsg,eax,lparam ret .endif Внутри EditWndрroc, мы фильтруем сообщения WM_CHAR. Если введен символ в диапазоне 0-9 или a-f, мы передаем его оригинальной процедуре окна. Если это символ нижнего регистра, мы конвертируем его в верхний, добавляя 20h. Заметьте, что если символ не тот, который мы ожидали, мы пропускаем его. Мы не передаем его оригинальной процедуре окна. Поэтому, когда пользователь печатает что-нибудь отличное от 0-9 или a-f, символ не появляется в edit control'е. .elseif uMsg==WM_KEYDOWN mov eax,wparam .if al==VK_RETURN invoke MessageBox,hEdit,addr Message,addr AppName,MB_OK+MB_ICONINFORMATION invoke SetFocus,hEdit .else invoke CallWindowproc,OldWndproc,hEdit,uMsg,wparam,lparam ret .end Я хочу продемонстрировать силу сабклассинга через перехват клавиши Enter. EditWndрroc проверяет сообщение WM_KEYDOWN, не равно ли оно VK_RETURN (клавиша Enter). Если это так, она отображает окно с сообщением "You pressed the Enter key in the text box!". Если это не клавиша Enter, она передает сообщение оригинальной процедуре. Вы можете использовать сабклассинг окна, чтобы получить контроль над другими окнами. Эту мощную технику вам следует иметь в своем арсенале. ----------------------- [C] Iczelion, пер. Aquila.