Anzeige
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender

Forumthread: VBA: msgbox button Capchen ändern

VBA: msgbox button Capchen ändern
10.01.2020 12:00:20
Charly
Hallo,
Frage:
Ist es möglich via VBA die Angezeigte Beschrieftung der Button´s einer MsgBox zu ändern?
Sub UF2_Word_CheckBox()
iClick = MsgBox( _
prompt:="Darstellung der Schmerzeinschätzung?" & vbCrLf & _
"Über (NRS) " & "oder " & "Über (BESD)", _
Buttons:=vbExclamation + vbYesNoCancel)
If iClick = vbYes Then  'Capchen des Button statt "Ja" in "NRS" ändern
ElseIf iClick = vbNo Then 'Capchen des Button statt "Nein" in "BESD" ändern
ElseIf iClick = vbCancel Then
End If
End Sub

Gruß Charly
Anzeige

22
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
Caption kann nicht geändert werden.Userform! (owT)
10.01.2020 12:11:19
EtoPHG

AW: VBA: msgbox button Capchen ändern
10.01.2020 12:11:59
Torsten
Hallo Charly,
das geht mit einer Messagebox nicht. Bau dir eine eigene Messagebox aus einer Userform, da kannst du dann beschriften, was du willst.
Noch zur Info: Das heist Caption und nicht Capchen.
Gruss Torsten
AW: VBA: msgbox button Capchen ändern
10.01.2020 12:17:43
Nepumuk
Hallo Charly,
teste mal:
Option Explicit

Private Declare Function FindWindowA Lib "user32.dll" ( _
    ByVal lpClassName As String, _
    ByVal lpWindowName As String) As Long
Private Declare Function SetTimer Lib "user32.dll" ( _
    ByVal Hwnd As Long, _
    ByVal nIDEvent As Long, _
    ByVal uElapse As Long, _
    ByVal lpTimer As Long) As Long
Private Declare Function KillTimer Lib "user32.dll" ( _
    ByVal Hwnd As Long, _
    ByVal nIDEvent As Long) As Long
Private Declare Function MessageBoxA Lib "user32.dll" ( _
    ByVal Hwnd As Long, _
    ByVal lpText As String, _
    ByVal lpCaption As String, _
    ByVal wType As Long) As Long
Private Declare Function SendDlgItemMessageA Lib "user32.dll" ( _
    ByVal hDlg As Long, _
    ByVal nIDDlgItem As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As String) As Long

Private Const TIMER_ID = 0
Private Const TIMER_ELAPSE = 25
Private Const WM_SETTEXT = &HC
Private Const GC_CLASSNAMEMSEXCEL = "XLMAIN"
Private Const GC_CLASSNAMEMSDIALOGS = "#32770"

Private lstrButtonCaption1 As String
Private lstrButtonCaption2 As String
Private lstrButtonCaption3 As String
Private lstrBoxTitel As String
Private llngHwnd As Long

Private Function MsgBoxPlus( _
        ByVal strText As String, _
        ByVal strTitle As String, _
        ByVal strButtonText1 As String, _
        Optional ByVal strButtonText2 As String, _
        Optional ByVal strButtonText3 As String, _
        Optional ByVal enmStyle As VbMsgBoxStyle) As Long

    
    Dim enmResult As VbMsgBoxResult
    
    lstrButtonCaption1 = strButtonText1
    lstrButtonCaption2 = strButtonText2
    lstrButtonCaption3 = strButtonText3
    lstrBoxTitel = strTitle
    
    If Val(Application.Version) > 9 Then
        llngHwnd = Application.Hwnd
    Else
        llngHwnd = FindWindowA(GC_CLASSNAMEMSEXCEL, Application.Caption)
    End If
    
    Call SetTimer(llngHwnd, TIMER_ID, TIMER_ELAPSE, AddressOf SetButtonText)
    
    If lstrButtonCaption2 = "" And lstrButtonCaption3 = "" Then
        enmResult = MessageBoxA(llngHwnd, strText, strTitle, vbOKOnly Or enmStyle)
    ElseIf lstrButtonCaption2 <> "" And lstrButtonCaption3 = "" Then
        enmResult = MessageBoxA(llngHwnd, strText, strTitle, vbYesNo Or enmStyle)
    Else
        enmResult = MessageBoxA(llngHwnd, strText, strTitle, vbAbortRetryIgnore Or enmStyle)
    End If
    
    If enmResult = vbOK Or enmResult = vbYes Or enmResult = vbAbort Then
        MsgBoxPlus = 1
    ElseIf enmResult = vbNo Or enmResult = vbRetry Then
        MsgBoxPlus = 2
    Else
        MsgBoxPlus = 3
    End If
    
End Function

Private Sub SetButtonText()
    
    Dim lngBox_hWnd As Long
    
    Call KillTimer(llngHwnd, TIMER_ID)
    
    lngBox_hWnd = FindWindowA(GC_CLASSNAMEMSDIALOGS, lstrBoxTitel)
    
    If lstrButtonCaption2 = "" And lstrButtonCaption3 = "" Then
        Call SendDlgItemMessageA(lngBox_hWnd, vbCancel, WM_SETTEXT, 0&, lstrButtonCaption1)
    ElseIf lstrButtonCaption2 <> "" And lstrButtonCaption3 = "" Then
        Call SendDlgItemMessageA(lngBox_hWnd, vbYes, WM_SETTEXT, 0&, lstrButtonCaption1)
        Call SendDlgItemMessageA(lngBox_hWnd, vbNo, WM_SETTEXT, 0&, lstrButtonCaption2)
    Else
        Call SendDlgItemMessageA(lngBox_hWnd, vbAbort, WM_SETTEXT, 0&, lstrButtonCaption1)
        Call SendDlgItemMessageA(lngBox_hWnd, vbRetry, WM_SETTEXT, 0&, lstrButtonCaption2)
        Call SendDlgItemMessageA(lngBox_hWnd, vbIgnore, WM_SETTEXT, 0&, lstrButtonCaption3)
    End If
    
End Sub

Public Sub Aufruf()
    Select Case MsgBoxPlus(strText:="Darstellung der Schmerzeinschätzung?" & vbLf & _
                "Über (NRS) oder Über (BESD)", strTitle:="Titel", _
                strButtonText1:="NRS", strButtonText2:="BESD", _
                strButtonText3:="Abbrechen", enmStyle:=vbExclamation)
        Case 1
            MsgBox "Button 1"
        Case 2
            MsgBox "Button 2"
        Case 3
            MsgBox "Button 3"
    End Select
End Sub

Gruß
Nepumuk
Anzeige
AW: VBA: msgbox button Capchen ändern
10.01.2020 12:28:32
Charly
In welches Modeul/UF muss ich das Reinlegen?
Gruß Charly
AW: VBA: msgbox button Capchen ändern
10.01.2020 12:34:51
Nepumuk
Hallo Charly,
in ein Standardmodul (Menüleiste - Einfügen - Modul). Die Prozedur "Aufruf" kannst du auch in das Modul deines Userforms bzw. in die Prozedur "UF2_Word_CheckBox()" kopieren (natürlich dann ohne mein <pre>Sub und End Sub</pre>.
Gruß
Nepumuk
Anzeige
AW: VBA: msgbox button Capchen ändern
10.01.2020 12:41:25
Charly
Test in einem Modul
Typen Unverträglich
In der Zeile "llngHwnd = FindWindowA(GC_CLASSNAMEMSEXCEL, Application.Caption)"
Application.Caption wird dabei markiert.

Private Function MsgBoxPlus( _
ByVal strText As String, _
ByVal strTitle As String, _
ByVal strButtonText1 As String, _
Optional ByVal strButtonText2 As String, _
Optional ByVal strButtonText3 As String, _
Optional ByVal enmStyle As VbMsgBoxStyle) As Long
Dim enmResult As VbMsgBoxResult
lstrButtonCaption1 = strButtonText1
lstrButtonCaption2 = strButtonText2
lstrButtonCaption3 = strButtonText3
lstrBoxTitel = strTitle
If Val(Application.Version) > 9 Then
llngHwnd = Application.Hwnd
Else
llngHwnd = FindWindowA(GC_CLASSNAMEMSEXCEL, Application.Caption)
End If
Call SetTimer(llngHwnd, TIMER_ID, TIMER_ELAPSE, AddressOf SetButtonText)
If lstrButtonCaption2 = "" And lstrButtonCaption3 = "" Then
enmResult = MessageBoxA(llngHwnd, strText, strTitle, vbOKOnly Or enmStyle)
ElseIf lstrButtonCaption2  "" And lstrButtonCaption3 = "" Then
enmResult = MessageBoxA(llngHwnd, strText, strTitle, vbYesNo Or enmStyle)
Else
enmResult = MessageBoxA(llngHwnd, strText, strTitle, vbAbortRetryIgnore Or enmStyle)
End If
If enmResult = vbOK Or enmResult = vbYes Or enmResult = vbAbort Then
MsgBoxPlus = 1
ElseIf enmResult = vbNo Or enmResult = vbRetry Then
MsgBoxPlus = 2
Else
MsgBoxPlus = 3
End If
End Function

Anzeige
AW: VBA: msgbox button Capchen ändern
10.01.2020 12:49:12
Nepumuk
Hallo Charly,
hast du ein 64Bit Office? Wenn ja dann funktioniert mein Code nicht.
Gruß
Nepumuk
AW: VBA: msgbox button Capchen ändern
10.01.2020 13:13:55
Charly
ja habe die 64bit Version.
Gruß Charly
AW: VBA: msgbox button Capchen ändern
10.01.2020 12:18:18
volti
Hallo Charly,
das ist nicht möglich.
Du hast aber zwei Möglichkeiten:
Über eine Userform kannst Du eine MsgBox nachbilden und gestalten wie Du möchtest.
Oder Du verwendest den nachfolgenden Code. Diese verwendet die Msgbox aus Windows und erlaubt über eine spezielle Technik das Ändern der Button-Beschriftung.
Zur Beachtung: ich habe es so programmiert, dass der Buttontext als Rückgabe erfolgt und keine Buttonnummer.
Kannst Du ja mal ausprobieren.
'Userdefined MsgBox 17.12.2016 by KHV
Option Explicit
Private Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hWnd As LongPtr, _
        ByVal hWndInsertAfter As LongPtr, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Declare PtrSafe Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" ( _
        ByVal hDlg As LongPtr, ByVal nIDDlgItem As Long, ByVal lpString As String) As Long
Private Declare PtrSafe Function GetCurrentThreadId Lib "kernel32" () As Long
Private Declare PtrSafe Function GetDesktopWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Function MessageBox Lib "user32" Alias "MessageBoxA" ( _
        ByVal hWnd As LongPtr, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Long) As Long
Private Declare PtrSafe Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" ( _
        ByVal idHook As Long, ByVal lpfn As LongPtr, ByVal hmod As LongPtr, ByVal dwThreadId As Long) As LongPtr
Private Declare PtrSafe Function UnhookWindowsHookEx Lib "user32" (ByVal hhk As LongPtr) As Long
Private Declare PtrSafe Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongPtrA" ( _
        ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr
Private Const HWND_TOPMOST = -1
Type MSGBOX_STRUCT
  hHook      As LongPtr
  hwndOwner  As LongPtr
  vbBtnStyle As Integer
  vbDlgStyle As Long
  x          As Long
  y          As Long
  sBtns()    As String
End Type
Dim Msg As MSGBOX_STRUCT
Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As Long) As LongPtr
'Funktion versieht die Buttons und Textbereiche mit neuen Texten
'Je nach Anzahl gewünschter Buttons wird eine MSGBOX mit passendem Style aufgemacht
'Schalter: vbMsgBoxSetForeground, vbSystemModal, vbMsgBoxHelpButton, vbDefaultButton1,2,3,4
 If uMsg = 5 Then
   With Msg
    If .vbDlgStyle &GT;= vbMsgBoxSetForeground Then _
    SetWindowPos wParam, HWND_TOPMOST, 0, 0, 0, 0, &H3 '&H3=SWP_NOMOVE Or SWP_NOSIZE
    SetDlgItemText wParam, 1, .sBtns(0)
    SetDlgItemText wParam, 2, .sBtns(1)
    SetDlgItemText wParam, 3, .sBtns(0)
    SetDlgItemText wParam, 4, .sBtns(1)
    SetDlgItemText wParam, 5, .sBtns(2)
    If .x &GT; 0 And .y &GT; 0 Then _
    SetWindowPos wParam, 0, .x, .y, 0, 0, &H1 '&H1=SWP_NOSIZE
    UnhookWindowsHookEx .hHook
   End With
 End If
 MsgBoxHookProc = False
End Function
Public Function MsgBoxEx(MsgTxt As String, Titel As String, _
       Optional sButtons As String = "OK", _
       Optional vbIcon As Long, Optional bParent As Boolean, _
       Optional ByVal x As Long, Optional ByVal y As Long) As String
'Funktion gibt den Text zum gedrückten Button zurück
 With Msg
  If x &GT; 0 And y &GT; 0 Then .x = x: .y = y
  If sButtons = "" Then
   Select Case (vbIcon And &H7)
   Case 0:  sButtons = "&Ok"
   Case 1:  sButtons = "&Ok,A&bbrechen"
   Case 2:  sButtons = "A&bbrechen,&Wiederholen,&Ignorieren"
   Case 3:  sButtons = "&Ja,&Nein,A&bbrechen"
   Case 4:  sButtons = "&Ja,&Nein"
   Case 5:  sButtons = "&Wiederholen,A&bbrechen"
   End Select
  End If
  .sBtns = Split(sButtons & ",,", ",")
  .vbDlgStyle = (vbIcon And &HFFFF8)
  .vbBtnStyle = UBound(.sBtns()) - 2
  If bParent Then
     .hwndOwner = GetDesktopWindow() 'MsgBox unabhängig von Excel
  Else
     .hwndOwner = Application.hWnd   'MsgBox an Excel gebunden
  End If
  .hHook = SetWindowsHookEx(5, AddressOf MsgBoxHookProc, _
           GetWindowLongPtr(Application.hWnd, -6), GetCurrentThreadId())
  Select Case MessageBox(.hwndOwner, Replace(MsgTxt, "¶", vbLf), Titel, .vbBtnStyle Or .vbDlgStyle)
  Case 1, 6, 3: x = 0 'vbOk, vbYes,   vbAbort
  Case 7, 4, 2: x = 1 'vbNo, vbRetry, vkCancel
  Case 5:       x = 2 'vbIgnore
  End Select
  MsgBoxEx = Replace(.sBtns(x), "&", "")
 End With
End Function
Sub MeinMsgBoxTest()
  MsgBox MsgBoxEx("Darstellung der Schmerzeinschätzung?" & vbCrLf & _
    "über (NRS) " & "oder " & "über (BESD)", "Meine MSG-Box", _
           "&NRS,BDSD,A&bbrechen", vbCritical Or vbMsgBoxSetForeground, True)
End Sub

viele Grüße
Karl-Heinz

Anzeige
AW: VBA: msgbox button Capchen ändern
10.01.2020 12:43:33
Charly
Hätte nicht gedacht das mann über Windows sich ne MsgBox anzeigenlassen kann.
Funktioniert.
Gruß Charly
AW: VBA: msgbox button Capchen ändern
10.01.2020 14:16:22
volti
Hallo Charly,
danke für die Rückmeldung und ja, man kann fast alles irgendwie über die API realisieren.
Ist aber oft kompliziert und wird schnell umfangreich....
viele Grüße
KH
Anzeige
AW: VBA: msgbox button Capchen ändern
10.01.2020 18:09:32
Thomas
Hallo voltiV,
ich bin gerade auf dein Beispiel gestoßen.
Hast du dieses Beispiel auch als eine variante die unter Office
32 bit funktioniert?
Und kannst du das so einstellen das diese Box genau unter dem Mauspfeil startet?
Hab schon mal recht vielen dank im voraus.
mfg thomas
Anzeige
AW: VBA: msgbox button Capchen ändern
10.01.2020 20:04:51
Nepumuk
Hallo Thomas,
teste mal:
Option Explicit

Private Declare Function FindWindowA Lib "user32.dll" ( _
    ByVal lpClassName As String, _
    ByVal lpWindowName As String) As Long
Private Declare Function SetTimer Lib "user32.dll" ( _
    ByVal hwnd As Long, _
    ByVal nIDEvent As Long, _
    ByVal uElapse As Long, _
    ByVal lpTimer As Long) As Long
