Is it possible to give the msgbox function custom buttons in stead of the standard buttons like Ok, Cancel etc. or do I have to create my own with a form and buttons?
I want to give the user the option to select eg. This, That or Cancel.
You can do a custom form as DSJ told you or you can use subclassing
The hook will need to know a few things, first of all,
where is the hook coming from? We can get that by making a call to GetWindowLong API function, specifying
that we need the instance of our window.
Another thing it needs to know is the thread that's calling it. For this we use the GetCurrentThreadID API.
Finally we need to specify where it should send the messages to, and that would be a function we wrote.
We now have everything to make the call. When calling, we specify that we are setting up a CBT hook, and
off we go.
Once we have the hWnd, we can search for buttons. Since a button is actually a window of the class
button, we can use the FindWindowEx API to find them. Once we have it, we can change the text using the
SetWindowText API.
After we done the processing, we need to release the hook. If we don't release the hook, our program can
just disappear. Resulting is a possible loss of data, and a memory leak. Also, when debugging, NEVER place
a break between the place where you place your hook and release it, because this will probably result in
the same effect as above.
This can also be applied to the InputBox. The example code shows both. The MSGBOX function will still
return the selected value, so if you change the Yes button to "Yeah", it will still return vbYes (and not
vbYeah
The INPUTBOX function returns the text entered, so basically nothing changes on the use, you just add a bit
of a preparation.
Since we are able to get the hWnd of the box and the
buttons, we could easely use most of the WIndow APIs on it.
Code:
'module
' used for placing the hook
Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Public Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Public Const GWL_HINSTANCE = (-6)
Public Const SWP_NOSIZE = &H1
Public Const SWP_NOZORDER = &H4
Public Const SWP_NOACTIVATE = &H10
Public Const HCBT_ACTIVATE = 5
Public Const WH_CBT = 5
Public hHook As Long
' used for locating and changing the buttons
Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hwndParent As Long, ByVal hwndChildAfter As Long, ByVal lpszClass As String, ByVal lpszWindow As String) As Long
Public Declare Function SetWindowText Lib "user32.dll" Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String) As Long
Public Declare Function GetClassName Lib "user32.dll" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Public ButtonText(0 To 3) As String
' function called by hook
Public Function Manipulate(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim Btn(0 To 3) As Long
Dim ButtonCount As Integer
Dim T As Integer
If lMsg = HCBT_ACTIVATE Then
Btn(0) = FindWindowEx(wParam, 0, vbNullString, vbNullString)
Dim cName As String, Length As Long
For T = 1 To 3
Btn(T) = FindWindowEx(wParam, Btn(T - 1), vbNullString, vbNullString)
' no more windows found
If Btn(T) = 0 Then Exit For
Next T
For T = 0 To 3
If Btn(T) <> 0 And Btn(T) <> wParam Then
cName = Space(255)
Length = GetClassName(Btn(T), cName, 255)
cName = Left(cName, Length)
Debug.Print cName
If UCase(cName) = "BUTTON" Then
' a button
SetWindowText Btn(T), ButtonText(ButtonCount)
ButtonCount = ButtonCount + 1
End If
End If
Next T
'Release the CBT hook
UnhookWindowsHookEx hHook
End If
Manip = False
End Function
'form
'add list with list values
'0 - vbOkOnly
'1 - vbOkCancel
'2 - vbAbortRetryIgnore
'3 - vbYesNoCancel
'4 - vbYesNo
'5 - vbRetryCancel
'add 2 options optMsgBox and optInputBox
Private Sub cmdShow_Click()
Dim hInst As Long
Dim Thread As Long
Dim Buttons As Integer
' if none selected, we just keep 0 (vbOkOnly)
If lstButtons.Text <> "" Then Buttons = Left(lstButtons.Text, 1)
' fill array with button text
ButtonText(0) = "Iouri 0"
ButtonText(1) = "Iouri 1"
ButtonText(2) = "Iouri 2"
ButtonText(3) = "Iouri 3"
'Set up the CBT hook
hInst = GetWindowLong(Me.hwnd, GWL_HINSTANCE)
Thread = GetCurrentThreadId()
hHook = SetWindowsHookEx(WH_CBT, AddressOf Manipulate, hInst, Thread)
'Display the box
Dim Retval As Variant
'optMsgBox - is option to show either MsgBox or InputBox
If optMsgBox.Value Then
Retval = MsgBox("Message Text", Buttons, "Title for Msgbox")
Select Case Retval
Case vbYes
Retval = Retval & " - Yes"
Case vbNo
Retval = Retval & " - No"
Case vbCancel
Retval = Retval & " - Cancel"
Case vbIgnore
Retval = Retval & " - Ignore"
Case vbAbort
Retval = Retval & " - Abort"
Case vbRetry
Retval = Retval & " - Retry"
Case vbOK
Retval = Retval & " - Ok"
End Select
Else
Retval = InputBox("My Prompt", "My Title")
End If
End Sub
Last edited by Cimperiali; June 16th, 2004 at 02:38 AM.
Iouri told it the correct (and a little more complex) way. But if you need a custom msgbox in a standar exe, you can do it easily declaring a Public Function msgBox in a module in your vb project, executing which you can show your own modal form. You can insert all parameters you want (usually it is a good idea to mirror the original function) and evem add your optional own to add the behaviour you need...
As the public function in a standard module is less general than the function in Vba module, it will shadow that function (as long as you are inside your project) and be called instead of the Vba.msgBox function without needing to hook...
Have a nice day,
Cesare
...at present time, using mainly Net 4.0, Vs 2010
Special thanks to Lothar "the Great" Haensler, Chris Eastwood , dr_Michael, ClearCode, Iouri and
all the other wonderful people who made and make Codeguru a great place.
Come back soon, you Gurus.
Originally posted by Cimperiali
Iouri told it the correct (and a little more complex) way. But if you need a custom msgbox in a standar exe, you can do it easily declaring a Public Function msgBox in a module in your vb project, executing which you can show your own modal form. You can insert all parameters you want (usually it is a good idea to mirror the original function) and evem add your optional own to add the behaviour you need...
As the public function in a standard module is less general than the function in Vba module, it will shadow that function (as long as you are inside your project) and be called instead of the Vba.msgBox function without needing to hook...
Have a nice day,
Cesare
I need to have a custom msgbox in my standard exe application, but I am not a very experienced coder and am not exactly sure what I have to do. Any chance of a small example? Sorry to be a pain. Thanks in advance.
Last edited by Cimperiali; June 16th, 2004 at 02:23 AM.
...at present time, using mainly Net 4.0, Vs 2010
Special thanks to Lothar "the Great" Haensler, Chris Eastwood , dr_Michael, ClearCode, Iouri and
all the other wonderful people who made and make Codeguru a great place.
Come back soon, you Gurus.
Main thing I need to do is name the buttons with something other than the standard Yes No Cancel etc. My program is going to write a report, I want to give the options "Text" "Html" "Cancel". Doens't matter if the response is the same as YesNoCancel, just need the button text to be different.
Can I do that with that code? I can ony see a way of resizing and repositioning the msgbox.
Special thanks to Lothar "the Great" Haensler, Chris Eastwood , dr_Michael, ClearCode, Iouri and
all the other wonderful people who made and make Codeguru a great place.
Come back soon, you Gurus.
Tested:
It seems to work, but you cannot put large text as button caption
...at present time, using mainly Net 4.0, Vs 2010
Special thanks to Lothar "the Great" Haensler, Chris Eastwood , dr_Michael, ClearCode, Iouri and
all the other wonderful people who made and make Codeguru a great place.
Come back soon, you Gurus.
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.