A drop-in ready module provides two methods to display standard MsgBox dialogs, provided by the VBA library, anywhere on screen. Your may choose to use absolute top/left coordinates or to position the dialog centered exactly over any given window. All positioning automatically accounts for situations where the requested position may be wholly or partially off-screen, and corrects to insure the full dialog is visible. Message box dialogs popped using either method may be automatically recalled after a specified timeout period.
This sample uses SetWindowsHookEx to set a CBT hook that watches for imminent activation of windows on the current thread, then calls the standard VBA.MsgHook function using the parameters you supplied. The appropriate CBTProc is called by Windows immediately before it activates the new dialog. This gives us a chance to reposition it wherever we want. Special precaution is needed in VBA to make sure the handle passed in wParam is indeed a message box, by looking for the special classname "#32770" with this simple test:
Public Function IsMsgBox(ByVal hWnd As Long) As Boolean Dim Class As String Const MaxLen As Long = 256 Const Target As String = "#32770" ' Retrieve classname of passed window. Class = String$(MaxLen, 0) If GetClassName(hWnd, Class, MaxLen) Then Class = Left$(Class, InStr(Class, vbNullChar) - 1) IsMsgBox = (StrComp(Class, Target, vbTextCompare) = 0) End If End Function
A standard timer callback is used to dismiss a dialog that has been displayed for the specified Timeout period, by posting a WM_CLOSE message to the handle provided in CBTProc.
Drop the MMsgBoxPos.bas file into any VB5, VB6, or VBA project. Since AddressOf is used for the callbacks, this technique is unavailable in VB4 and earlier versions of Classic VB. Two functions are now ready to call; their prototypes are:Public Function MsgBoxAbs( _ ByVal Prompt As String, _ Optional ByVal Buttons As VbMsgBoxStyle = vbOKOnly, _ Optional Title As String, _ Optional ByVal Left As Long, _ Optional ByVal Top As Long, _ Optional ByVal Timeout As Long) As VbMsgBoxResult Public Function MsgBoxOver( _ ByVal Prompt As String, _ Optional ByVal Buttons As VbMsgBoxStyle = vbOKOnly, _ Optional Title As String, _ Optional ByVal hWndOver As Long, _ Optional ByVal Timeout As Long) As VbMsgBoxResult
The first three parameters correspond exactly to the standard VBA.MsgBox function call, as does the return value from both functions. Both functions expose Timeout as their last parameter, which is the number of milliseconds before the dialog will be automatically dismissed. (This functionality is unavailable for vbAbortRetryIgnore and vbYesNo styles, as no default is defined by Windows.) The first function, MsgBoxAbs, will place the dialog exactly at the pixel positions passed in the Left and Top parameters. The second function, MsgBoxOver, will place the dialog exactly centered over the window passed in the hWndOver parameter. Both functions will, however, adjust the dialog positioning if part or all of it would extend off-screen.
The only adjustment necessary to use the MMsgBoxPos.bas file in a VBA project is toggling a boolean conditional compilation constant. Make sure this value is set appropriately:' Flag that *must* be toggled for VB/VBA! #Const VBA = True
You will see that this constant is used later, to supply a default Title value for your message box dialogs when you choose to ignore that optional parameter:
' Set title using proper default, if none supplied. #If VBA Then If Title = "" Then Title = Application.Name 'VBA #Else If Title = "" Then Title = App.Title 'VB #End If
Other than that, every aspect of this enhanced MsgBox functionality is handled directly through the API and/or language. Of course, if you'd prefer not to mess with the conditional compilation, and always use this module in one environment or the other, just hardcode that Title assignment.
This sample, or the one from which it originally derived, was published (or at least peripherally mentioned) in the following article(s):
- Manipulate Your Message Boxes, Ask the VB Pro, VBPJ, December 2000
This sample uses the following API calls:
Module Library Function MMsgBoxPos.bas kernel32
Don't see what you're looking for? Here's a complete API cross-reference.
Please, enjoy and learn from this sample. Include its code within your own projects, if you wish. But, in order to insure only the most recent code is available to all, I ask that you don't share the sample by any form of mass distribution.
Download MovedMsg.zip, 11Kb, Last Updated: Wednesday, July 13, 2005
The following resources may also be of interest:
- TimedMsg - Add a time-out to ordinary MsgBox's so they can be dismissed after some period of no user reaction.