'[Set msgbox to new left and top values]

'Code/Example below is identical to the VB6 project.
'Code should be pasted into Form1 and Module1.

'For suggestions,
'E.B. Knoppert, ProFinance WOERDEN Netherlands
'profinance@wxs.nl

'// FORM1

Option Explicit

Private Sub Command1_Click()

    Dim R As RECT

    GetWindowRect Command1.hWnd, R

    Beep
    MsgboxPos R.Right, R.Top, Time

End Sub


'// MODULE1
Option Explicit

Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function GetActiveWindow Lib "user32" () As Long
Public Declare Function GetWindowRect Lib "user32" (ByVal hWnd As Long, lpRect As RECT) As Long
Public Declare Function MoveWindow Lib "user32" (ByVal hWnd As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Type RECT

    Left    As Long
    Top     As Long
    Right   As Long
    Bottom  As Long

End Type

Public Const WM_ACTIVATE = &H6
Public Const GWL_WNDPROC = (-4)

Global MsgboxPosPrevProc    As Long
Global MsgboxPosLeftPos     As Long
Global MsgboxPosTopPos      As Long

Public Function MsgBoxPos_Proc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    On Error Resume Next

    Dim I           As Long
    Dim R           As RECT
    Dim PrevProc    As Long 'Collect recursive procedures
    Dim mbLeft      As Long
    Dim mbTop       As Long

    PrevProc = MsgboxPosPrevProc

    'Take action while deactivating current Window (wParam = False)
    Select Case Msg
    Case WM_ACTIVATE

        'lParam contains hWnd of newly set Window.
        'A msgbox in this case.
        If lParam Then

            'Retrieve the current msgbox dimensions.
            GetWindowRect lParam, R

            'As backup, set to current Left And Top.
            mbLeft = R.Left
            mbTop = R.Top

            'Set new positions.
            If MsgboxPosLeftPos >= 0 Then mbLeft = MsgboxPosLeftPos
            If MsgboxPosTopPos >= 0 Then mbTop = MsgboxPosTopPos

            'Set and redraw.
            MoveWindow lParam, mbLeft, mbTop, R.Right - R.Left, R.Bottom - R.Top, True

        End If

    End Select

    'Return windows messages!
    MsgBoxPos_Proc = CallWindowProc(PrevProc, hWnd, Msg, wParam, lParam)

    'Unhook on deactivate.
    Select Case Msg
    Case WM_ACTIVATE

        If MsgboxPosPrevProc Then

            SetWindowLong hWnd, GWL_WNDPROC, MsgboxPosPrevProc
            MsgboxPosPrevProc = 0

        End If

    End Select

End Function

'Replacement for ordinary msgbox
Function MsgboxPos( _
  LeftPos As Long _
, TopPos As Long _
, Prompt As Variant _
, Optional Buttons As VbMsgBoxStyle = vbOKOnly _
, Optional Title As Variant _
, Optional HelpFile As Variant _
, Optional Context As Variant _
) As VbMsgBoxResult

    On Error Resume Next

    Dim hWnd As Long

    'We need to subclass the current active window.
    'This window will be deactivated when activating another Window.
    'In this case a Msgbox (-Window)
    hWnd = GetActiveWindow()

    'Enable temporary hook on active Window.
    MsgboxPosPrevProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf MsgBoxPos_Proc)

    'Set desired values global.
    'Negative values, Msgbox will skip this setting.
    MsgboxPosLeftPos = LeftPos
    MsgboxPosTopPos = TopPos

    'Enable box.
    MsgboxPos = MsgBox(Prompt, Buttons, Title, HelpFile, Context)

    'Be sure hook is succesfully eliminated.
    If MsgboxPosPrevProc Then

        SetWindowLong hWnd, GWL_WNDPROC, MsgboxPosPrevProc
        MsgboxPosPrevProc = 0

    End If

End Function