Private Declare Function KillTimer Lib "user32.dll" ( _
    ByVal hwnd As Long, _
    ByVal nIDEvent As Long) As Long
Private Declare Function MessageBoxA Lib "user32.dll" ( _
    ByVal hwnd As Long, _
    ByVal lpText As String, _
    ByVal lpCaption As String, _
    ByVal wType As Long) As Long
Private Declare Function SendDlgItemMessageA Lib "user32.dll" ( _
    ByVal hDlg As Long, _
    ByVal nIDDlgItem As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As String) As Long
Private Declare PtrSafe Function GetWindowPlacement Lib "user32.dll" ( _
    ByVal hwnd As LongPtr, _
    ByRef lpwndpl As WINDOWPLACEMENT) As Long
Private Declare PtrSafe Function GetCursorPos Lib "user32.dll" ( _
    ByRef lpPoint As POINTAPI) As Long
Private Declare Function GetSystemMetrics Lib "user32.dll" ( _
    ByVal nIndex As Long) As Long
Private Declare PtrSafe Function MoveWindow Lib "user32.dll" ( _
    ByVal hwnd As LongPtr, _
    ByVal x As Long, _
    ByVal y As Long, _
    ByVal nWidth As Long, _
    ByVal nHeight As Long, _
    ByVal bRepaint As Long) As Long

Private Type POINTAPI
    x As Long
    y As Long
End Type

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Type WINDOWPLACEMENT
    Length As Long
    flags As Long
    showCmd As Long
    ptMinPosition As POINTAPI
    ptMaxPosition As POINTAPI
    rcNormalPosition As RECT
End Type

Private Const WM_PAINT As Long = &HF

Private Const SM_CXSCREEN As Long = 0&
Private Const SM_CYSCREEN As Long = 1&

Private Const TIMER_ID As Long = 0
Private Const TIMER_ELAPSE As Long = 25
Private Const WM_SETTEXT As Long = &HC
Private Const GC_CLASSNAMEMSDIALOGS As String = "#32770"

Private lstrButtonCaption1 As String
Private lstrButtonCaption2 As String
Private lstrButtonCaption3 As String
Private lstrBoxTitel As String
Private llngHwnd As Long

Private Function MsgBoxPlus( _
        ByVal strText As String, _
        ByVal strTitle As String, _
        ByVal strButtonText1 As String, _
        Optional ByVal strButtonText2 As String, _
        Optional ByVal strButtonText3 As String, _
        Optional ByVal enmStyle As VbMsgBoxStyle) As Long

    Dim enmResult As VbMsgBoxResult
    lstrButtonCaption1 = strButtonText1
    lstrButtonCaption2 = strButtonText2
    lstrButtonCaption3 = strButtonText3
    lstrBoxTitel = strTitle
    llngHwnd = Application.hwnd
    Call SetTimer(llngHwnd, TIMER_ID, TIMER_ELAPSE, AddressOf SetButtonText)
    If lstrButtonCaption2 = "" And lstrButtonCaption3 = "" Then
        enmResult = MessageBoxA(llngHwnd, strText, strTitle, vbOKOnly Or enmStyle)
    ElseIf lstrButtonCaption2 <> "" And lstrButtonCaption3 = "" Then
        enmResult = MessageBoxA(llngHwnd, strText, strTitle, vbYesNo Or enmStyle)
    Else
        enmResult = MessageBoxA(llngHwnd, strText, strTitle, vbAbortRetryIgnore Or enmStyle)
    End If
    If enmResult = vbOK Or enmResult = vbYes Or enmResult = vbAbort Then
        MsgBoxPlus = 1
    ElseIf enmResult = vbNo Or enmResult = vbRetry Then
        MsgBoxPlus = 2
    Else
        MsgBoxPlus = 3
    End If
End Function

Private Sub SetButtonText()
    Dim lngBoxHwnd As Long
    Call KillTimer(llngHwnd, TIMER_ID)
    lngBoxHwnd = FindWindowA(GC_CLASSNAMEMSDIALOGS, lstrBoxTitel)
    If lstrButtonCaption2 = "" And lstrButtonCaption3 = "" Then
        Call SendDlgItemMessageA(lngBoxHwnd, vbCancel, WM_SETTEXT, 0&, lstrButtonCaption1)
    ElseIf lstrButtonCaption2 <> "" And lstrButtonCaption3 = "" Then
        Call SendDlgItemMessageA(lngBoxHwnd, vbYes, WM_SETTEXT, 0&, lstrButtonCaption1)
        Call SendDlgItemMessageA(lngBoxHwnd, vbNo, WM_SETTEXT, 0&, lstrButtonCaption2)
    Else
        Call SendDlgItemMessageA(lngBoxHwnd, vbAbort, WM_SETTEXT, 0&, lstrButtonCaption1)
        Call SendDlgItemMessageA(lngBoxHwnd, vbRetry, WM_SETTEXT, 0&, lstrButtonCaption2)
        Call SendDlgItemMessageA(lngBoxHwnd, vbIgnore, WM_SETTEXT, 0&, lstrButtonCaption3)
    End If
    Call SetWindowPos
End Sub

Private Sub SetWindowPos()
    Dim lngLeft As Long, lngTop As Long
    Dim lngptrBoxHwnd As LongPtr
    Dim udtWindowPlacemet As WINDOWPLACEMENT
    Dim udtCursorPos As POINTAPI
    lngptrBoxHwnd = FindWindowA(GC_CLASSNAMEMSDIALOGS, lstrBoxTitel)
    Call GetWindowPlacement(lngptrBoxHwnd, udtWindowPlacemet)
    Call GetCursorPos(udtCursorPos)
    udtWindowPlacemet.Length = Len(udtWindowPlacemet)
    With udtWindowPlacemet.rcNormalPosition
        If udtCursorPos.x + (.Right - .Left) > GetSystemMetrics(SM_CXSCREEN) Then
            lngLeft = udtCursorPos.x - (.Right - .Left)
        Else
            lngLeft = udtCursorPos.x
        End If
        If udtCursorPos.y + (.Bottom - .Top) > GetSystemMetrics(SM_CYSCREEN) Then
            lngTop = udtCursorPos.y - (.Bottom - .Top)
        Else
            lngTop = udtCursorPos.y
        End If
        Call MoveWindow(lngptrBoxHwnd, lngLeft, lngTop, .Right - .Left, .Bottom - .Top, WM_PAINT)
    End With
End Sub

Public Sub Aufruf()
    Select Case MsgBoxPlus(strText:="Darstellung der Schmerzeinschätzung?" & vbLf & _
                "Über (NRS) oder Über (BESD)", strTitle:="Titel", _
                strButtonText1:="NRS", strButtonText2:="BESD", _
                strButtonText3:="Abbrechen", enmStyle:=vbExclamation)
        Case 1
            MsgBox "Button 1"
        Case 2
            MsgBox "Button 2"
        Case 3
            MsgBox "Button 3"
    End Select
End Sub

Gruß
Nepumuk
Anzeige
AW: VBA: msgbox button Capchen ändern
10.01.2020 20:39:18
volti
Hallo Thomas,
danke der Nachfrage. Da ich selbst seit meinem Rentnereintritt nur noch 64 Bit privat habe, schreibe ich meistens hierfür. Anliegend trotzdem mal eine 32 Bit-Version, die aber nicht testen kann.
Die Funktion war auch schon für Positionierung der MsgBox vorgesehen. Jetzt wird sie an der Mausposition gestartet, hoffentlich. :-)
'Userdefined MsgBox 17.12.2016 by KHV
Option Explicit
Private 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
Private Declare Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" ( _
        ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal lpString As String) As Long
Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function MessageBox Lib "user32" Alias "MessageBoxA" ( _
        ByVal hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, _
        ByVal wType As Long) As Long
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" ( _
        ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, _
        ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" ( _
        ByVal hhk As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" ( _
        ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Type POINTAPI
     x As Long
     y As Long
End Type
Private Const HWND_TOPMOST = -1
Type MSGBOX_STRUCT
  hHook      As Long
  hwndOwner  As Long
  vbBtnStyle As Integer
  vbDlgStyle As Long
  x          As Long
  y          As Long
  sBtns()    As String
