Создание и обработка улучшенного MessageBox

В одной из прошлых статей мы уже научились обрабатывать и облагораживать окно выбора каталога, а теперь сделаем что-нибудь необычное и противоестественное с окном сообщения MessageBox. Первое, что приходит на ум - это описать аналог MessageBox в ресурсах или создавать его динамически по мере надобности, но это получается как-то слишком просто. Попробуем перехватить стандартное окно MessageBox в момент создания. Для этого поставим хук на текущий тред нашего процесса, хук должен иметь тип WH_CBT:
        ...
        ; Получить хэндл текущего потока
        invoke  GetCurrentThreadId
        ; Установить перехватчик событий
        invoke  SetWindowsHookEx,WH_CBT,MBHookProc,NULL,eax
        ; Сохранить хэндл хука
        mov     [hMBHook],eax
        ...

Теперь мы можем отследить и обработать момент, когда система захочет активировать любое окно, принадлежащее треду. Значит если сразу после установки этого хука вызвать функцию MessageBox, то перехватчик также получит управление и мы сможем получить хэндл окна создаваемого MessageBox. В сегменте данных определим нужные переменные, структуры и строки. Их назначение будет раскрыто дальше.
section '.date' data readable writeable
 
; Заголовок и текст окна
szTitle         db 'Hello!',0
szMess          db 'This is a Customized MessageBox with long text!',13,10
                db 'FASM is the BEST Assembler!',0
 
; Новый текст на кнопках
szButt1         db 'Of Course ;)',0
szButt2         db 'No-no-no!!!',0
 
; Название класса окна
cname           db 'EDIT',0
 
hMBHook         dd ?    ; Хэндл хука
pOldProc        dd ?    ; Адрес старого обработчика окна
hInstance       dd ?    ; Хэндл модуля
hHeap           dd ?    ; Хэндл кучи
hMemory         dd ?    ; Указатель на память
coord           RECT    ; Размеры текста

Зная хэндл, с окном можно сделать практически все что угодно. Здесь есть важный момент: после обработки окна надо обязательно сразу же снять хук, чтобы не было никаких накладок.

Функция перехватчика будет иметь следующий вид:
;-----------------------------------------------------------------------
; Функция обработки перехватчика
;-----------------------------------------------------------------------
proc MBHookProc nCode:DWORD,wParam:DWORD,lParam:DWORD
        ; Сохранить все регистры
        pusha
 
        cmp     [nCode],0
        jb      @f
        cmp     [nCode],HCBT_ACTIVATE
        jne     @f
 
        ; Установить иконку окна
        invoke  GetModuleHandle,0
        invoke  LoadIcon,eax,1
        invoke  SendMessage,[wParam],WM_SETICON,ICON_BIG,eax
 
        ; Поменять текст на кнопке Yes
        invoke  GetDlgItem,[wParam],IDYES
        invoke  SetWindowText,eax,szButt1
        ; Поменять текст на кнопке No
        invoke  GetDlgItem,[wParam],IDNO
        invoke  SetWindowText,eax,szButt2
 
        ; Изменить стиль окна
        invoke  GetWindowLong,[wParam],GWL_EXSTYLE
        add     eax,WS_EX_LAYERED
        invoke  SetWindowLong,[wParam],GWL_EXSTYLE,eax
        ; Установить атрибут прозрачности
        invoke  SetLayeredWindowAttributes,[wParam],0,200,LWA_ALPHA
 
        ; Получить хэндл текстового поля
        invoke  GetDlgItem,[wParam],0FFFFh
        ; Сохранить хэндл текстового поля
        mov     ebx,eax
 
        ; Получить длину текста в окне
        invoke  GetWindowTextLength,ebx
        or      eax,eax
        jz      no_text
 
        ; Получить координаты текстового блока
        invoke  GetClientRect,ebx,coord
        ; Пересчитать координаты на дочернее окно
        invoke  MapWindowPoints,ebx,[wParam],coord,2
        mov     eax,[coord.left]
        sub     [coord.right],eax
        add     [coord.right],5
        sub     [coord.left],7
        mov     eax,[coord.top]
        sub     [coord.bottom],eax
        add     [coord.top],2
 
        ; Получить кучу текущего процесса
        invoke  GetProcessHeap
        mov     [hHeap],eax
 
        mov     esi,eax
        ; Выделить память для текста
        invoke  HeapAlloc,[hHeap],HEAP_ZERO_MEMORY,eax
        mov     [hMemory],eax
 
        ; Прочитать текст в буфер
        invoke  GetWindowText,ebx,[hMemory],esi
 
        ; Спрятать основной текст
        invoke  ShowWindow,ebx,SW_HIDE
        ; Получить шрифт текста в окне
        invoke  SendMessage,ebx,WM_GETFONT,NULL,NULL
        mov     esi,eax
 
        ; Создать поле EDIT вместо STATIC
        invoke  CreateWindowEx,WS_EX_WINDOWEDGE,cname,[hMemory],\
                WS_CHILD+WS_VISIBLE+ES_MULTILINE+ES_READONLY,[coord.left],\
                [coord.top],[coord.right],[coord.bottom],[wParam],0FFFFh,\
                [hInstance],NULL
        ; Установить шрифт как было у исходного текста
        invoke  SendMessage,eax,WM_SETFONT,esi,NULL
 
        ; Очистить память в куче
        invoke  HeapFree,[hHeap],NULL,[hMemory]
 
no_text:
        ; Субклассировать обработчик окна
        invoke  SetWindowLong,[wParam],GWL_WNDPROC,NewWindowProc
        ; Сохранить адрес предыдущего обработчика
        mov     [pOldProc],eax
 
        ; Снять перехватчик
        invoke  UnhookWindowsHookEx,[hMBHook]
 
        ; Восстановить регистры
        popa
 
        xor     eax,eax
        ret     
@@:
        ; Восстановить регистры
        popa
 
        ; Передать управление следующему обработчику
        invoke  CallNextHookEx,[hMBHook],[nCode],[wParam],[lParam]
        ret
endp

Субклассированный обработчик окна для перетаскивания его за любое место почти такой же, как и в предыдущей статье. Разница только в том, что адрес предыдущего обработчика должен храниться в отдельной переменной. Это связано с особенностями заполнения структур окна MessageBox. После выполнения получается полупрозрачный MessageBox с иконкой в заголовке, измененным текстом на стандартных кнопках "Да" и "Нет", текст сообщения помещен в EDIT и его можно выделить мышкой и скопировать, а само окно можно перемещать за любое место. Естественно, что в прикладных программах одновременно столько наворотов не потребуется, это сделано только для демонстрации.

В приложении пример программы с исходным текстом, реализующей описанный в статье метод перехвата и обработки MessageBox.
Теги:
MessageBox
Добавлено: 10 Апреля 2018 20:09:49 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...