Blog. Just Blog

Создание пользовательского MessageBox с помощью SoftModalMessageBox

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Ранее я уже рассказывал, каким образом можно кастомизировать стандартный MessageBox при помощи хуков, в частности, менять надписи на кнопках. Сегодня разберем создание MessageBox с помощью недокументированной функции SoftModalMessageBox. В качестве единственного параметра она принимает указатель на структуру MSGBOXDATA, которая тоже относится к недокументированным:
  1. struct MSGBOXDATA
  2.         params         MSGBOXPARAMS
  3.         pwndOwner      dd ?  ; Хэндл окна-владельца
  4.         wLanguageId    dd ?  ; Идентификатор языка
  5.         pidButton      dd ?  ; Массив с идентификаторами кнопок
  6.         ppszButtonText dd ?  ; Массив с указателями на строки текста
  7.         cButtons       dd ?  ; Количество кнопок в окне
  8.         DefButton      dd ?  ; Кнопка по умолчанию
  9.         CancelId       dd ?  ; Идентификатор кнопки отмены
  10.         Timeout        dd ?  ; Таймаут окна
  11.         Unknown        rd 5  ; Зарезервировано
  12. ends
Давайте подробно разберем ее поля, так как никаких нормальных описаний в рунете я не нашел, пришлось собирать информацию по крупицам. Первый параметр - документированная структура MSGBOXPARAMS, в ней можно настроить, например, пользовательскую иконку, которая будет отображаться в MessageBox. Подробное описание структуры есть в MSDN, дублировать его не буду. Поля pwndOwner и wLanguageId сложности не представляют, это хэндл окна-владельца и идентификатор языка, на котором будет выведен текст в окне сообщения. Поле pidButton - указатель на массив DWORD'ов, которые являются идентификаторами кнопок в создаваемом окне. Важное замечание. Идентификаторы кнопок должны быть строго одним из стандартных значений, возвращаемых обычной функцией MessageBox. Любое другое значение будет проигнорировано, а соответствующая кнопка при нажатии не будет ничего делать. В поле ppszButtonText записывается указатель на массив указателей на юникодные строки, которые будут использоваться в качестве надписей на кнопках. Размер кнопок под длину надписей не подгоняется, берется максимальный системный размер кнопки для текущей локали, так что без фанатизма. cButtons - количество кнопок в окне. Этому количеству должно соответствовать количество элементов в массиве идентификаторов и в массиве указателей на названия. DefButton - кнопка по умолчанию, нумерация кнопок начинается с 0. В поле CancelId по задумке должен быть идентификатор, отвечающий за кнопку отмены, но по факту это поле игнорируется. Нулевое значение деактивирует крестик закрытия в заголовке окна сообщения. Timeout задает интервал, после которого окно автоматически закроется, об этом я рассказывал в одной из предыдущих статей.

Еще одно важное замечание. Для того, чтобы функция SoftModalMessageBox возвращала идентификатор нажатой кнопки, хотя бы один из четырех младших бит в поле dwStyle структуры params (MSGBOXPARAMS) должен быть взведен. То есть стиль должен включать любой из флагов MB_OKCANCEL, MB_RETRYCANCEL, MB_YESNO или MB_YESNOCANCEL. Они игнорируются при отрисовке окна, но должны присутствовать при описании, иначе в качестве результата SoftModalMessageBox будет всегда возвращаться 1.

Теперь, когда мы знаем все поля структуры, можно переходить к программированию. Вот простейший пример использования SoftModalMessageBox:
  1. ; Массив идентификаторов кнопок
  2. butIDs  dd IDOK,IDYES,IDNO,IDCANCEL
  3. ; Массив указателей на названия кнопок
  4. butTxt  dd str1,str2,str3,str4
  5.  
  6. str1    du 'Natalie',0
  7. str2    du 'Dylan',0
  8. str3    du 'Alex',0
  9. str4    du 'NONE',0
  1.         ; Размер структуры MSGBOXPARAMS, обязательное поле
  2.         mov     [mbdata.params.cbSize],sizeof.MSGBOXPARAMS
  3.         ; Хэндл окна-владельца
  4.         mov     [mbdata.params.hwndOwner],HWND_DESKTOP
  5.         ; Хэндл приложения, из ресурсов которого будет браться иконка
  6.         invoke  GetModuleHandle,0
  7.         mov     [mbdata.params.hInstance],eax
  8.         ; Текст сообщения
  9.         mov     [mbdata.params.lpszText],szMess
  10.         ; Текст заголовка
  11.         mov     [mbdata.params.lpszCaption],szTitle
  12.         ; Пользовательская иконка + возврат идентификатора
  13.         mov     [mbdata.params.dwStyle],MB_USERICON or MB_OKCANCEL
  14.         ; Идентификатор иконки из ресурсов
  15.         mov     [mbdata.params.lpszIcon],1
  16.  
  17.         ; Хэндл окна-владельца
  18.         mov     [mbdata.pwndOwner],HWND_DESKTOP
  19.         ; Язык текста
  20.         mov     [mbdata.wLanguageId],LANG_NEUTRAL
  21.         ; Указатель на массив идентификаторов кнопок
  22.         mov     [mbdata.pidButton],butIDs
  23.         ; Указатель на массив указателей на названия кнопок
  24.         mov     [mbdata.ppszButtonText],butTxt
  25.         ; Количество кнопок
  26.         mov     [mbdata.cButtons],4
  27.         ; Вторая по счету кнопка используется по умолчанию
  28.         mov     [mbdata.DefButton],1
  29.         ; Крестик закрытия окна активен
  30.         mov     [mbdata.CancelId],1
  31.         ; Бесконечное отображение
  32.         mov     [mbdata.Timeout],-1
  33.  
  34.         invoke  SoftModalMessageBox,mbdata
