Кастомные подписи кнопок в месседжбоксе

Для неординарных вопросов. Если вы опытный программист, попавший в трудную ситуацию, — вам сюда.

Модератор: gaidar

Правила форума
Этот раздел не предназначен для того, чтобы вы адресовали свою проблему профессионалам.
Этот раздел предназначен для профессионалов, которые столкнулись с проблемой и не могут решить ее самостоятельно.
Если вы считаете себя профессионалом, а свою проблему сложной — вам сюда.
Если модератор посчитает, что вы ошиблись, то на первый раз он перенесет ваше сообщение в основной раздел без последствий для автора. Во второй раз тема будет закрыта, а автору будет выписано нарушение. В третий раз автор будет забанен.
tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Кастомные подписи кнопок в месседжбоксе

Сообщение tyomitch » 24.09.2006 (Вс) 17:38

Код: Выделить всё
Option Explicit

Private Type MSGBOXPARAMS
    cbSize As Long
    hwndOwner As Long
    hInstance As Long
    lpszText As Long
    lpszCaption As Long
    dwStyle As Long
    lpszIcon As Long
    dwContextHelpId As Long
    lpfnMsgBoxCallback As Long
    dwLanguageId As Long
End Type

Private Type MSGBOXDATA
    params As MSGBOXPARAMS
    pwndOwner As Long
    wLanguageId As Integer
    pidButton As Long '                 // Array of button IDs
    ppszButtonText As Long '            // Array of button text strings
    cButtons As Long
    DefButton As Long
    CancelId As Long
    Timeout As Long
End Type

Private Declare Function SoftModalMessageBox Lib "user32" (pMsgBoxParams As MSGBOXDATA) As Long

Sub Main()
Dim mbd As MSGBOXDATA, Buttons(3) As Long, Captions(3) As String
    Captions(0) = "Нафиг"
    Buttons(0) = vbAbort
    Captions(1) = "Нефиг"
    Buttons(1) = vbRetry
    Captions(2) = "Пофиг"
    Buttons(2) = vbIgnore
    Captions(3) = "Отмена"
    Buttons(3) = vbCancel
With mbd
    With .params
        .cbSize = LenB(mbd.params)
        .lpszText = StrPtr(Replace("Чтобы сделать месседжбокс с собственными подписями\nкнопок, совсем не обязательно рисовать форму самому:\nдля этого идеально подходит малодокументированная\nфункция SoftModalMessageBox.", "\n", vbCrLf))
        .lpszCaption = StrPtr("Круто, да?")
        .dwStyle = vbQuestion & vbOKCancel
    End With
    .DefButton = 2
    .CancelId = vbCancel
    .cButtons = 4
    .pidButton = VarPtr(Buttons(0))
    .ppszButtonText = VarPtr(Captions(0))
    .Timeout = -1
End With
Debug.Print SoftModalMessageBox(mbd)
End Sub
Изображение

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 24.09.2006 (Вс) 18:18

Эээээ... А почему
Инструкция по адресу "0x77e48e2c" обратилась к памяти по адресу "0xffffffff". Память не может быть "read"

после нажатия одной из кнопок месаджбокса? :roll: (Дебагер грит, что 0x77e48e2c - в USER32.DLL)
Изображение

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 24.09.2006 (Вс) 18:41

Аналогично.

---------------------------
Круто, да?: vb6.exe - Application Error
---------------------------
The instruction at "0x77e48e2c" referenced memory at "0xffffffff". The memory could not be "read".


Click on OK to terminate the program
Click on CANCEL to debug the program
---------------------------
OK Cancel
---------------------------


---------------------------
Microsoft Visual C++
---------------------------
Unhandled exception in VB6.EXE (USER32.DLL): 0xC0000005: Access Violation.
---------------------------
OK
---------------------------


Windows 2000 SP4 En
const char *out = "|*0>78-,+<|"; size_t cc = char_traits<char>::length(out);
for (size_t i=0;i<cc;i++){cout<<static_cast<char>((out[i]^89));}cout<<endl;

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 24.09.2006 (Вс) 18:48

