Сабклассинг кнопки

Тема в разделе "WASM.BEGINNERS", создана пользователем fdr, 13 авг 2005.

  1. fdr

    fdr New Member

    Публикаций:
    0
    Регистрация:
    2 авг 2005
    Сообщения:
    8
    После осуществления сабжа, кнопка перестала нажиматься. В новой функции обработки событий кнопки я пока ничего не делаю, а сразу вызываю старый обработчик следующим образом:

    push lParam

    push wParam

    push uMsg

    push hButton

    push OldButtonProc

    call CallWindowProcA



    Возможно, я должен самостоятельно обрабатывать какие-то сообщения, а не сразу вызывать стандартный обработчик? Подскажите, что я делаю не правильно.
     
  2. fdr

    fdr New Member

    Публикаций:
    0
    Регистрация:
    2 авг 2005
    Сообщения:
    8
    Ошибка была в том, что я обнулял содержимое регистра eax перед выходом из своего обработчика, чего делать не следовало (видимо значение, возвращаемое функцией CallWindowProc где-то используется).
     
  3. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Возврат нуля означает, что все операции по нажатию кнопки (в т.ч. и перерисовка нажатого и отжатого положения) выполнены и больше ничего делать не надо.

    Поэтому, увидев ноль в еах, виндовс решила, что все уже сделано, суетиться не надо :) И пропустила стадию перерисовки кнопки.

    Возврат любого ненулевого значения заставит её перерисовать нажатое и отжатое состояние (т.е. "выполнить нажатие"). Это значение не обязательно должно быть от CallWindowProc. Можно например сделать or eax,-1 перед возвратом.
     
  4. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Я тут на днях решил поюзать MFC.

    Сделал карту сообщения OnLButtonClick для кнопки. Так там произошла такая же штука. Похоже что в Microsoft тоже это сделали сабкласингом.
     
  5. fdr

    fdr New Member

    Публикаций:
    0
    Регистрация:
    2 авг 2005
    Сообщения:
    8
    cresta

    Если возвращаю -1 или любое другое значение отличное от CallWindowProc(которая возвращает 0xF), то кнопка по прежнему не перерисовывается. Или в разных версиях винды по разному?
     
  6. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Чтобы перерисовывалась, нужно либо вызывать CallWindowProc в теле твоего обработчика, либо там же самому руками нарисовать нажатое и отжатое состояние. И после этого можно возвращать -1. Например так (правда не кнопка, а edit, но принцип тот же)
    Код (Text):
    1.     if(uMsg == WM_CHAR ) {
    2.         CallWindowProc(lpWProcEditName, hwnd, uMsg, wParam, lParam);
    3.         find_match(hwnd);   //тут можно делать ещё что-нибудь
    4.         return 123456789;   //тут можно вернуть что угодно
    5.                             //в т.ч. и 0 и -1, т.к. дефолтные
    6.                             //действия уже сделаны по CallWindowProc
    7.         }
     
  7. fdr

    fdr New Member

    Публикаций:
    0
    Регистрация:
    2 авг 2005
    Сообщения:
    8
    Хм.. в том то и дело, что я вызываю CallWindowProc именно в теле своего обработчика:


    Код (Text):
    1.  
    2. button_wndproc proc
    3.     push ebp
    4.     mov ebp,esp
    5.  
    6. hButton equ dword ptr [ebp+08h]
    7. uMsg equ dword ptr [ebp+0Ch]
    8. wParam equ dword ptr [ebp+10h]
    9. lParam equ dword ptr [ebp+14h]
    10.  
    11.     mov eax,uMsg
    12.     cmp uMsg,WM_MOUSEMOVE
    13.     jne @default
    14.  
    15.       ; мой обработчик WM_MOUSEMOVE
    16. @default:
    17.  
    18.     push lParam
    19.     push wParam
    20.     push uMsg
    21.     push hButton
    22.     push OldButtonProc
    23.     call CallWindowProcA
    24.  
    25.     leave
    26.       or eax,-1 ; из-за этого кнопка не перерисовывается
    27.     ret 16
    28.  
    29. button_wndproc endp
    30.  




    Не работает. Кстати, команда return в C возвращает значение обязательно через eax?
     
  8. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    А с чего это вдруг по WM_MOUSEMOVE должна перерисовываться кнопка? Кто так решил?

    По умолчанию кнопка перерисовывается по WM_LBUTTONDOWN и WM_LBUTTONUP.

    Или может ты прицепил манифест, и хочешь отловить прорисовку рамки по моменту, когда мышь зашла на кнопку?





    Да.
     
  9. fdr

    fdr New Member

    Публикаций:
    0
    Регистрация:
    2 авг 2005
    Сообщения:
    8
    А с чего это вдруг по WM_MOUSEMOVE должна перерисовываться кнопка?

    Не должна, но я ведь после своего обработчика сразу вызываю стандартный. Который почему-то перестает обрабатывать WM_LBUTTONDOWN и WM_LBUTTONUP и кнопка не отрисовывается, если в eaх лежит не то, что нужно.
     
  10. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Вот посмотри в аттаче пример, после WM_MOUSEMOVE и возвращения из него 123456 в eax (как впрочем и -1 и любого другого значения), остальные сообщения нормально обрабатываются, и перерисовываются как нажатое, так и отжатое состояние кнопки.

    Чем этот пример отличается от твоего - смотри сам.

    Работает как с манифестом, так и без него.



    Обрати внимание: ни по одному из обрабатываемых сообщений не возвращается то, что получено от CallWindowProc. Тем не менее на все сообщения реагирует как положено.





    [​IMG] _2027899617__mouse_move.zip
     
  11. fdr

    fdr New Member

    Публикаций:
    0
    Регистрация:
    2 авг 2005
    Сообщения:
    8
    Причина похоже в том, что значение в eax важно не для всех сообщений. Действительно, в твоем исходнике все сообщения WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSELEAVE обрабатываются корректно с произвольным значением eax. Но если добавить or eax,-1 для остальных сообщений, которые ты не обрабатываешь (после последнего вызова CallWindowProc в твоем обработчике), то получается мой случай :)
     
  12. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257




    Естественно :) Оно важно для тех, которые не были упомянуты или обработаны в твоем обработчике.



    Если ты не обрабатываешь какие-то сообщения, то кто-то же должен их обработать :)

    Возврат нуля сигнализирует, что ты сам не обрабатывал, и CallWindowProc для их обработки тоже не вызывал. Поэтому ноль нужен.

    Если же ты сам рисовал вручную или вызвал для этого CallWindowProc, то необходимый минимум действий по сообщениям уже сделан, и возвращать можно что угодно.
     
  13. fdr

    fdr New Member

    Публикаций:
    0
    Регистрация:
    2 авг 2005
    Сообщения:
    8
    Оно важно для тех, которые не были упомянуты или обработаны в твоем обработчике.

    Вот этого я и не могу понять :)

    Почему если некоторое сообщение обрабатывается в моем обработчике явно, например так:
    Код (Text):
    1.  
    2. mov     eax,uMsg
    3. .if     (eax==WM_PAINT)
    4. invoke  CallWindowProc,OldButtonProc,hWin,uMsg,wParam,lParam
    5.         or      eax,-1
    6.         ret  
    7.  


    Такой код работает, независимо, что находится в eax.



    В случае, если тот же WM_PAINT обрабатывается таким образом (неявно):
    Код (Text):
    1.  
    2. .else
    3. invoke  CallWindowProc,OldButtonProc,hWin,uMsg,wParam,lParam ; uMSG==WM_PAINT
    4.         or      eax,-1
    5.         ret  
    6.  


    То из-за этого никакие сообщения не обрабатываются и кнопка не перерисовывается.

    Фактически, в обоих случаях происходит вызов функции CallWindowProc с параметром uMsg==WM_PAINT. В чем разница между этими двумя вызовами?





    Если же ты сам рисовал вручную или вызвал для этого CallWindowProc, то необходимый минимум действий по сообщениям уже сделан, и возвращать можно что угодно.



    В примере выше, я вызываю CallWindowProc для сообщения WM_PAINT, изменяю eax и кнопка не отрисовывается. Хотя по идее минимум действий сделан т.к. я вызвал CallWindowProc, которая должна отослать это сообщине стандартному обработчику.

    Ничего не понимаю (с) Колобки
     
  14. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Код (Text):
    1. ;     .elseif (eax==WM_PAINT)
    2. ;        invoke  CallWindowProc,prev_butt_proc,hWin,uMsg,wParam,lParam
    3. ;        ;invoke  SetWindowText,hButton,SADD("BUTTON")  
    4. ;        mov     eax,123456
    5. ;        ret    
    6.      
    7.     .else        ;все остальные сообщения (в т.ч. WM_PAINT)
    8.         invoke CallWindowProc,prev_butt_proc,hWin,uMsg,wParam,lParam  
    9.         .if (uMsg==WM_PAINT)
    10.             mov     eax,-11112222
    11.         .endif
    12.         ret
    13.     .endif




    Вот так рисует :)



    А так как ты последний раз показывал, на все подряд сообщения возвращается -1. Но не на все подряд сообщения можно возвращать произвольный результат в eax.

    Есть сообщения, для которых возвращаемое значение из WndProc должно быть определенным (и которое влияет на рисование кнопки). Какое из сообщений - можешь поэкспериментировать и поискать путём подбора строки .if (uMsg==WM_PAINT). Но это не WM_PAINT.
     
  15. fdr

    fdr New Member

    Публикаций:
    0
    Регистрация:
    2 авг 2005
    Сообщения:
    8
    Теперь все стало понятно. Спасибо )