' (C) Dan Elgaard (www.EXCELGAARD.dk)
' MsgBox Buttons/Answers ID Constants
Private Const MsgBox_Button_ID_OK As Long = 1
Private Const MsgBox_Button_ID_Cancel As Long = 2
Private Const MsgBox_Button_ID_Abort As Long = 3
Private Const MsgBox_Button_ID_Retry As Long = 4
Private Const MsgBox_Button_ID_Ignore As Long = 5
Private Const MsgBox_Button_ID_Yes As Long = 6
Private Const MsgBox_Button_ID_No As Long = 7
' MsgBox Buttons/Answers Text Variables
Private MsgBox_Button_Text_OK As String
Private MsgBox_Button_Text_Cancel As String
Private MsgBox_Button_Text_Abort As String
Private MsgBox_Button_Text_Retry As String
Private MsgBox_Button_Text_Ignore As String
Private MsgBox_Button_Text_Yes As String
Private MsgBox_Button_Text_No As String
' Handle to the Hook procedure
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If"]#If[/URL] VBA7 Then
Private MsgBoxHookHandle As LongPtr ' 64-bit handle
Private MsgBoxHookHandle2 As LongPtr ' 64-bit handle
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else"]#Else[/URL]
Private MsgBoxHookHandle As Long
Private MsgBoxHookHandle2 As Long
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End"]#End[/URL] If
Private Type RECT
Left As Long
Top As Long
right As Long
bottom As Long
End Type
' Windows API functions
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If"]#If[/URL] VBA7 Then
Private Declare PtrSafe Function GetCurrentThreadId Lib "kernel32" () As LongPtr
Private Declare PtrSafe Function SetDlgItemText Lib "user32" Alias "SetDlgItemTextA" (ByVal hDlg As LongPtr, ByVal nIDDlgItem As LongPtr, ByVal lpString As String) As LongPtr
Private Declare PtrSafe Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As LongPtr, ByVal lpfn As LongPtr, ByVal hmod As LongPtr, ByVal dwThreadId As LongPtr) As LongPtr
Private Declare PtrSafe Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As LongPtr) As LongPtr
Private Declare PtrSafe Function GetWindowRect Lib "user32" (ByVal hwnd As LongPtr, lpRect As RECT) As Long
Private Declare PtrSafe Function ClipCursor Lib "user32" (lpRect As Any) As Long
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else"]#Else[/URL]
Private Declare Function GetCurrentThreadId Lib "kernel32" () 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 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 hHook As Long) As Long
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function ClipCursor Lib "user32" (lpRect As Any) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End"]#End[/URL] If
Option Private Module ' To prevent the function(s) from appearing the worksheet list of functions (it's a 'for macros only' function)
Option Explicit
Function MsgBoxCB(MsgBox_Text As String, Button1 As String, Optional Button2 As String, Optional Button3 As String, Optional MsgBox_Icon As Long, Optional MsgBox_Title As String) As Long
' * ' Initialize
On Error Resume Next
' * ' Define variables
If Button1 = vbNullString Then
Button1 = Button2
Button2 = vbNullString
End If
If Button2 = vbNullString Then
Button2 = Button3
Button3 = vbNullString
End If
Dim ButtonsToUse As Long
ButtonsToUse = vbAbortRetryIgnore
If Button3 = vbNullString Then ButtonsToUse = vbYesNo
If Button2 = vbNullString Then ButtonsToUse = vbOKOnly
Select Case MsgBox_Icon
Case vbCritical: ButtonsToUse = ButtonsToUse + MsgBox_Icon
Case vbExclamation: ButtonsToUse = ButtonsToUse + MsgBox_Icon
Case vbInformation: ButtonsToUse = ButtonsToUse + MsgBox_Icon
Case vbQuestion: ButtonsToUse = ButtonsToUse + MsgBox_Icon
End Select
If MsgBox_Title = vbNullString Then MsgBox_Title = " Microsoft Excel" ' Default MsgBox title
Dim MsgBoxAnswer As Long
' * ' Set custom buttons texts
MsgBox_Button_Text_OK = Button1
MsgBox_Button_Text_Cancel = vbNullString ' Not used
MsgBox_Button_Text_Abort = Button1
MsgBox_Button_Text_Retry = Button2
MsgBox_Button_Text_Ignore = Button3
MsgBox_Button_Text_Yes = Button1
MsgBox_Button_Text_No = Button2
MsgBoxHookHandle = SetWindowsHookEx(5, AddressOf MsgBoxHook, 0, GetCurrentThreadId) ' Set MsgBox Hook
' * ' Show hooked MsgBox
MsgBoxAnswer = MsgBox(MsgBox_Text, ButtonsToUse, MsgBox_Title)
EF: ' End of Function
UnhookWindowsHookEx MsgBoxHookHandle ' Unhook MsgBox again
ClipCursor ByVal 0
Select Case MsgBoxAnswer
Case vbOK: MsgBoxCB = 1
Case vbCancel: MsgBoxCB = 0 ' Not used
Case vbAbort: MsgBoxCB = 1
Case vbRetry: MsgBoxCB = 2
Case vbIgnore: MsgBoxCB = 3
Case vbYes: MsgBoxCB = 1
Case vbNo: MsgBoxCB = 2
End Select
End Function
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If"]#If[/URL] VBA7 Then
Private Function MsgBoxHook(ByVal LM As LongPtr, ByVal WP As LongPtr, ByVal LP As LongPtr) As LongPtr
SetDlgItemText WP, MsgBox_Button_ID_OK, MsgBox_Button_Text_OK
SetDlgItemText WP, MsgBox_Button_ID_Cancel, MsgBox_Button_Text_Cancel ' Not used
SetDlgItemText WP, MsgBox_Button_ID_Abort, MsgBox_Button_Text_Abort
SetDlgItemText WP, MsgBox_Button_ID_Retry, MsgBox_Button_Text_Retry
SetDlgItemText WP, MsgBox_Button_ID_Ignore, MsgBox_Button_Text_Ignore
SetDlgItemText WP, MsgBox_Button_ID_Yes, MsgBox_Button_Text_Yes
SetDlgItemText WP, MsgBox_Button_ID_No, MsgBox_Button_Text_No
Dim tMsgBoxRect As RECT, sBuffer As String * 256, ret As Long
ret = GetClassName(WP, sBuffer, Len(sBuffer))
If Left(sBuffer, ret) = "#32770" Then
GetWindowRect WP, tMsgBoxRect
With tMsgBoxRect
.right = .right - 2: .bottom = .bottom - 2
End With
ClipCursor tMsgBoxRect
End If
End Function
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else"]#Else[/URL]
Private Function MsgBoxHook(ByVal LM As Long, ByVal WP As Long, ByVal LP As Long) As Long
SetDlgItemText WP, MsgBox_Button_ID_OK, MsgBox_Button_Text_OK
SetDlgItemText WP, MsgBox_Button_ID_Cancel, MsgBox_Button_Text_Cancel ' Not used
SetDlgItemText WP, MsgBox_Button_ID_Abort, MsgBox_Button_Text_Abort
SetDlgItemText WP, MsgBox_Button_ID_Retry, MsgBox_Button_Text_Retry
SetDlgItemText WP, MsgBox_Button_ID_Ignore, MsgBox_Button_Text_Ignore
SetDlgItemText WP, MsgBox_Button_ID_Yes, MsgBox_Button_Text_Yes
SetDlgItemText WP, MsgBox_Button_ID_No, MsgBox_Button_Text_No
Dim tMsgBoxRect As RECT, sBuffer As String * 256, ret As Long
ret = GetClassName(WP, sBuffer, Len(sBuffer))
If Left(sBuffer, ret) = "#32770" Then
GetWindowRect WP, tMsgBoxRect
With tMsgBoxRect
.right = .right - 2: .bottom = .bottom - 2
End With
ClipCursor tMsgBoxRect
End If
End Function
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End"]#End[/URL] If
Public Property Let MsgboxClipCursor(ByVal Clip As Boolean)
If Clip Then
MsgBoxHookHandle2 = SetWindowsHookEx(5, AddressOf MsgBoxClipProc, 0, GetCurrentThreadId)
Else
ClipCursor ByVal 0
UnhookWindowsHookEx MsgBoxHookHandle2
End If
End Property
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If"]#If[/URL] VBA7 Then
Private Function MsgBoxClipProc(ByVal LM As LongPtr, ByVal WP As LongPtr, ByVal LP As LongPtr) As LongPtr
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else"]#Else[/URL]
Private Function MsgBoxClipProc(ByVal LM As Long, ByVal WP As Long, ByVal LP As Long) As Long
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End"]#End[/URL] If
Dim tMsgBoxRect As RECT, sBuffer As String * 256, ret As Long
ret = GetClassName(WP, sBuffer, Len(sBuffer))
If Left(sBuffer, ret) = "#32770" Then
GetWindowRect WP, tMsgBoxRect
With tMsgBoxRect
.right = .right - 2: .bottom = .bottom - 2
End With
ClipCursor tMsgBoxRect
End If
End Function