End Type
Dim Msg As MSGBOX_STRUCT
Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'Funktion versieht die Buttons mit neuen Texten
'Je nach Anzahl gewünschter Buttons wird eine MSGBOX mit passendem Style aufgemacht
'Schalter: vbMsgBoxSetForeground, vbSystemModal, vbMsgBoxHelpButton, vbDefaultButton1,2,3,4
 If uMsg = 5 Then
   With Msg
    If .vbDlgStyle &GT;= vbMsgBoxSetForeground Then _
    SetWindowPos wParam, HWND_TOPMOST, 0, 0, 0, 0, &H3 '&H3=SWP_NOMOVE Or SWP_NOSIZE
    SetDlgItemText wParam, 1, .sBtns(0)
    SetDlgItemText wParam, 2, .sBtns(1)
    SetDlgItemText wParam, 3, .sBtns(0)
    SetDlgItemText wParam, 4, .sBtns(1)
    SetDlgItemText wParam, 5, .sBtns(2)
    If .x &GT; 0 And .y &GT; 0 Then _
    SetWindowPos wParam, 0, .x, .y, 0, 0, &H1 '&H1=SWP_NOSIZE
    UnhookWindowsHookEx .hHook
   End With
 End If
 MsgBoxHookProc = False
End Function
Public Function MsgBoxEx(MsgTxt As String, sTitle As String, _
       Optional sButtons As String = "OK", _
       Optional vbIcon As Long, Optional bParent As Boolean, _
       Optional ByVal x As Long, Optional ByVal y As Long) As String
'Funktion gibt den Text zum gedrückten Button zurück
 With Msg
  .x = x: .y = y
  If sButtons = "" Then
   Select Case (vbIcon And &H7)
   Case 0:  sButtons = "&Ok"
   Case 1:  sButtons = "&Ok,A&bbrechen"
   Case 2:  sButtons = "A&bbrechen,&Wiederholen,&Ignorieren"
   Case 3:  sButtons = "&Ja,&Nein,A&bbrechen"
   Case 4:  sButtons = "&Ja,&Nein"
   Case 5:  sButtons = "&Wiederholen,A&bbrechen"
   End Select
  End If
  .sBtns = Split(sButtons & ",,", ",")
  .vbDlgStyle = (vbIcon And &HFFFF8)
  .vbBtnStyle = UBound(.sBtns()) - 2
  If bParent Then
     .hwndOwner = GetDesktopWindow() 'MsgBox unabhängig von Excel
  Else
     .hwndOwner = Application.hWnd   'MsgBox an Excel gebunden
  End If
  .hHook = SetWindowsHookEx(5, AddressOf MsgBoxHookProc, _
           GetWindowLong(Application.hWnd, -6), GetCurrentThreadId())
  Select Case MessageBox(.hwndOwner, Replace(MsgTxt, "¶", vbLf), sTitle, .vbBtnStyle Or .vbDlgStyle)
  Case 1, 6, 3: x = 0 'vbOk, vbYes,   vbAbort
  Case 7, 4, 2: x = 1 'vbNo, vbRetry, vkCancel
  Case 5:       x = 2 'vbIgnore
  End Select
  MsgBoxEx = Replace(.sBtns(x), "&", "")
 End With
End Function
'Diese Sub ist zum Testen
'Es können 1,2 oder 3 Button angezeigt werden =&GT; Kommagetrennt angeben
'& vor einem Buchtabn stellt den Shortcuttaste dar
'¶ stellt einen Zeilenumbruch dar
'Zurückgegeben wird keine Nummer sondern der Buttontext des geklickten Buttons
Sub MeinMsgBoxTest()
  Dim pt As POINTAPI
  GetCursorPos pt
  MsgBox MsgBoxEx("Habe die Datei nicht gefunden,¶Mail trotzdem absenden?", "Mailversand", _
           "&Senden,Er&neut,A&bbrechen", vbCritical Or vbMsgBoxSetForeground, True, pt.x, pt.y)
End Sub

viele Grüße
Karl-Heinz

Anzeige
AW: VBA: msgbox button Capchen ändern
10.01.2020 23:20:11
Thomas
Hallo Nepumuk und volti,
ihr seid super Leute. Habt echt vielen dank für eure Hilfe.
Beide Versionen laufen ohne Fehlermeldungen.
Das einzige was aufgefallen ist das beim Beispiel von Nepumuk die Meldung erst in der Mitte der Userform gestartet wird. Aber nach einer Sekunde positioniert sich das Fenster genau an der Mouse Position.
Ich werde mal versuchen die Beispiele so zusammenzubauen das die Versionen allein erkennen ob es ein 32 bit oder ein 64 bit System ist. Ich denke das ich dies bestimmt, dank euch, hin bekomme. ( hoffe ich jedenfalls ).
Ihr wisst gar nicht wie lange ich dies schon versuche und am ende immer an irgendetwas gescheitert bin. Bin total glücklich. Habt recht vielen vielen dank.
Ich wünsche euch noch ein ruhiges WE.
https://www.herber.de/bbs/user/134314.xlsm
mfg thomas
Anzeige
AW: VBA: msgbox button Capchen ändern
10.01.2020 23:37:21
volti
Hallo Thomas,
viel Erfolg dabei und noch ein Tipp:
Compilerschalter verwenden
#IF Win64 and VBA7 then oder auch nur #IF VBA7 then
#ELSE
#END IF
Z.B.auch für die Functions, usw.:
#IF Win64 and VBA7 then
Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As Long) As LongPtr
#ELSE
Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
#END IF
viele Grüße
KH
Anzeige
mist bekomme es doch nicht hin
11.01.2020 00:51:40
Thomas
Hallo volti,
hab nochmal rechtvielen dank für den tipp.
Aber ich schaffe es trotzdem nicht. Ich bekomme auf dem 64 Bit System
an dieser Stelle .hwndOwner = GetDesktopWindow() die Fehlermeldung
" Typen unverträglichkeit "
https://www.herber.de/bbs/user/134316.xlsm
Kannst du mal schauen was ich da wieder für ein Murks gebaut hab?
Hab schon mal recht vielen dank für deine Ausdauer.
mfg thomas
Anzeige
AW: mist bekomme es doch nicht hin
11.01.2020 09:04:03
volti
hallo Thomas,
die Struct muss natürlich u.a. auch umgesetzt werden:
Bin bis heute abend offline:
#If Win64 And VBA7 Then
Type MSGBOX_STRUCT
  hHook      As LongPtr
  hwndOwner  As LongPtr
  vbBtnStyle As Integer
  vbDlgStyle As Long
  x          As Long
  y          As Long
  sBtns()    As String
End Type
#Else
Type MSGBOX_STRUCT
  hHook      As Long
  hwndOwner  As Long
  vbBtnStyle As Integer
  vbDlgStyle As Long
  x          As Long
  y          As Long
  sBtns()    As String
End Type
#End If
viele Grüße
Karl-Heinz

Anzeige
AW: mist bekomme es doch nicht hin
11.01.2020 12:21:20
Thomas
Hallo volti,
mist, ich habe mir schon gedacht das es nur so etwas sein kann.
Jetzt läuft es perfekt.
Kannst du mir noch die Stellschraube zeigen wenn ich 5 Button haben möchte?
Hab schon mal recht vielen dank für deine Hilfe und vor allem auch Ausdauer.
https://www.herber.de/bbs/user/134320.xlsm
Option Explicit
#If Win64 And VBA7 Then
Private Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hWnd As LongPtr, _
ByVal hWndInsertAfter As LongPtr, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Declare PtrSafe Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" ( _
ByVal hDlg As LongPtr, ByVal nIDDlgItem As Long, ByVal lpString As String) As Long
Private Declare PtrSafe Function GetCurrentThreadId Lib "kernel32" () As Long
Private Declare PtrSafe Function GetDesktopWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Function MessageBox Lib "user32" Alias "MessageBoxA" ( _
ByVal hWnd As LongPtr, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Long) As Long
Private Declare PtrSafe Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" ( _
ByVal idHook As Long, ByVal lpfn As LongPtr, ByVal hmod As LongPtr, ByVal dwThreadId As Long) As LongPtr
Private Declare PtrSafe Function UnhookWindowsHookEx Lib "user32" (ByVal hhk As LongPtr) As Long
Private Declare PtrSafe Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongPtrA" ( _
ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr
Private Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As LongPtr
Type MSGBOX_STRUCT
hHook As LongPtr
hwndOwner As LongPtr
vbBtnStyle As Integer
vbDlgStyle As Long
x As Long
y As Long
sBtns() As String
End Type
#Else
Private 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
Private Declare Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" ( _
ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal lpString As String) As Long
Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function MessageBox Lib "user32" Alias "MessageBoxA" ( _
ByVal hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, _
ByVal wType As Long) As Long
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" ( _
ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" ( _
ByVal hhk As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" ( _
ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Type MSGBOX_STRUCT
hHook As Long
hwndOwner As Long
vbBtnStyle As Integer
vbDlgStyle As Long
x As Long
y As Long
sBtns() As String
End Type
#End If
Type POINTAPI
x As Long
y As Long
End Type
Private Const HWND_TOPMOST = -1
Dim Msg As MSGBOX_STRUCT
#If Win64 And VBA7 Then
Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As Long) As LongPtr
'Funktion versieht die Buttons mit neuen Texten
'Je nach Anzahl gewünschter Buttons wird eine MSGBOX mit passendem Style aufgemacht
'Schalter: vbMsgBoxSetForeground, vbSystemModal, vbMsgBoxHelpButton, vbDefaultButton1,2,3,4
If uMsg = 5 Then
With Msg
If .vbDlgStyle >= vbMsgBoxSetForeground Then _
SetWindowPos wParam, HWND_TOPMOST, 0, 0, 0, 0, &H3 '&H3=SWP_NOMOVE Or SWP_NOSIZE
SetDlgItemText wParam, 1, .sBtns(0)
SetDlgItemText wParam, 2, .sBtns(1)
SetDlgItemText wParam, 3, .sBtns(0)
SetDlgItemText wParam, 4, .sBtns(1)
SetDlgItemText wParam, 5, .sBtns(2)
If .x > 0 And .y > 0 Then _
SetWindowPos wParam, 0, .x, .y, 0, 0, &H1 '&H1=SWP_NOSIZE
UnhookWindowsHookEx .hHook
End With
End If
MsgBoxHookProc = False
#Else
Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'Funktion versieht die Buttons mit neuen Texten
'Je nach Anzahl gewünschter Buttons wird eine MSGBOX mit passendem Style aufgemacht
'Schalter: vbMsgBoxSetForeground, vbSystemModal, vbMsgBoxHelpButton, vbDefaultButton1,2,3,4
If uMsg = 5 Then
With Msg
If .vbDlgStyle >= vbMsgBoxSetForeground Then _
SetWindowPos wParam, HWND_TOPMOST, 0, 0, 0, 0, &H3 '&H3=SWP_NOMOVE Or SWP_NOSIZE
SetDlgItemText wParam, 1, .sBtns(0)
SetDlgItemText wParam, 2, .sBtns(1)
SetDlgItemText wParam, 3, .sBtns(0)
SetDlgItemText wParam, 4, .sBtns(1)
SetDlgItemText wParam, 5, .sBtns(2)
If .x > 0 And .y > 0 Then _
SetWindowPos wParam, 0, .x, .y, 0, 0, &H1 '&H1=SWP_NOSIZE
UnhookWindowsHookEx .hHook
End With
End If
MsgBoxHookProc = False
#End If
End Function #If Win64 And VBA7 Then
'Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As Long) As LongPtr
Public Function MsgBoxEx(MsgTxt As String, Titel As String, _
Optional sButtons As String = "OK", _
Optional vbIcon As Long, Optional bParent As Boolean, _
Optional ByVal x As Long, Optional ByVal y As Long) As String
'Funktion gibt den Text zum gedrückten Button zurück
With Msg
If x > 0 And y > 0 Then .x = x: .y = y
If sButtons = "" Then
Select Case (vbIcon And &H7)
Case 0:  sButtons = "&Ok"
Case 1:  sButtons = "&Ok,A&bbrechen"
Case 2:  sButtons = "A&bbrechen,&Wiederholen,&Ignorieren"
Case 3:  sButtons = "&Ja,&Nein,A&bbrechen"
Case 4:  sButtons = "&Ja,&Nein"
Case 5:  sButtons = "&Wiederholen,A&bbrechen"
End Select
End If
.sBtns = Split(sButtons & ",,", ",")
.vbDlgStyle = (vbIcon And &HFFFF8)
.vbBtnStyle = UBound(.sBtns()) - 4
If bParent Then
.hwndOwner = GetDesktopWindow() 'MsgBox unabhängig von Excel
Else
.hwndOwner = Application.hWnd   'MsgBox an Excel gebunden
End If
.hHook = SetWindowsHookEx(5, AddressOf MsgBoxHookProc, _
GetWindowLongPtr(Application.hWnd, -6), GetCurrentThreadId())
Select Case MessageBox(.hwndOwner, Replace(MsgTxt, "¶", vbLf), Titel, .vbBtnStyle Or . _
vbDlgStyle)
Case 1, 6, 3: x = 0 'vbOk, vbYes,   vbAbort
Case 7, 4, 2: x = 1 'vbNo, vbRetry, vkCancel
Case 5:       x = 2 'vbIgnore
End Select
MsgBoxEx = Replace(.sBtns(x), "&", "")
End With
#Else

Public Function MsgBoxEx(MsgTxt As String, sTitle As String, _
Optional sButtons As String = "OK", _
Optional vbIcon As Long, Optional bParent As Boolean, _
Optional ByVal x As Long, Optional ByVal y As Long) As String
'Funktion gibt den Text zum gedrückten Button zurück
With Msg
.x = x: .y = y
If sButtons = "" Then
Select Case (vbIcon And &H7)
Case 0:  sButtons = "&Ok"
Case 1:  sButtons = "&Ok,A&bbrechen"
Case 2:  sButtons = "A&bbrechen,&Wiederholen,&Ignorieren"
Case 3:  sButtons = "&Ja,&Nein,A&bbrechen"
Case 4:  sButtons = "&Ja,&Nein"
Case 5:  sButtons = "&Wiederholen,A&bbrechen"
End Select
End If
.sBtns = Split(sButtons & ",,", ",")
.vbDlgStyle = (vbIcon And &HFFFF8)
.vbBtnStyle = UBound(.sBtns()) - 2
If bParent Then
.hwndOwner = GetDesktopWindow() 'MsgBox unabhängig von Excel
Else
.hwndOwner = Application.hWnd   'MsgBox an Excel gebunden
End If
.hHook = SetWindowsHookEx(5, AddressOf MsgBoxHookProc, _
GetWindowLong(Application.hWnd, -6), GetCurrentThreadId())
Select Case MessageBox(.hwndOwner, Replace(MsgTxt, "¶", vbLf), sTitle, .vbBtnStyle Or . _
vbDlgStyle)
Case 1, 6, 3: x = 0 'vbOk, vbYes,   vbAbort
Case 7, 4, 2: x = 1 'vbNo, vbRetry, vkCancel
Case 5:       x = 2 'vbIgnore
End Select
MsgBoxEx = Replace(.sBtns(x), "&", "")
End With
#End If
End Function
'Diese Sub ist zum Testen
'Es können 1,2 oder 3 Button angezeigt werden => Kommagetrennt angeben
'& vor einem Buchtabn stellt den Shortcuttaste dar
'¶ stellt einen Zeilenumbruch dar
'Zurückgegeben wird keine Nummer sondern der Buttontext des geklickten Buttons
Sub MeinMsgBoxTest()
Dim pt As POINTAPI
GetCursorPos pt
MsgBox MsgBoxEx("Habe die Datei nicht gefunden,¶Mail trotzdem absenden?", "Mailversand", _
"&Senden,Er&neut,A&bbrechen", vbCritical Or vbMsgBoxSetForeground, True, pt.x, pt.y)
End Sub

