Custom messagebox

Can anyone help me to slightly alter a Yes/No Messagebox, in a way that buttons' captions are Agree/Disagree, instead of Yes/No?

I did a thorough search on the net on similar problems, but the only one that was close to my problem can be found in http://vbnet.mvps.org/index.html?code/hooks/messageboxhook.htm, which is also for VB6, while I want to find a solution (since I can't create it myself) for VB.NET.

Please, if anyone is interested in helping me, don't tell me to create a DialoxBox form. I just want to customize a messagebox. Thanks.

Petros.
«1

Comments

  • : Can anyone help me to slightly alter a Yes/No Messagebox, in a way that buttons' captions are Agree/Disagree, instead of Yes/No?
    :
    : I did a thorough search on the net on similar problems, but the only one that was close to my problem can be found in http://vbnet.mvps.org/index.html?code/hooks/messageboxhook.htm, which is also for VB6, while I want to find a solution (since I can't create it myself) for VB.NET.
    :
    : Please, if anyone is interested in helping me, don't tell me to create a DialoxBox form. I just want to customize a messagebox. Thanks.
    :
    : Petros.
    :

    I belive you can accompolish this with the MessageBoxEx() Win32 API function.
  • : I belive you can accompolish this with the MessageBoxEx() Win32 API function.
    :

    But how do I use this API in VB.NET? Can you give me an example plz?
  • Depending on what for, and how often you use this message box you can make a form and call the function to show as dialog, which will replace the functionality of a message box. But it will take more resources to create a form.

    ~rlc
  • : Depending on what for, and how often you use this message box you can make a form and call the function to show as dialog, which will replace the functionality of a message box. But it will take more resources to create a form.
    :
    : ~rlc
    :
    I think I made it clear that I don't want a dialog form. Can you give me instead an example of how to feature a MessaboxEx for my app?
  • What's the big deal with the messagebox?

    It's perfectly possible to create a form that looks to the user *exactly* like a messagebox but with a lot of additional functionality - far more than the minor tweak you have in mind.

    Why are you so set on using the built-in messagebox (butchered via API) when there is an easy workaround available?

    =================================================================


    : :
    : I think I made it clear that I don't want a dialog form. Can you give me instead an example of how to feature a MessaboxEx for my app?
    :

  • : Can anyone help me to slightly alter a Yes/No Messagebox, in a way that buttons' captions are Agree/Disagree, instead of Yes/No?
    :
    : I did a thorough search on the net on similar problems, but the only one that was close to my problem can be found in http://vbnet.mvps.org/index.html?code/hooks/messageboxhook.htm, which is also for VB6, while I want to find a solution (since I can't create it myself) for VB.NET.
    :
    : Please, if anyone is interested in helping me, don't tell me to create a DialoxBox form. I just want to customize a messagebox. Thanks.
    :
    : Petros.
    :

    First off, here is the Win32 API documentation for MessageBoxEx()

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/dialogboxes/dialogboxreference/dialogboxfunctions/messageboxex.asp

    Second, here is hat the VB.NET declaration of the function looks like ...

    [code]
    Declare Function MessageBoxEx Lib "user32" Alias "MessageBoxExA" ( _
    ByVal hwnd As IntPtr, _
    ByVal lpText As String, _
    ByVal lpCaption As String, _
    ByVal uType As Integer, _
    ByVal wLanguageId As Integer) As Integer
    [/code]

    Here is a .NET article that shows an example, but the code is in C#. But the code should not be hard to convert to VB.NET.

    http://www.knowdotnet.com/articles/advancedapicalls.html

    There is isn't much more documentation in the web. I do recommend taking a look at the book ...

    .NET Framework Solutions: In Search of the Lost Win32 API

    Check it out at Amazon ...

    http://www.amazon.com/exec/obidos/tg/detail/-/078214134X/qid=1097069248/sr=1-1/ref=sr_1_1/002-5776929-6086441?v=glance&s=books

    The book has a detailed example of the MessageBoxEx function in both vb and c#



  • [b][red]This message was edited by rlc at 2004-10-6 8:2:22[/red][/b][hr]
    Yes it can be done, but why is a good question? I would think it would be preferable to use managed code when possible... Going to the API function will circumvent this, the framework will need to use the interop service to create a wrapper to the messagebox and its objects from the api. Obviously for some toolkits components previously developed this is great. But for a simple form, other than being comfortable using the API from past work, I am not sure what the benefit is.

    ~rlc


  • First of all I'd like to thank you for answering on my question instead of arguing on my choice to use a Messagebox (MessageBoxEx in the case) like all the others did...

    But, are you sure that one can actually change the buttons' captions using a MessageBoxEx? I went to the link you gave me, and also studied the MessageBoxEx API, but it didn't say anywhere that you can change the captions of the buttons. What was pretty clear to me is that it can show captions in a pre-selected language set, rather than change them to whatever else the user would like to. Additionally, it can display a Help button passing the correct error id to the program to show the appropriate help.

    Can you supply a better example maybe, showing exactly that you can change the captions to Whatever you like, such as 'Agree/Disagree' ?

    I'll be grateful if you do so. Anyway, thanks for your time.

    Petros.
  • : : Can anyone help me to slightly alter a Yes/No Messagebox, in a way that buttons' captions are Agree/Disagree, instead of Yes/No?
    : :
    : : I did a thorough search on the net on similar problems, but the only one that was close to my problem can be found in http://vbnet.mvps.org/index.html?code/hooks/messageboxhook.htm, which is also for VB6, while I want to find a solution (since I can't create it myself) for VB.NET.
    : :
    : : Please, if anyone is interested in helping me, don't tell me to create a DialoxBox form. I just want to customize a messagebox. Thanks.
    : :
    : : Petros.
    : :
    :

    If you go to http://vbnet.mvps.org/index.html?code/main/tocbyuse.htm you will see EXACTLY what I want. The only problem is that it is VB6. I managed to convert it into VB.NET except for the AddressOf expression that is somewhere in the code. Can you please revise the code apropriately so that it works in VB.NET?

    I NEED so much to customise the buttons' captions in my app, but I can't use a DialogBox form, as there are dozens of similar messagebox, and it will be a hell to create a DialogBox form for each one of them...

    Thanks,
    Petros.
    : First off, here is the Win32 API documentation for MessageBoxEx()
    :
    : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/dialogboxes/dialogboxreference/dialogboxfunctions/messageboxex.asp
    :
    : Second, here is hat the VB.NET declaration of the function looks like ...
    :
    : [code]
    : Declare Function MessageBoxEx Lib "user32" Alias "MessageBoxExA" ( _
    : ByVal hwnd As IntPtr, _
    : ByVal lpText As String, _
    : ByVal lpCaption As String, _
    : ByVal uType As Integer, _
    : ByVal wLanguageId As Integer) As Integer
    : [/code]
    :
    : Here is a .NET article that shows an example, but the code is in C#. But the code should not be hard to convert to VB.NET.
    :
    : http://www.knowdotnet.com/articles/advancedapicalls.html
    :
    : There is isn't much more documentation in the web. I do recommend taking a look at the book ...
    :
    : .NET Framework Solutions: In Search of the Lost Win32 API
    :
    : Check it out at Amazon ...
    :
    : http://www.amazon.com/exec/obidos/tg/detail/-/078214134X/qid=1097069248/sr=1-1/ref=sr_1_1/002-5776929-6086441?v=glance&s=books
    :
    : The book has a detailed example of the MessageBoxEx function in both vb and c#
    :
    :
    :
    :

  • [b][red]This message was edited by rlc at 2004-10-8 7:35:53[/red][/b][hr]
    Easy Tiger, just trying to help you out. You should welcome advise from others, I do, part of learning more.

    Did you try importing, just like messagebox, the API function to change it like in VB6.0?


    Declare Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" (ByVal hDlg As Integer, ByVal nIDDlgItem As Integer, ByVal lpString As String) As Integer

    !-----

    Missed that last part: addressof() is only for function addresses.

    try this maybe: http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=463&lngWId=10

    ~rlc


  • With little effort, I redid the code to work in VB.NET ... However, I created a mini framework so that you can have different classes of message boxes. I leave it up to you to mold the code further. Anyways, first I created a base class from the code:

    [code]
    Imports System.Reflection
    Imports System.Runtime.InteropServices

    Public MustInherit Class MessageBoxAPI

    'uType parameters
    Public Const MB_ICONINFORMATION As Integer = &H40
    Public Const MB_ABORTRETRYIGNORE As Integer = &H2
    Public Const MB_TASKMODAL As Integer = &H2000

    'Windows-defined Return values. The return
    'values and control IDs are identical.
    Public Const IDOK As Integer = 1
    Public Const IDCANCEL As Integer = 2
    Public Const IDABORT As Integer = 3
    Public Const IDRETRY As Integer = 4
    Public Const IDIGNORE As Integer = 5
    Public Const IDYES As Integer = 6
    Public Const IDNO As Integer = 7

    'VBnet-defined control ID for the message prompt
    Public Const IDPROMPT As Integer = &HFFFF

    'misc constants
    Public Const WH_CBT As Integer = 5
    Public Const GWL_HINSTANCE As Integer = (-6)
    Public Const HCBT_ACTIVATE As Integer = 5

    ' CREATE A DELEGATE FOR THE CALLBACK
    Protected Delegate Function msgBoxDeleg( _
    ByVal uMsg As Integer, _
    ByVal wParam As Integer, _
    ByVal lParam As Integer) As Integer

    ' DOES NOT WORK IN VB.NET
    'Private Type MSGBOX_HOOK_PARAMS
    ' hwndOwner As Long
    ' hHook As Long
    'End Type

    ' VB.NET Does not support the type keyword no more
    ' This is how you properly simulate it
    _
    Protected Structure MSGBOX_HOOK_PARAMS
    Public hwndOwner As Integer
    Public hHook As Integer
    End Structure

    'need this declared at module level as
    'it is used in the call and the hook proc
    Protected MSGHOOK As MSGBOX_HOOK_PARAMS

    ' DONT NEED THIS BECAUSE .NET HAS BUILT IN FUNTION
    'Private Declare Function GetCurrentThreadId Lib "kernel32" () As Integer

    ' DONT NEED THIS CALL BECAUSE THE NUMBER 0 IS THE DESKTOP HANDLE
    ' Public Declare Function GetDesktopWindow Lib "user32" () As Integer

    ' VB.NET WAS NOT FINDING THE ENTRYPOINT FOR THIS (BUT IM USING WINDOWS XP)
    'Private Declare Function GetWindowinteger Lib "user32" _
    ' (ByVal hwnd As Integer, _
    ' ByVal nIndex As Integer) As Integer

    ' CREATE A FUNTION THAT GETS THE hInstance IN A ROUND ABOUT WAY
    Protected Function GetWindowinteger() As IntPtr
    ' Store the array of modules loaded in the current assembly
    Dim modules() As [Module] = [Assembly].GetEntryAssembly().GetModules()

    ' Marshal the hIntstance from a module
    Return Marshal.GetHINSTANCE(modules(0))
    End Function

    Protected Declare Function MessageBox Lib "user32" _
    Alias "MessageBoxA" _
    (ByVal hwnd As Integer, _
    ByVal lpText As String, _
    ByVal lpCaption As String, _
    ByVal wType As Integer) As Integer

    Protected Declare Function SetDlgItemText Lib "user32" _
    Alias "SetDlgItemTextA" _
    (ByVal hDlg As Integer, _
    ByVal nIDDlgItem As Integer, _
    ByVal lpString As String) As Integer

    ' NOTICE THAT lpfn IS DECLARED AS THE DELEGATE I CREATED ABOVE
    ' THIS IS HOW YOU DEFINE CALL BACKS IN .NET
    Protected Declare Function SetWindowsHookEx Lib "user32" _
    Alias "SetWindowsHookExA" _
    (ByVal idHook As Integer, _
    ByVal lpfn As msgBoxDeleg, _
    ByVal hmod As IntPtr, _
    ByVal dwThreadId As Integer) As Integer

    Protected Declare Function SetWindowText Lib "user32" _
    Alias "SetWindowTextA" _
    (ByVal hwnd As Integer, _
    ByVal lpString As String) As Integer

    Protected Declare Function UnhookWindowsHookEx Lib "user32" _
    (ByVal hHook As Integer) As Integer

    ' REMOVED THE FIRST ARGUMENT BECAUSE IT WAS NOT NEEDED ANYMORE
    Public Function MessageBoxH(ByVal hwndOwner As Integer) As Integer
    'Wrapper function for the MessageBox API

    Dim hInstance As IntPtr
    Dim hThreadId As Integer

    'Set up the CBT (computer-based training) hook
    hInstance = GetWindowinteger() 'GetWindowinteger(hwndThreadOwner, GWL_HINSTANCE)
    hThreadId = AppDomain.GetCurrentThreadId() 'GetCurrentThreadId()

    'set up the MSGBOX_HOOK_PARAMS values
    'By specifying a Windows hook as one
    'of the params, we can intercept messages
    'sent by Windows and thereby manipulate
    'the dialog
    With MSGHOOK
    .hwndOwner = hwndOwner
    .hHook = SetWindowsHookEx(WH_CBT, _
    AddressOf MsgBoxHookProc, _
    hInstance, hThreadId)
    End With

    'call the MessageBox API and return the
    'value as the result of the function. The
    'Space$(120) statements assures the messagebox
    'is wide enough for the message that will
    'be set in the hook.
    '
    'NOTE: I am setting the text in the hook only
    'for demo purposes, to show how its done. You
    'certainly can pass the title and prompt text
    'right in the API call instead.
    Return MessageBox(hwndOwner, _
    Space$(120), _
    Space$(120), _
    MB_ABORTRETRYIGNORE Or MB_ICONINFORMATION)

    End Function

    ' VIRTUAL MSGBOX HOOK FUNCTION
    Public MustOverride Function MsgBoxHookProc(ByVal uMsg As Integer, _
    ByVal wParam As Integer, _
    ByVal lParam As Integer) As Integer

    End Class
    [/code]

    There is extensive changes to support inheritence and a few API modifications to support VB.NET. Basically the comments in the code should explain it.

    Next, I created a class called MyMessageBox that inherits the base MessageBoxAPI class above:

    [code]
    Public Class MyMessageBox
    Inherits MessageBoxAPI

    Public Overrides Function MsgBoxHookProc(ByVal uMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
    'When the message box is about to be shown,
    'we'll change the titlebar text, prompt message
    'and button captions
    If uMsg = HCBT_ACTIVATE Then

    'in a HCBT_ACTIVATE message, wParam holds
    'the handle to the messagebox

    SetWindowText(wParam, "VBnet MessageBox Hook Demo")

    'the ID's of the buttons on the message box
    'correspond exactly to the values they return,
    'so the same values can be used to identify
    'specific buttons in a SetDlgItemText call.
    SetDlgItemText(wParam, IDABORT, "Search C:")
    SetDlgItemText(wParam, IDRETRY, "Search D:")
    SetDlgItemText(wParam, IDIGNORE, "Cancel")

    'Change the dialog prompt text ...
    SetDlgItemText(wParam, IDPROMPT, "MyApp will now locate the application." & _
    "Please select the drive to search.")

    'we're done with the dialog, so release the hook
    UnhookWindowsHookEx(MSGHOOK.hHook)

    End If

    'return False to let normal processing continue
    Return 0
    End Function
    End Class
    [/code]

    This class does one thing and that is it overrides the MsgBoxHookProc function to cutomize a messagebox. This is where you create your own buttons and captions.

    Then finally, I changed the demo code to use the new functionality:

    [code]
    ...
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim mb As New MyMessageBox

    ' WE PASS 0 AS THE HANDLE TO THE DESKTOP
    Select Case mb.MessageBoxH(0)
    Case MessageBoxAPI.IDABORT : TextBox1.Text = "Scan C selected"
    Case MessageBoxAPI.IDRETRY : TextBox1.Text = "Scan D selected"
    Case MessageBoxAPI.IDIGNORE : TextBox1.Text = "Cancel selected"
    End Select

    End Sub
    ...
    [/code]

    Hopefully this solves your problem.
  • Thank you very much for your help. It was exactly what I was looking for. Take care. :)
  • I didn't mean my reply, which triggered your reply, in an offending way. Besides, I didn't mention your name either. But maybe you knew I was referring to you. ;)

    Anyway, I DO accept adcice as a piece of learning, and likewise I welcomed your advice too. But that still couldn't solve my problem, which was demanding an answer the soonest possible. On the other hand, my 'sarcastic' reply was not at all referring to any other part of your advice, but to your point that I'd use a dialog form, which I had made clear that wasn't my option.

    Anyway, no hurt feelings. I hope you keep learning more and more, and spread that knowledge to others too, in your way. Take care.

    Regards,
    'Tiger'.
  • Hi. I simplified a little the code that you redid for me, and works fine. But I wonder if it can cause any future problems regarding thread handling, in a strange situation (whatever that may include).

    Additionally, the custom messagebox doesn't act like a normal windows-created messagebox, in a way that it shows an icon in the taskbar, and also something of minor importance is that it doesn't 'flash' when the user tries to set the focus to the window that popped it up (it is taskmodal, and also acts likewise, but it just doesn't 'flash' twice, like all other normal messageboxes).

    If you can, please give it a look for me, telling me your opinion about: 1) any potentional problems the simplified code might arise, and 2) if there is anything to fix the different behavior I described in the second paragraph.

    In the following code, I also use a second messagebox (that is popped up by clicking Button2) for the comparison of the two messageboxes' behavior.

    Copy the following in a class:

    [code]
    Public Class CustomMessageBoxAPI

    Dim WH_CBT As Integer = 5
    Dim HCBT_ACTIVATE As Integer = 5
    Dim hHook As Integer
    Dim MB_YESNO As Integer = &H4
    Dim MB_ICONINFORMATION As Integer = &H40
    Dim MB_TASKMODAL As Integer = &H2000
    Public Shared IDYES As Integer = 6
    Public Shared IDNO As Integer = 7

    Private Declare Function MessageBox Lib "user32" Alias "MessageBoxA" _
    (ByVal hwnd As Integer, _
    ByVal lpText As String, _
    ByVal lpCaption As String, _
    ByVal wType As Integer) As Integer

    Private Declare Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" _
    (ByVal hDlg As Integer, _
    ByVal nIDDlgItem As Integer, _
    ByVal lpString As String) As Integer

    Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" _
    (ByVal idHook As Integer, _
    ByVal lpfn As CallBack, _
    ByVal hmod As Integer, _
    ByVal dwThreadId As Integer) As Integer

    Private Declare Function UnhookWindowsHookEx Lib "user32" Alias "UnhookWindowsHookEx" _
    (ByVal hHook As Integer) As Integer

    Private Delegate Function CallBack( _
    ByVal uMsg As Integer, _
    ByVal wParam As Integer, _
    ByVal lParam As Integer) As Integer

    Public Function MyMessageBox(ByVal hWnd As Integer) As Integer
    hHook = SetWindowsHookEx(WH_CBT, AddressOf MsgBoxHookProc, 0, AppDomain.GetCurrentThreadId())
    Return MessageBox(hWnd, "Prompt", "Caption", MB_YESNO Or MB_ICONINFORMATION Or MB_TASKMODAL)
    End Function

    Private Function MsgBoxHookProc(ByVal uMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
    If uMsg = HCBT_ACTIVATE Then
    SetDlgItemText(wParam, IDYES, "Agree")
    SetDlgItemText(wParam, IDNO, "Disagree")
    UnhookWindowsHookEx(hHook)
    End If
    End Function

    End Class
    [/code]

    Also, paste the following in the form's code class, adding two buttons (Button1 and Button2) and two textboxes (Textbox1 and Textbox2) on the design.

    [code]
    ...
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim mb As New CustomMessageBoxAPI()
    Select Case mb.MyMessageBox(0)
    Case CustomMessageBoxAPI.IDYES : TextBox1.Text = "Agree"
    Case CustomMessageBoxAPI.IDNO : TextBox1.Text = "Disagree"
    End Select
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    Dim varMsgBoxResult As MsgBoxResult
    varMsgBoxResult = System.Windows.Forms.MessageBox.Show("Prompt", "Caption", MessageBoxButtons.YesNo, MessageBoxIcon.Information)
    If varMsgBoxResult = MsgBoxResult.Yes Then Me.TextBox2.Text = "Yes"
    If varMsgBoxResult = MsgBoxResult.No Then Me.TextBox2.Text = "No"
    End Sub
    ...
    [/code]
    Many thanks in advance for your time.
  • So, no one is interested in helping me with this little problem?
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories