Option Explicit
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 LOGFONT
lfHeight As Long
lfWidth As Long
lfEscapement As Long
lfOrientation As Long
lfWeight As Long
lfItalic As String * 1
lfUnderline As String * 1
lfStrikeOut As String * 1
lfCharSet As String * 1
lfOutPrecision As String * 1
lfClipPrecision As String * 1
lfQuality As String * 1
lfPitchAndFamily As String * 1
lfFaceName As String * 32
End Type
Private Declare Function CreateFontIndirect Lib "gdi32" _
Alias "CreateFontIndirectA" _
(lpLogFont As LOGFONT) As Long
Private Declare Function GetTextExtentPoint32 Lib "gdi32" _
Alias "GetTextExtentPoint32A" _
(ByVal hdc As Long, _
ByVal lpsz As String, _
ByVal cbString As Long, _
lpSize As POINTAPI) As Long
Private Declare Function GetDC Lib "user32" _
(ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" _
(ByVal hwnd As Long, _
ByVal hdc As Long) As Long
Private Declare Function TextOut Lib "gdi32" _
Alias "TextOutA" _
(ByVal hdc As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal lpString As String, _
ByVal nCount As Long) As Long
Private Declare Function SetBkMode Lib "gdi32" _
(ByVal hdc As Long, _
ByVal nBkMode As Long) As Long
Private Declare Function SelectObject Lib "gdi32" _
(ByVal hdc As Long, _
ByVal hObject As Long) As Long
Private Declare Function GetClientRect Lib "user32.dll" _
(ByVal hwnd As Long, _
ByRef lpRect As RECT) As Long
Private Declare Function FindWindowEx Lib "user32.dll" _
Alias "FindWindowExA" _
(ByVal hWnd1 As Long, _
ByVal hWnd2 As Long, _
ByVal lpsz1 As String, _
ByVal lpsz2 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 CallNextHookEx Lib "user32" _
(ByVal hHook As Long, _
ByVal ncode As Long, _
ByVal wParam As Long, _
lParam As Any) As Long
Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Private Declare Function SetWindowLong Lib "user32" _
Alias "SetWindowLongA" _
(ByVal hwnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
Private 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
Private Declare Function GetClassName Lib "user32" _
Alias "GetClassNameA" _
(ByVal hwnd As Long, _
ByVal lpClassName As String, _
ByVal nMaxCount As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" _
(ByVal hObject As Long) As Long
Private Declare Function ShowWindow Lib "user32.dll" _
(ByVal hwnd As Long, _
ByVal nCmdShow As Long) As Long
Private Declare Function SetTextAlign Lib "gdi32.dll" _
(ByVal hdc As Long, _
ByVal wFlags As Long) As Long
Private Const TA_BASELINE As Long = 24
Private Const GWL_WNDPROC As Long = -4
Private Const WH_CBT As Long = 5
Private Const HCBT_ACTIVATE As Long = 5
Private Const WM_PARENTNOTIFY As Long = &H210
Private Const WM_ACTIVATE As Long = &H6
Private Const WM_PAINT As Long = &HF&
Private lPrevWnd As Long
Private lhHook As Long
Private bHookEnabled As Boolean
Private sBoldPart As String
Private sPrompt As String
Private Sub StartHook()
[COLOR=seagreen][B]'install a cbt hook to monitor for[/B][/COLOR]
[B][COLOR=seagreen] 'the activation of a window.[/COLOR][/B]
If Not bHookEnabled Then
lhHook = SetWindowsHookEx _
(WH_CBT, AddressOf HookProc, 0, GetCurrentThreadId)
bHookEnabled = True
Else
MsgBox "The hook is already set.", vbInformation
End If
End Sub
Private Sub TerminateHook()
[COLOR=seagreen][B]'important to unhook when done![/B][/COLOR]
UnhookWindowsHookEx lhHook
bHookEnabled = False
End Sub
Private Function HookProc _
(ByVal idHook As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
Dim sBuffer As String
Dim lRetVal As Long
[COLOR=seagreen][B]'check if a window has been activated.[/B][/COLOR]
If idHook = HCBT_ACTIVATE Then
[COLOR=seagreen][B]'if so,get it's class name.[/B][/COLOR]
sBuffer = Space(256)
lRetVal = GetClassName(wParam, sBuffer, 256)
[COLOR=seagreen][B]'check if it is a "MsgBox" window that is being activated.[/B][/COLOR]
If Left(sBuffer, lRetVal) = "#32770" Then
[B][COLOR=seagreen]'if so,subclass it to catch the[/COLOR][/B]
[B][COLOR=seagreen] 'WM_ACTIVATE and WM_PAINT msgs.[/COLOR][/B]
lPrevWnd = SetWindowLong _
(wParam, GWL_WNDPROC, AddressOf CallBackProc)
[COLOR=seagreen][B]'done so remove CBT hook.[/B][/COLOR]
Call TerminateHook
End If
End If
[COLOR=seagreen][B]'Call next hook.[/B][/COLOR]
HookProc = CallNextHookEx _
(lhHook, idHook, ByVal wParam, ByVal lParam)
End Function
Private Function CallBackProc _
(ByVal hwnd As Long, ByVal Msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Dim textSize As POINTAPI
Dim tRect As RECT
Dim lDC As Long
Dim lStaticHwnd As Long
On Error Resume Next
[COLOR=seagreen][B]'catch this msg to format the msgbox.[/B][/COLOR]
If Msg = WM_PAINT Or Msg = WM_ACTIVATE Then
[COLOR=seagreen][B]'get the msgbox text window hwnd and store its DC.[/B][/COLOR]
lStaticHwnd = FindWindowEx _
(hwnd, 0, "STATIC", vbNullString)
lDC = GetDC(hwnd)
[COLOR=seagreen][B]'set the background of the msgbox text to transparent.[/B][/COLOR]
SetBkMode lDC, 1
[B][COLOR=seagreen]'set the text-alignment[/COLOR][/B]
SetTextAlign lDC, TA_BASELINE
[COLOR=seagreen][B]'store the text window metrics.[/B][/COLOR]
GetClientRect lStaticHwnd, tRect
[COLOR=seagreen][B]'hide the text window.[/B][/COLOR]
ShowWindow lStaticHwnd, 0
Select Case True
[B][COLOR=seagreen]'if the BoldPart = Prompt.[/COLOR][/B]
Case UCase(sPrompt) = UCase(sBoldPart)
CreateFont lDC, Bold:=True
TextOut lDC, tRect.Left + 10, _
tRect.Bottom + 10, sPrompt, Len(sPrompt)
[COLOR=seagreen][B]'if the BoldPart = N LeftMost characters.[/B][/COLOR]
Case UCase(Left(sPrompt, Len(sBoldPart))) _
= UCase(sBoldPart)
CreateFont lDC, Bold:=True
TextOut lDC, tRect.Left + 10, tRect.Bottom + 10, _
sBoldPart, Len(sBoldPart)
GetTextExtentPoint32 lDC, sBoldPart, _
Len(sBoldPart), textSize
CreateFont lDC
TextOut lDC, textSize.x + tRect.Left + 10, _
tRect.Bottom + 10, _
Right(sPrompt, Len(sPrompt) - Len(sBoldPart)), _
Len(sPrompt) - Len(sBoldPart)
[COLOR=seagreen][B]'if the BoldPart = N RightMost characters.[/B][/COLOR]
Case UCase(Right(sPrompt, Len(sBoldPart))) = _
UCase(sBoldPart)
CreateFont lDC
TextOut lDC, tRect.Left + 10, tRect.Bottom + 10, _
Left(sPrompt, Len(sPrompt) - Len(sBoldPart)), _
Len(Left(sPrompt, Len(sPrompt) - Len(sBoldPart)))
GetTextExtentPoint32 lDC, _
Left(sPrompt, Len(sPrompt) - Len(sBoldPart)), _
Len(Left(sPrompt, Len(sPrompt) - _
Len(sBoldPart))), textSize
CreateFont lDC, Bold:=True
TextOut lDC, textSize.x + tRect.Left + 10, _
tRect.Bottom + 10, (sBoldPart), Len(sBoldPart)
[COLOR=seagreen][B]'if the BoldPart is in the middle of the Prompt text.[/B][/COLOR]
Case InStr(1, sPrompt, sBoldPart, 1) > 1
If UCase(Right(sPrompt, Len(sBoldPart))) <> _
UCase(sBoldPart) Then
CreateFont lDC
TextOut lDC, tRect.Left + 10, tRect.Bottom + 10, _
Left(sPrompt, _
InStr(1, sPrompt, sBoldPart, 1) - 1), _
Len(Left(sPrompt, _
InStr(1, sPrompt, sBoldPart, 1) - 1))
GetTextExtentPoint32 lDC, _
Left(sPrompt, InStr(1, sPrompt, sBoldPart, 1) - 1), _
Len(Left(sPrompt, _
InStr(1, sPrompt, sBoldPart, 1) - 1)), textSize
CreateFont lDC, Bold:=True
TextOut lDC, textSize.x + tRect.Left + 10, _
tRect.Bottom + 10, (sBoldPart), Len(sBoldPart)
GetTextExtentPoint32 lDC, _
Left(sPrompt, InStr(1, sPrompt, sBoldPart, 1) - 1) _
& sBoldPart, Len(Left(sPrompt, _
InStr(1, sPrompt, sBoldPart, 1) - 1)) _
+ Len(sBoldPart) - 1, textSize
CreateFont lDC
TextOut lDC, textSize.x + tRect.Left + 10, _
tRect.Bottom + 10, Right(sPrompt, Len(sPrompt) _
- InStr(1, sPrompt, sBoldPart, 1) _
- Len(sBoldPart) + 1), _
Len(Right(sPrompt, Len(sPrompt) - _
InStr(1, sPrompt, sBoldPart, 1) - _
Len(sBoldPart) + 1))
End If
[COLOR=seagreen][B]'if no bold text.[/B][/COLOR]
Case InStr(1, sPrompt, sBoldPart, 1) = 0
[B][COLOR=seagreen]'display default msgbox text.[/COLOR][/B]
ShowWindow lStaticHwnd, 1
End Select
[COLOR=seagreen][B]'cleanup[/B][/COLOR]
ReleaseDC hwnd, lDC
End If
[COLOR=seagreen][B]'process other msgs.[/B][/COLOR]
CallBackProc = CallWindowProc _
(lPrevWnd, hwnd, Msg, wParam, ByVal lParam)
End Function
Private Sub CreateFont(DC As Long, Optional Bold As Boolean)
Dim uFont As LOGFONT
Dim lNewFont As Long
With uFont
.lfFaceName = "Tahoma" & Chr$(0)
.lfHeight = 13
.lfWidth = 5
.lfWeight = IIf(Bold, 900, 100)
End With
lNewFont = CreateFontIndirect(uFont)
DeleteObject (SelectObject(DC, lNewFont))
End Sub
Private Function FormatMsgBox _
(Prompt As String, Optional BoldPart As String, _
Optional Title As String) As VbMsgBoxResult
[COLOR=seagreen][B]'strore parameters in module level vars.[/B][/COLOR]
sBoldPart = BoldPart
sPrompt = Prompt
[COLOR=seagreen][B]'setup a CBT hook.[/B][/COLOR]
Call StartHook
[COLOR=seagreen][B]'display our custom msgbox.[/B][/COLOR]
MsgBox Prompt:=Prompt, Title:=Title
End Function