mfg thomas
Anzeige
AW: mist bekomme es doch nicht hin
11.01.2020 12:21:20
Thomas
Hallo volti,
mist, ich habe mir schon gedacht das es nur so etwas sein kann.
Jetzt läuft es perfekt.
Kannst du mir noch die Stellschraube zeigen wenn ich 5 Button haben möchte?
Hab schon mal recht vielen dank für deine Hilfe und vor allem auch Ausdauer.
https://www.herber.de/bbs/user/134320.xlsm
Option Explicit
#If Win64 And VBA7 Then
Private Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hWnd As LongPtr, _
ByVal hWndInsertAfter As LongPtr, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Declare PtrSafe Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" ( _
ByVal hDlg As LongPtr, ByVal nIDDlgItem As Long, ByVal lpString As String) As Long
Private Declare PtrSafe Function GetCurrentThreadId Lib "kernel32" () As Long
Private Declare PtrSafe Function GetDesktopWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Function MessageBox Lib "user32" Alias "MessageBoxA" ( _
ByVal hWnd As LongPtr, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Long) As Long
Private Declare PtrSafe Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" ( _
ByVal idHook As Long, ByVal lpfn As LongPtr, ByVal hmod As LongPtr, ByVal dwThreadId As Long) As LongPtr
Private Declare PtrSafe Function UnhookWindowsHookEx Lib "user32" (ByVal hhk As LongPtr) As Long
Private Declare PtrSafe Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongPtrA" ( _
ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr
Private Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As LongPtr
Type MSGBOX_STRUCT
hHook As LongPtr
hwndOwner As LongPtr
vbBtnStyle As Integer
vbDlgStyle As Long
x As Long
y As Long
sBtns() As String
End Type
#Else
Private 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
Private Declare Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" ( _
ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal lpString As String) As Long
Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function MessageBox Lib "user32" Alias "MessageBoxA" ( _
ByVal hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, _
ByVal wType As Long) As Long
Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" ( _
ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" ( _
ByVal hhk As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" ( _
ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Type MSGBOX_STRUCT
hHook As Long
hwndOwner As Long
vbBtnStyle As Integer
vbDlgStyle As Long
x As Long
y As Long
sBtns() As String
End Type
#End If
Type POINTAPI
x As Long
y As Long
End Type
Private Const HWND_TOPMOST = -1
Dim Msg As MSGBOX_STRUCT
#If Win64 And VBA7 Then
Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As Long) As LongPtr
'Funktion versieht die Buttons mit neuen Texten
'Je nach Anzahl gewünschter Buttons wird eine MSGBOX mit passendem Style aufgemacht
'Schalter: vbMsgBoxSetForeground, vbSystemModal, vbMsgBoxHelpButton, vbDefaultButton1,2,3,4
If uMsg = 5 Then
With Msg
If .vbDlgStyle >= vbMsgBoxSetForeground Then _
SetWindowPos wParam, HWND_TOPMOST, 0, 0, 0, 0, &H3 '&H3=SWP_NOMOVE Or SWP_NOSIZE
SetDlgItemText wParam, 1, .sBtns(0)
SetDlgItemText wParam, 2, .sBtns(1)
SetDlgItemText wParam, 3, .sBtns(0)
SetDlgItemText wParam, 4, .sBtns(1)
SetDlgItemText wParam, 5, .sBtns(2)
If .x > 0 And .y > 0 Then _
SetWindowPos wParam, 0, .x, .y, 0, 0, &H1 '&H1=SWP_NOSIZE
UnhookWindowsHookEx .hHook
End With
End If
MsgBoxHookProc = False
#Else
Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'Funktion versieht die Buttons mit neuen Texten
'Je nach Anzahl gewünschter Buttons wird eine MSGBOX mit passendem Style aufgemacht
'Schalter: vbMsgBoxSetForeground, vbSystemModal, vbMsgBoxHelpButton, vbDefaultButton1,2,3,4
If uMsg = 5 Then
With Msg
If .vbDlgStyle >= vbMsgBoxSetForeground Then _
SetWindowPos wParam, HWND_TOPMOST, 0, 0, 0, 0, &H3 '&H3=SWP_NOMOVE Or SWP_NOSIZE
SetDlgItemText wParam, 1, .sBtns(0)
SetDlgItemText wParam, 2, .sBtns(1)
SetDlgItemText wParam, 3, .sBtns(0)
SetDlgItemText wParam, 4, .sBtns(1)
SetDlgItemText wParam, 5, .sBtns(2)
If .x > 0 And .y > 0 Then _
SetWindowPos wParam, 0, .x, .y, 0, 0, &H1 '&H1=SWP_NOSIZE
UnhookWindowsHookEx .hHook
End With
End If
MsgBoxHookProc = False
#End If
End Function #If Win64 And VBA7 Then
'Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As Long) As LongPtr
Public Function MsgBoxEx(MsgTxt As String, Titel As String, _
Optional sButtons As String = "OK", _
Optional vbIcon As Long, Optional bParent As Boolean, _
Optional ByVal x As Long, Optional ByVal y As Long) As String
'Funktion gibt den Text zum gedrückten Button zurück
With Msg
If x > 0 And y > 0 Then .x = x: .y = y
If sButtons = "" Then
Select Case (vbIcon And &H7)
Case 0:  sButtons = "&Ok"
Case 1:  sButtons = "&Ok,A&bbrechen"
Case 2:  sButtons = "A&bbrechen,&Wiederholen,&Ignorieren"
Case 3:  sButtons = "&Ja,&Nein,A&bbrechen"
Case 4:  sButtons = "&Ja,&Nein"
Case 5:  sButtons = "&Wiederholen,A&bbrechen"
End Select
End If
.sBtns = Split(sButtons & ",,", ",")
.vbDlgStyle = (vbIcon And &HFFFF8)
.vbBtnStyle = UBound(.sBtns()) - 4
If bParent Then
.hwndOwner = GetDesktopWindow() 'MsgBox unabhängig von Excel
Else
.hwndOwner = Application.hWnd   'MsgBox an Excel gebunden
End If
.hHook = SetWindowsHookEx(5, AddressOf MsgBoxHookProc, _
GetWindowLongPtr(Application.hWnd, -6), GetCurrentThreadId())
Select Case MessageBox(.hwndOwner, Replace(MsgTxt, "¶", vbLf), Titel, .vbBtnStyle Or . _
vbDlgStyle)
Case 1, 6, 3: x = 0 'vbOk, vbYes,   vbAbort
Case 7, 4, 2: x = 1 'vbNo, vbRetry, vkCancel
Case 5:       x = 2 'vbIgnore
End Select
MsgBoxEx = Replace(.sBtns(x), "&", "")
End With
#Else

Public Function MsgBoxEx(MsgTxt As String, sTitle As String, _
Optional sButtons As String = "OK", _
Optional vbIcon As Long, Optional bParent As Boolean, _
Optional ByVal x As Long, Optional ByVal y As Long) As String
'Funktion gibt den Text zum gedrückten Button zurück
With Msg
.x = x: .y = y
If sButtons = "" Then
Select Case (vbIcon And &H7)
Case 0:  sButtons = "&Ok"
Case 1:  sButtons = "&Ok,A&bbrechen"
Case 2:  sButtons = "A&bbrechen,&Wiederholen,&Ignorieren"
Case 3:  sButtons = "&Ja,&Nein,A&bbrechen"
Case 4:  sButtons = "&Ja,&Nein"
Case 5:  sButtons = "&Wiederholen,A&bbrechen"
End Select
End If
.sBtns = Split(sButtons & ",,", ",")
.vbDlgStyle = (vbIcon And &HFFFF8)
.vbBtnStyle = UBound(.sBtns()) - 2
If bParent Then
.hwndOwner = GetDesktopWindow() 'MsgBox unabhängig von Excel
Else
.hwndOwner = Application.hWnd   'MsgBox an Excel gebunden
End If
.hHook = SetWindowsHookEx(5, AddressOf MsgBoxHookProc, _
GetWindowLong(Application.hWnd, -6), GetCurrentThreadId())
Select Case MessageBox(.hwndOwner, Replace(MsgTxt, "¶", vbLf), sTitle, .vbBtnStyle Or . _
vbDlgStyle)
Case 1, 6, 3: x = 0 'vbOk, vbYes,   vbAbort
Case 7, 4, 2: x = 1 'vbNo, vbRetry, vkCancel
Case 5:       x = 2 'vbIgnore
End Select
MsgBoxEx = Replace(.sBtns(x), "&", "")
End With
#End If
End Function
'Diese Sub ist zum Testen
'Es können 1,2 oder 3 Button angezeigt werden => Kommagetrennt angeben
'& vor einem Buchtabn stellt den Shortcuttaste dar
'¶ stellt einen Zeilenumbruch dar
'Zurückgegeben wird keine Nummer sondern der Buttontext des geklickten Buttons
Sub MeinMsgBoxTest()
Dim pt As POINTAPI
GetCursorPos pt
MsgBox MsgBoxEx("Habe die Datei nicht gefunden,¶Mail trotzdem absenden?", "Mailversand", _
"&Senden,Er&neut,A&bbrechen", vbCritical Or vbMsgBoxSetForeground, True, pt.x, pt.y)
End Sub

