MovedMsg

Description

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:

Color-coded with vbMarkUp - try it today!
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:

Color-coded with vbMarkUp - try it today!
' 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.

Published

This sample, or the one from which it originally derived, was published (or at least peripherally mentioned) in the following article(s):

APIs Usage

This sample uses the following API calls:

Module Library Function
MMsgBoxPos.bas kernel32
user32










GetCurrentThreadId
GetClassName
GetDesktopWindow
GetSystemMetrics
GetWindowRect
IsWindow
KillTimer
MoveWindow
PostMessage
SendMessage
SetTimer
SetWindowsHookEx
UnhookWindowsHookEx

Don't see what you're looking for? Here's a complete API cross-reference.

Download

Download MovedMsg.zip   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

See Also

The following resources may also be of interest: