main page >programming tips (VB5/6) >  Positioning a MessageBox or a CommonDialog     diese Seite auf deutsch diese Seite auf deutsch
 
By default a MessageBox is displayed at the center of the screen. In some situations, however, a different position may be preferable. But how can this be accomplished?

A Hook is the solution here. Short background info: placing a Hook means to tell the operating system to call a certain routine whenever a Windows message is fired that concerns the current thread. We do this in order to be notified when the MessageBox window is created; at this point the Hook routine also gives us the window handle so we can now send a message that places the window at the desired screen coordinates. The Hook should then be released immediately - except you wish to do additional tasks with it.

The creation of a window (by the way: controls like Buttons, TextBoxes and so on are windows also!) is indicated by the message WM_CREATE. Now we have to find out whether it's the window in question; we use GetClassName to find out whether it's a window of class #32770 - if so, it's the window we are looking for, and we treat it as described above.

Place the following code in a standard module:

Option Explicit

Private X32770&, Y32770&, MyHook&

  Type CWPSTRUCT
    lParam As Long
    wParam As Long
    Message As Long
    hwnd As Long
  End Type

Public Const WH_CALLWNDPROC& = 4
Public Const SWP_NOSIZE = &H1
Public Const SWP_NOZORDER = &H4

Declare Function SetWindowsHookEx& Lib "user32" Alias _
  "SetWindowsHookExA" (ByVal idHook&, ByVal lpfn&, ByVal _
  hmod&, ByVal dwThreadId&)
Declare Function UnhookWindowsHookEx& Lib "user32" (ByVal hHook&)
Declare Function GetClassName& Lib "user32" Alias _
  "GetClassNameA" (ByVal hwnd&, ByVal lpClassName$, _
  ByVal nMaxCount&)
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 Sub Position32770(ByVal x As Long, ByVal y As Long) 'parameters are in pixels!
X32770 = x
Y32770 = y
MyHook = SetWindowsHookEx(WH_CALLWNDPROC, AddressOf Hook32770, 0&, App.ThreadID)
End Sub
            

Private Function Hook32770&(ByVal nCode&, ByVal wParam&, MyStruct As CWPSTRUCT)
Const WM_CREATE& = &H1
Dim PosFlag&
  With MyStruct
    If .Message = WM_CREATE Then 'something was created
    Dim s$, i%
    s = String$(255, 0)
    GetClassName .hwnd, s, 256   'determine class name
    i = InStr(s, vbNullChar)
    If i Then s = Left$(s, i - 1)
      If s = "#32770" Then  'it's the dialog window!
      Call UnhookWindowsHookEx(MyHook)
      'release Hook, it's no longer needed; place window
      PosFlag = SWP_NOZORDER Or SWP_NOSIZE    'change only x and y
      SetWindowPos .hwnd, 0&, X32770, Y32770, 0&, 0&, PosFlag
      End If
    End If
  End With
End Function

            
Now placing a MessageBox is a simple task:

Private Sub Command1_Click()
Position32770 0, 0
MsgBox "I'm displayed in the upper left corner"
End Sub
            
Additionally, since the CommonDialog window is of class #32770 also, the exactly same code as above can be used to place CommonDialogs as well.
main page >  programming tips (VB5/6) >  this page