mfg thomas
Anzeige
AW: mist bekomme es doch nicht hin
12.01.2020 00:10:42
volti
Hallo Thomas,
wie war das mit dem kleinen Finger... ?
Aber Spaß beiseite, anliegend findest Du eine optimierte Version für MsgboxEx für 32- und 64-Bit.
Da die Standard-Messagebox aus Windows verwendet wird, sind hier auch nur drei Buttons vorgesehen, auch wenn hier der code fünf Buttons vorgaukelt.
Möglicherweise sind in der Messagebox tatsächlich fünf Buttons vorhanden, die sich ggf. gegenseitig überlagern, aber das entzieht sich meiner Kenntnis.
Um diese evtl. sichtbar zu machen, bedarf es umfangreichen weiteren Codes, Resizing der Messagebox an sich und weiteres mehr. Das erscheint mir des Aufwandes wegen nicht angemessen.
Also Fazit: Fünf Buttons geht nicht.
Hallo Thomas,
wie war das mit dem kleinen Finger... ?
Aber Spass beiseite, anliegend findest Du eine optimierte Version für MsgboxEx für 32- und 64-Bit.
Da die Standard-Messagebox aus Windows verwendet wird, sind hier auch nur drei Buttons vorgesehen, auch wenn hier der code fünf Buttons vorgaukelt.
Möglicherweise sind in der Messagebox tatsächlich fünf Buttons vorhanden, die sich ggf. gegenseitig überlagern, aber das entzieht sich meiner Kenntnis.
Um diese evtl. sichtbar zu machen, bedarf es umfangreichen weiteren Codes, Resizing der Messagebox an sich und weiteres mehr. Das erscheint mir des Aufwandes wegen nicht angemessen.
Also Fazit: Fünf Buttons geht nicht.
'Userdefined MsgBox 11.01.2020 by KHV
Option Explicit
#If VBA7 Then
 Private Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hwnd As LongPtr, _
         ByVal hWndInsertAfter As LongPtr, ByVal x As Long, ByVal y As Long, _
         ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
 Private Declare PtrSafe Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" ( _
         ByVal hDlg As LongPtr, ByVal nIDDlgItem As Long, ByVal lpString As String) As Long
 Private Declare PtrSafe Function GetCurrentThreadId Lib "kernel32" () As Long
 Private Declare PtrSafe Function GetDesktopWindow Lib "user32" () As LongPtr
 Private Declare PtrSafe Function MessageBox Lib "user32" Alias "MessageBoxA" ( _
         ByVal hwnd As LongPtr, ByVal lpText As String, ByVal lpCaption As String, _
         ByVal wType As Long) As Long
 Private Declare PtrSafe Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" ( _
         ByVal idHook As Long, ByVal lpfn As LongPtr, ByVal hmod As LongPtr, _
         ByVal dwThreadId As Long) As LongPtr
 Private Declare PtrSafe Function UnhookWindowsHookEx Lib "user32" ( _
         ByVal hhk As LongPtr) As Long
 Private Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongPtrA" ( _
         ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr
 Private Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
 Private Declare PtrSafe Function GetWindowRect Lib "user32" ( _
         ByVal hwnd As LongPtr, lpRect As RECT) As Long
 Private Declare PtrSafe Function GetSystemMetrics Lib "user32" ( _
         ByVal nIndex As Long) As Long
 Type MSGBOX_STRUCT
   hHook      As LongPtr
   hwndOwner  As LongPtr
   vbBtnStyle As Integer
   vbDlgStyle As Long
   x          As Long
   y          As Long
   sBtns()    As String
 End Type
#Else
 Private 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
 Private Declare Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" ( _
         ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal lpString As String) As Long
 Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
 Private Declare Function GetDesktopWindow Lib "user32" () As Long
 Private Declare Function MessageBox Lib "user32" Alias "MessageBoxA" ( _
         ByVal hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, _
         ByVal wType As Long) As Long
 Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" ( _
         ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, _
         ByVal dwThreadId As Long) As Long
 Private Declare Function UnhookWindowsHookEx Lib "user32" ( _
         ByVal hhk As Long) As Long
 Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" ( _
         ByVal hWnd As Long, ByVal nIndex As Long) As Long
 Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
 Private Declare Function GetSystemMetrics Lib "user32" ( _
         ByVal nIndex As Long) As Long
 Private Declare Function GetWindowRect Lib "user32" ( _
         ByVal hwnd As Long, lpRect As RECT) As Long
 Type MSGBOX_STRUCT
   hHook      As Long
   hwndOwner  As Long
   vbBtnStyle As Integer
   vbDlgStyle As Long
   x          As Long
   y          As Long
   sBtns()    As String
 End Type
#End If
Type RECT
  Left As Long
  Top As Long
  Right As Long
  Bottom As Long
End Type
Type POINTAPI
  x As Long
  y As Long