Приношу свои извинения: в конец структуры MSGBOXDATA нужно добавить поле Unknown As Long
Изображение

Kovu
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 924
Зарегистрирован: 29.04.2005 (Пт) 17:38

Сообщение Kovu » 24.09.2006 (Вс) 18:50

Хы, а у меня и без поля нормально работало
Если всё делать своими ручками, они скоро отвалятся !

BV
Thinker
Thinker
Аватара пользователя
 
Сообщения: 3987
Зарегистрирован: 12.09.2004 (Вс) 0:55
Откуда: Молдавия, г. Кишинёв

Сообщение BV » 24.09.2006 (Вс) 18:51

tyomitch писал(а):в конец структуры MSGBOXDATA нужно добавить поле Unknown As Long


То же самое.
const char *out = "|*0>78-,+<|"; size_t cc = char_traits<char>::length(out);
for (size_t i=0;i<cc;i++){cout<<static_cast<char>((out[i]^89));}cout<<endl;

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 24.09.2006 (Вс) 19:26

Kovu писал(а):Хы, а у меня и без поля нормально работало

А скомпилированное пробовал? ;-)

BV писал(а):
tyomitch писал(а):в конец структуры MSGBOXDATA нужно добавить поле Unknown As Long


То же самое.

В Win2000 нужно убрать строку .Timeout = -1 (функция MessageBoxTimeout появилась только в WinXP)

Дополнительный бонус для обладателей WinXP: если установить .cButtons в 0 и Timeout в конечное значение, получится автоубирающееся окно "пассивного предупреждения". Круто, да?
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 24.09.2006 (Вс) 20:19

А вот ещё одна фишка (проверять нужно из-под IDE)

Замените ".dwStyle = vbQuestion & vbOKCancel" на
Код: Выделить всё
        .dwStyle = 129
        .lpszIcon = 1256
        .hInstance = App.hInstance
Изображение

Kovu
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 924
Зарегистрирован: 29.04.2005 (Пт) 17:38

Сообщение Kovu » 24.09.2006 (Вс) 21:13

tyomitch
А какой стиль надо поставить чтобы иконка грузилась не из ресурсов, а допустим через LoadPicture ?
Если всё делать своими ручками, они скоро отвалятся !

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 24.09.2006 (Вс) 21:24

Низя; можно только из ресурсов. (См. доку по MessageBoxIndirect, структура MSGBOXPARAMS объявлена там.)
Изображение

Lumen
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 841
Зарегистрирован: 03.12.2005 (Сб) 16:09
Откуда: Брянск

Сообщение Lumen » 24.09.2006 (Вс) 21:29

tyomitch
Супер!!! А я помню, когда делал подобный мессаджбокс, приходилось ставить хук на появление окна, а затем вручную перебирать все дочерние окна этого окна и выставлять им соотвествующий текст (если кнопка) или картинку (если Static).

Спасибо!!!
Подпись проходит рефакторинг

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 25.09.2006 (Пн) 17:41

Kovu
Ставишь перехват на LoadIcon(или LoadIconEx, посмотри в дебаггере), и возвращаещь Picture.handle. По идее должно заработать.
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 25.09.2006 (Пн) 17:48

Я бы просто по нулевому таймеру подменил иконку в статике. И никакие перехватчики не нужны, пять строк на весь код. Плюс совместимость с Win9x.
Изображение

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 25.09.2006 (Пн) 18:19

Так давай код :) А то мы, неграмотные, нагородим тут всякого...
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 25.09.2006 (Пн) 18:36

Код: Выделить всё
Option Explicit

Private Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long
Private Declare Function GetForegroundWindow Lib "user32" () As Long
Private Declare Function SendDlgItemMessage Lib "user32" Alias "SendDlgItemMessageA" (ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const STM_SETICON = &H170

Dim hTimer As Long, hIcon As StdPicture

Sub Main()
    Set hIcon = LoadPicture("c:\earth.ico", vbLPLarge, vbLPColor)
    hTimer = SetTimer(0, 0, 0, AddressOf TimerProc)
    MsgBox "Неужели правда так сложно сделать это самим?", vbInformation, "пять строчек кода"
End Sub

Sub TimerProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long)
    KillTimer 0, hTimer
    SendDlgItemMessage GetForegroundWindow, 20, STM_SETICON, hIcon, 0
