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.
Usage
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.
VBA Notes
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.