End Type
Private Const SM_CXSCREEN = 0
Private Const SM_CYSCREEN = 1
Private Const HWND_TOPMOST = -1
Dim tMsg As MSGBOX_STRUCT
#If VBA7 Then
Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As Long) As LongPtr
#Else
Function MsgBoxHookProc(ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
#End If
 Dim tRect As RECT, lPos As Long
'Funktion versieht die Buttons mit neuen Texten
'Je nach Anzahl gewünschter Buttons wird eine MsgBox mit passendem Style aufgemacht
'Schalter: vbMsgBoxSetForeground, vbSystemModal, vbMsgBoxHelpButton, vbDefaultButton1,2,3,4
 If uMsg = 5 Then
   With tMsg
    If .vbDlgStyle &GT;= vbMsgBoxSetForeground Then _
    SetWindowPos wParam, HWND_TOPMOST, 0, 0, 0, 0, &H3 '&H3=SWP_NOMOVE Or SWP_NOSIZE
    SetDlgItemText wParam, 1, .sBtns(0)
    SetDlgItemText wParam, 2, .sBtns(1)
    SetDlgItemText wParam, 3, .sBtns(0)
    SetDlgItemText wParam, 4, .sBtns(1)
    SetDlgItemText wParam, 5, .sBtns(2)
    If .x &GT; 0 And .y &GT; 0 Then
     GetWindowRect wParam, tRect
     lPos = GetSystemMetrics(SM_CXSCREEN) - (tRect.Right - tRect.Left)
     If .x &GT; lPos Then .x = lPos
     lPos = GetSystemMetrics(SM_CYSCREEN) - (tRect.Bottom - tRect.Top)
     If .y &GT; lPos Then .y = lPos
     SetWindowPos wParam, 0, .x, .y, 0, 0, &H1 '&H1=SWP_NOSIZE
    End If
    UnhookWindowsHookEx .hHook
   End With
 End If
 MsgBoxHookProc = False
End Function
Public Function MsgBoxEx(MsgTxt As String, sTitle As String, _
       Optional sButtons As String = "OK", _
       Optional vbIcon As Long, Optional bParent As Boolean, _
       Optional ByVal x As Long, Optional ByVal y As Long) As String
'Funktion gibt den Text zum gedrückten Button zurück
 With tMsg
  .x = x: .y = y
  If sButtons = "" Then
   Select Case (vbIcon And &H7)
   Case 0:  sButtons = "&Ok"
   Case 1:  sButtons = "&Ok,A&bbrechen"
   Case 2:  sButtons = "A&bbrechen,&Wiederholen,&Ignorieren"
   Case 3:  sButtons = "&Ja,&Nein,A&bbrechen"
   Case 4:  sButtons = "&Ja,&Nein"
   Case 5:  sButtons = "&Wiederholen,A&bbrechen"
   End Select
  End If
  .sBtns = Split(sButtons & ",,", ",")
  .vbDlgStyle = (vbIcon And &HFFFF8)
  .vbBtnStyle = UBound(.sBtns()) - 2
  If bParent Then
     .hwndOwner = GetDesktopWindow() 'MsgBox unabhängig von Excel
  Else
     .hwndOwner = Application.hwnd   'MsgBox an Excel gebunden
  End If
  .hHook = SetWindowsHookEx(5, AddressOf MsgBoxHookProc, _
           GetWindowLong(Application.hwnd, -6), GetCurrentThreadId())
  Select Case MessageBox(.hwndOwner, Replace(MsgTxt, "¶", vbLf), sTitle, .vbBtnStyle Or .vbDlgStyle)
  Case vbOK, vbYes, vbAbort:    x = 0
  Case vbNo, vbRetry, vbCancel: x = 1
  Case vbIgnore:                x = 2
  End Select
  MsgBoxEx = Replace(.sBtns(x), "&", "")
 End With
End Function
'Diese Sub's sind zum Testen
'Es können 1,2 oder 3 Buttons angezeigt werden =&GT; kommagetrennt angeben
'Wenn keine angegeben sind, werdne die Originaltext (deutsch) laut Style-Vorgabe verwendet
'& vor einem Buchstaben stellt die Shortcuttaste dar z.B. Alt-S usw.
'¶ stellt einen Zeilenumbruch dar (vbLf)
'Die beiden letzten optionalen Parameter sind für die Positionierung der MsgBox
'Zurückgegeben wird keine Nummer, sondern der Buttontext des geklickten Buttons
Sub MeinMsgBoxTest1()
  Dim pt As POINTAPI
  GetCursorPos pt
  MsgBox MsgBoxEx("Habe die Datei nicht gefunden,¶Mail trotzdem absenden?", "Mailversand", _
           "&Senden,Er&neut,A&bbrechen", vbCritical Or vbMsgBoxSetForeground, True, pt.x, pt.y)
End Sub
Sub MeinMsgBoxTest2()
 Select Case MsgBoxEx("Bitte wähle eine Option aus!", "Auswahl", _
            "Option &1,Option &2,Option &3", vbQuestion)
 Case "Option 1": MsgBox "Option 1 gewählt"
 Case "Option 2": MsgBox "Option 2 gewählt"
 Case "Option 3": MsgBox "Option 3 gewählt"
 End Select
End Sub
Sub MeinMsgBoxTest3()
  MsgBox MsgBoxEx("Hello World!", "MeineMsgbox")
End Sub

viele Grüße
Karl-Heinz

Anzeige
riesen dank an volti
12.01.2020 10:25:23
Thomas
Hallo volti,
ich weiß was du sagen wolltest " kleiner Finger ".
Ich dachte das dies vielleicht nicht so Aufwendig ist, da im Code 5 Button stehen.
Sorry.
Hab vielen vielen dank für deinen neuen Code. Nun kann ich diesen optimal einsetzen.
Ich mach mir auch gleich an die Arbeit um ihn in meinem Projekt einzubauen.
Ich wünsche dir noch einen ruhigen Sonntag.
Und sorry für den " kleinen Finger"
mfg thomas
Anzeige
;

Forumthreads zu verwandten Themen

Anzeige
Anzeige
Anzeige
Anzeige

Infobox / Tutorial

Anpassung von VBA MsgBox-Buttons in Excel


Schritt-für-Schritt-Anleitung

Um die Beschriftung der Buttons in einer VBA MsgBox anzupassen, kannst du die Standard-MessageBox nicht direkt verwenden. Stattdessen kannst du eine benutzerdefinierte MsgBox mit einer Userform erstellen oder die Windows-API nutzen. Hier ist eine Schritt-für-Schritt-Anleitung zur Verwendung der Windows-API:

  1. Erstelle ein neues Modul:

    • Gehe zu Excel, öffne den VBA-Editor (Alt + F11).
    • Füge ein neues Modul hinzu (Einfügen > Modul).
  2. Füge den folgenden Code ein:

    Option Explicit
    
    Private Declare PtrSafe Function MessageBox Lib "user32" Alias "MessageBoxA" ( _
       ByVal hWnd As LongPtr, _
       ByVal lpText As String, _
       ByVal lpCaption As String, _
       ByVal wType As Long) As Long
    
    Public Function MsgBoxEx(MsgTxt As String, sTitle As String, _
       Optional sButtons As String = "OK", _
       Optional vbIcon As Long, Optional bParent As Boolean) As String
    
       Dim Msg As MSGBOX_STRUCT
       ' Logik für die Button-Beschriftung
       If sButtons = "" Then
           sButtons = "&Ok"
       End If
       Msg.sBtns = Split(sButtons, ",")
       Msg.vbBtnStyle = UBound(Msg.sBtns()) + 1
    
       MsgBoxEx = Msg.sBtns(0) ' Beispiel: Rückgabe des ersten Buttontextes
    End Function
  3. Rufe die Funktion auf:

    Sub TestMsgBox()
       MsgBox MsgBoxEx("Möchtest du fortfahren?", "Bestätigung", "Ja, Nein")
    End Sub
  4. Führe die Prozedur TestMsgBox aus, um die benutzerdefinierte MsgBox anzuzeigen.


Häufige Fehler und Lösungen

  • Typenunverträglichkeit: Wenn du auf llngHwnd = FindWindowA(GC_CLASSNAMEMSEXCEL, Application.Caption) stößt, stelle sicher, dass du den richtigen Typ für 64-Bit-Excel verwendest. Verwende LongPtr für 64-Bit und Long für 32-Bit.

  • Fehler bei der Verwendung von API: Überprüfe, ob die Deklarationen der Funktionen korrekt sind und dass du die richtigen Parameter übergibst.


Alternative Methoden

Wenn du die Standard-MessageBox nicht verwenden möchtest, kannst du eine Userform erstellen, um eine benutzerdefinierte MsgBox zu gestalten. Hier ist ein Beispiel:

  1. Erstelle eine Userform mit drei Schaltflächen (Ja, Nein, Abbrechen).
  2. Füge die Logik in die Schaltflächen ein, um die gewünschte Aktion auszuführen.

Praktische Beispiele

Hier sind einige praktische Beispiele zur Verwendung von Excel VBA MsgBox mit benutzerdefinierten Buttons:

  1. MsgBox mit benutzerdefinierten Buttons:

    Sub CustomMsgBox()
       Dim response As String
       response = MsgBoxEx("Möchtest du speichern?", "Speichern", "Ja, Nein, Abbrechen", vbCritical)
       Select Case response
           Case "Ja"
               ' Speichern
           Case "Nein"
               ' Nicht speichern
           Case "Abbrechen"
               ' Abbrechen
       End Select
    End Sub
  2. Mehrere Optionen:

    Sub MultiOptionMsgBox()
       Dim response As String
       response = MsgBoxEx("Wähle eine Option:", "Auswahl", "Option 1, Option 2, Option 3")
       MsgBox "Du hast " & response & " gewählt."
    End Sub

Tipps für Profis

  • Nutze die API-Funktionen, um tiefere Anpassungen an der MsgBox vorzunehmen.
  • Verwende #If VBA7 Then-Bedingungen, um Code für 32-Bit und 64-Bit Excel zu trennen.
  • Halte die Userform designfreundlich; füge ansprechende Farben und Schriftarten hinzu.

FAQ: Häufige Fragen

1. Kann ich die Standard-MessageBox verwenden und die Buttontexte ändern? Nein, die Standard-MessageBox erlaubt keine Änderungen der Buttontexte. Du musst eine benutzerdefinierte Lösung erstellen.

2. Wie kann ich die MsgBox unter dem Mauszeiger positionieren? Du kannst die Position der MsgBox mit der API-Funktion SetWindowPos anpassen und die Mauskoordinaten durch GetCursorPos ermitteln.

3. Gibt es eine Möglichkeit, mehr als drei Buttons in der MsgBox anzuzeigen? Die Standard-MessageBox unterstützt maximal drei Buttons. Um mehr als drei Optionen anzuzeigen, solltest du eine Userform verwenden.

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Entdecke mehr
Finde genau, was du suchst

Die erweiterte Suchfunktion hilft dir, gezielt die besten Antworten zu finden

Suche nach den besten Antworten
Unsere beliebtesten Threads

Entdecke unsere meistgeklickten Beiträge in der Google Suche

Top 100 Threads jetzt ansehen
Anzeige