Сообщения от дочерних окон

Тема в разделе "WASM.WIN32", создана пользователем Quark, 7 дек 2008.

  1. Quark

    Quark New Member

    Публикаций:
    0
    Регистрация:
    7 авг 2007
    Сообщения:
    211
    У меня есть 3 окошка.

    Диалоговое окно (hwnd_1) имеет одно дочернее (hwnd_2). Дочернее имеет окошко edit (hwnd_edit). мне нужно чтобы при нажатии в эдите кнопки Enter окно hwnd_2 ловило мессагу WM_COMMAND с wparam == IDC_EDIT. Но эта мессага идёт окошку hwnd_1. Что нужно сделать чтобы мессага шла именно второму окну? Второе окно я создаю след образом:
    Код (Text):
    1.     m_hwnd_2 =  CreateWindowEx(WS_EX_CONTROLPARENT, L"#pklasmfsdf", 0,
    2. WS_CHILD|WS_VISIBLE|WS_SIZEBOX,
    3. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    4. hwnd_prnt, (HMENU)IDC_EDIT, 0, 0);
     
  2. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Quark
    Кто родитель edit'а? Покажи экстрастили и стили edit'а.
    Как ты добился, чтобы "при нажатии в эдите кнопки Enter окно hwnd_1 ловило мессагу WM_COMMAND с wparam == IDC_EDIT"? Я знаю, что edit посылает своему родителю уведомление EN_CHANGE.
     
  3. driver

    driver New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2008
    Сообщения:
    302
    эдит нужно сабклассировать, иначе он - получает сообщение, но оно находится внутри ОС
    и обрабатывать наверное надо WM_CHAR
     
  4. Quark

    Quark New Member

    Публикаций:
    0
    Регистрация:
    7 авг 2007
    Сообщения:
    211
    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.
     
  5. driver

    driver New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2008
    Сообщения:
    302
    Урок 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 hWnd:lol: WORD, nIndex:lol: WORD, dwNewLong:lol: WORD

    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 lpprevWndFunc:lol: WORD, \
    hWnd:lol: WORD,\
    Msg:lol: WORD,\
    wparam:lol: WORD,\
    lparam:lol: WORD

    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 :lol: WORD,:lol: WORD,:lol: WORD,:lol: WORD
    EditWndproc PROTO :lol: WORD,:lol: WORD,:lol: WORD,:lol: 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,CmdShow:lol: WORD
    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 hEdit:lol: WORD,uMsg:lol: WORD,wparam:lol: WORD,lparam:lol: WORD

    .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.
     
  6. Quark

    Quark New Member

    Публикаций:
    0
    Регистрация:
    7 авг 2007
    Сообщения:
    211
    Ну переопределить WindowProc, конечно, можно, но помойму несколько кривовато.