Таким образом сразу решается несколько задач: добавление пользовательской иконки в окно сообщения, можно менять порядок кнопок по вашему усмотрению, надписи на кнопках можно кастомизировать без использования хуков и, наконец, со всей этой красотой можно использовать таймер автозакрытия.

В приложении пример программы с исходным текстом, которая использует функцию SoftModalMessageBox для создания окна сообщения.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

SoftModalMessageBox.Demo.zip (5,935 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 1009 | Комментариев: 12

Метки: Assembler
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
Mikl___ (21.03.2022 в 13:42):
Спасибо за подсказку! Жаль, что в комментарии нельзя картинки в тэгах [img] и [/img] вставлять
ManHunter (21.03.2022 в 13:30):
Можно и без dll: https://www.manhunter.ru/assem...sagebox.html
Хук WH_CBT на текущий тред. Тоже постоянно пользуюсь в своих программах, делаю перетаскиваемое окно "About".
Mikl___ (21.03.2022 в 13:03):
ManHunter а это SoftModalMessageBox, который при помощи хуков превратился в окно диалога https://wasm.in/threads/skazki...#post-383977 :) на странице исходники, капелька пояснений и экзешник
https://wasm.in/attachments/01-png.5617/
ManHunter (21.03.2022 в 12:21):
Mikl___, ну вот, все написано до нас :) Но там x64 и без описания. Я где-то в камментах тоже собирал варианты вывода MessageBox, сейчас не вспомню.

А от себя в копилку к Дядюшке могу добавить SHMessageBoxCheck:
https://www.manhunter.ru/assem...kazivat.html
Mikl___ (21.03.2022 в 12:16):
Здравствуйте, ManHunter!
wasm.in --> WASM.ARTICLES --> Сказки дядюшки Римуса о x64 --> Глава шестая. Братец Кролик выводит MessageBox всеми возможными способами
https://wasm.in/threads/skazki...#post-408016
ManHunter (16.03.2022 в 14:04):
Теги и так есть, но там, где я считаю нужным.
qqq (16.03.2022 в 12:37):
афтар по брацки, расставь в статьях тематические метки аля winapi, шифрование, архивы и т.д.
ManHunter (14.03.2022 в 15:56):
Я в своих программах пользуюсь MessageBoxIndirect
DRON (14.03.2022 в 09:30):
Нет, всё не так: основная проблема в том, что на 64-битных виндах pwndOwner имеет размер 8, а не 4 байта, потому что объявлен он как
PWND     hwndOwner; // Converted hwndOwner

Вообще с этой функцией одна морока: она чисто внутренняя и MS меняет её как хочет от версии к версии, что там в Win11 я боюсь представить.
Проще использовать документированный TaskDialogIndirect.
ManHunter (14.03.2022 в 07:57):
Дополнил, спасибо!
DRON (14.03.2022 в 06:36):
>Размер кнопок под длину надписей не подгоняется, так что без фанатизма.
Он кстати подгоняется, но только под самую большую стандартную надпись. Так что у разных языков будут разные длины кнопок.

Исходник функции: https://pastebin.com/LyY3SCSr
DRON (14.03.2022 в 05:38):
На 64-битной семёрке вылетает, потому что там структура больше:
struct MSGBOXDATA
        params         MSGBOXPARAMS
        pwndOwner      dd ?  ; Хэндл окна-владельца
        dwPadding      dd ?
        wLanguageId    dd ?  ; Идентификатор языка
        pidButton      dd ?  ; Массив с идентификаторами кнопок
        ppszButtonText dd ?  ; Массив с указателями на строки текста
        cButtons       dd ?  ; Количество кнопок в окне
        DefButton      dd ?  ; Кнопка по умолчанию
        CancelId       dd ?  ; Идентификатор кнопки отмены
        Timeout        dd ?  ; Таймаут окна
        Unknown        dd 5 dup ?  ; Зарезервировано
ends

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.11 сек. / MySQL: 2 (0.0088 сек.) / Память: 4.5 Mb
Наверх