End Sub
Изображение

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 25.09.2006 (Пн) 18:43

Мне проще было сделать перехват :lol:
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 25.09.2006 (Пн) 18:47

Когда в руках молоток, всё вокруг кажется гвоздями (с)
Изображение

Nicky
Постоялец
Постоялец
 
Сообщения: 519
Зарегистрирован: 12.08.2004 (Чт) 12:14

Сообщение Nicky » 26.09.2006 (Вт) 7:40

Код: Выделить всё
Expression      Value      Type
-------------------------------
vbOKCancel       1         Long
vbQuestion      32         Long
dwStyle                    Long

dwStyle = vbQuestion & vbOKCancel '( = 321)

:shock:

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 26.09.2006 (Вт) 8:51

Nicky писал(а):
Код: Выделить всё
Expression      Value      Type
-------------------------------
vbOKCancel       1         Long
vbQuestion      32         Long
dwStyle                    Long

dwStyle = vbQuestion & vbOKCancel '( = 321)

:shock:

Таки-да, бага. Но это поле всё равно функцией игнорируется ;-)
Изображение

Nicky
Постоялец
Постоялец
 
Сообщения: 519
Зарегистрирован: 12.08.2004 (Чт) 12:14

Сообщение Nicky » 26.09.2006 (Вт) 10:43

tyomitch писал(а):Таки-да, бага. Но это поле всё равно функцией игнорируется ;-)

Да? ;)
Тогда почему при .dwStyle = vbQuestion & vbOKOnly что ни нажмешь, печатает 1?

И еще: как сделать 1 кнопку?, 2? 0?
[EDIT]:1 кнопку нашел, 2 нашел (макс кнопок 5). При .cButtons = 0 зависла
[EDIT]: эээ, не зависла, а ожидала заданное время (бесконечность :) Однако работает...

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 26.09.2006 (Вт) 12:14

Nicky писал(а):
tyomitch писал(а):Таки-да, бага. Но это поле всё равно функцией игнорируется ;-)

Да? ;)
Тогда почему при .dwStyle = vbQuestion & vbOKOnly что ни нажмешь, печатает 1?

Это фича. Если младшие 4 бита стиля нулевые, возвращается всегда 1, иначе ID нажатой кнопки.
Последний раз редактировалось tyomitch 26.09.2006 (Вт) 16:32, всего редактировалось 1 раз.
Изображение

Nicky
Постоялец
Постоялец
 
Сообщения: 519
Зарегистрирован: 12.08.2004 (Чт) 12:14

Сообщение Nicky » 26.09.2006 (Вт) 15:43

Как показывать стандартные иконки (Question, Information, Critical, без иконки)?

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 26.09.2006 (Вт) 16:32

стандартно: 4--6 биты стиля
(таки да, он не совсем игнорируется)
Изображение

lister
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 389
Зарегистрирован: 15.01.2005 (Сб) 7:34
Откуда: Страна оления

Сообщение lister » 24.01.2007 (Ср) 10:40

Сорри, что влезаю в старую тему...

Тёмыч, а у тебя нет примерчика по изменению MessageBox ?

Вот хочу добавить в него чекбокс "Не показывать более данное сообщение"

P.S.
Можно, конечно, свое окно нарисовать... Но ведь мы простых путей не ищем :P

Nicky
Постоялец
Постоялец
 
Сообщения: 519
Зарегистрирован: 12.08.2004 (Чт) 12:14

Сообщение Nicky » 24.01.2007 (Ср) 11:16

Точно было на форуме

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 24.01.2007 (Ср) 18:27

Изображение

lister
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 389
Зарегистрирован: 15.01.2005 (Сб) 7:34
Откуда: Страна оления

Сообщение lister » 24.01.2007 (Ср) 20:08

АФИГЕТЬ!!!
Я в восторге!!!


Вернуться в Раздел для Профессионалов

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 15

    TopList