Option Explicit
#If Win64 Then
Const NULL_PTR = 0^
Const PTR_SIZE = 8&
#Else
Const NULL_PTR = 0&
Const PTR_SIZE = 4&
#End If
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type BLENDFUNCTION
BlendOp As Byte
BlendFlags As Byte
SourceConstantAlpha As Byte
AlphaFormat As Byte
End Type
#If VBA7 Then
#If Win64 Then
Private Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongPtrA" (ByVal hwnd As LongLong, ByVal nIndex As Long, ByVal dwNewLong As LongLong) As LongLong
#Else
Private Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
#End If
Private Declare PtrSafe Function IUnknown_GetWindow Lib "shlwapi" Alias "#172" (ByVal pIUnk As IUnknown, ByVal hUF As LongPtr) As Long
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hDC As LongPtr) As Long
Private Declare PtrSafe Function DeleteDC Lib "gdi32" (ByVal hDC As LongPtr) As Long
Private Declare PtrSafe Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As LongPtr) As LongPtr
Private Declare PtrSafe Function CreateCompatibleBitmap Lib "gdi32" (ByVal hDC As LongPtr, ByVal nWidth As Long, ByVal nHeight As Long) As LongPtr
Private Declare PtrSafe Function SelectObject Lib "gdi32" (ByVal hDC As LongPtr, ByVal hObject As LongPtr) As LongPtr
Private Declare PtrSafe Function DeleteObject Lib "gdi32" (ByVal hObject As LongPtr) As Long
Private Declare PtrSafe Function AlphaBlend Lib "msimg32.dll" (ByVal hDC As LongPtr, ByVal lInt As Long, ByVal lInt As Long, ByVal lInt As Long, ByVal lInt As Long, ByVal hDC As LongPtr, ByVal lInt As Long, ByVal lInt As Long, ByVal lInt As Long, ByVal lInt As Long, ByVal BLENDFUNCT As LongPtr) As Long
Private Declare PtrSafe Function BitBlt Lib "gdi32" (ByVal hDestDC As LongPtr, ByVal x As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As LongPtr, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr
Private Declare PtrSafe Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As LongPtr, ByVal hwnd As LongPtr, ByVal Msg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
Private Declare PtrSafe Function GetClientRect Lib "user32" (ByVal hwnd As LongPtr, lpRect As RECT) As Long
Private Declare PtrSafe Function SetProp Lib "user32" Alias "SetPropA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal hData As LongPtr) As Long
Private Declare PtrSafe Function GetProp Lib "user32" Alias "GetPropA" (ByVal hwnd As LongPtr, ByVal lpString As String) As LongPtr
Private Declare PtrSafe Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hwnd As LongPtr, ByVal lpString As String) As LongPtr
Private Declare PtrSafe Function IsBadCodePtr Lib "kernel32" (ByVal lpfn As LongPtr) As Long
Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
Private Declare PtrSafe Function CreateRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As LongPtr
Private Declare PtrSafe Function CombineRgn Lib "gdi32" (ByVal hDestRgn As LongPtr, ByVal hSrcRgn1 As LongPtr, ByVal hSrcRgn2 As LongPtr, ByVal nCombineMode As Long) As Long
Private Declare PtrSafe Function ExtSelectClipRgn Lib "gdi32" (ByVal hDC As LongPtr, ByVal hRgn As LongPtr, ByVal fnMode As Long) As Long
Private Declare PtrSafe Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
Private Declare PtrSafe Function RegisterHotKey Lib "user32" (ByVal hwnd As LongPtr, ByVal id As Long, ByVal fsModifiers As Long, ByVal vk As Long) As Long
Private Declare PtrSafe Function UnregisterHotKey Lib "user32" (ByVal hwnd As LongPtr, ByVal id As Long) As Long
Private Declare PtrSafe Function SetTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
Private Declare PtrSafe Function KillTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
#Else
Private Enum LongPtr
[_]
End Enum
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 IUnknown_GetWindow Lib "shlwapi" Alias "#172" (ByVal pIUnk As IUnknown, ByVal hUF As LongPtr) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Private Declare Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hDC As LongPtr) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As LongPtr) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As LongPtr) As LongPtr
Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hDC As LongPtr, ByVal nWidth As Long, ByVal nHeight As Long) As LongPtr
Private Declare Function SelectObject Lib "gdi32" (ByVal hDC As LongPtr, ByVal hObject As LongPtr) As LongPtr
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As LongPtr) As Long
Private Declare Function AlphaBlend Lib "msimg32.dll" (ByVal hDC As LongPtr, ByVal lInt As Long, ByVal lInt As Long, ByVal lInt As Long, ByVal lInt As Long, ByVal hDC As LongPtr, ByVal lInt As Long, ByVal lInt As Long, ByVal lInt As Long, ByVal lInt As Long, ByVal BLENDFUNCT As LongPtr) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As LongPtr, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As LongPtr, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As LongPtr, ByVal hwnd As LongPtr, ByVal Msg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As LongPtr, lpRect As RECT) As Long
Private Declare Function SetProp Lib "user32" Alias "SetPropA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal hData As LongPtr) As Long
Private Declare Function GetProp Lib "user32" Alias "GetPropA" (ByVal hwnd As LongPtr, ByVal lpString As String) As LongPtr
Private Declare Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hwnd As LongPtr, ByVal lpString As String) As LongPtr
Private Declare Function IsBadCodePtr Lib "kernel32" (ByVal lpfn As LongPtr) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetActiveWindow Lib "user32" () As LongPtr
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
Private Declare Function CreateRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As LongPtr
Private Declare Function CombineRgn Lib "gdi32" (ByVal hDestRgn As LongPtr, ByVal hSrcRgn1 As LongPtr, ByVal hSrcRgn2 As LongPtr, ByVal nCombineMode As Long) As Long
Private Declare Function ExtSelectClipRgn Lib "gdi32" (ByVal hDC As LongPtr, ByVal hRgn As LongPtr, ByVal fnMode As Long) As Long
Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
Private Declare Function RegisterHotKey Lib "user32" (ByVal hwnd As LongPtr, ByVal id As Long, ByVal fsModifiers As Long, ByVal vk As Long) As Long
Private Declare Function UnregisterHotKey Lib "user32" (ByVal hwnd As LongPtr, ByVal id As Long) As Long
Private Declare Function SetTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
Private Declare Function KillTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
#End If
Private hwnd As LongPtr, lPrevProc As LongPtr
Private hInitMemDC As LongPtr, hPrevInitBmp As LongPtr
Private hEllipRgn As LongPtr
Private oForm As UserForm
Private lBrightness As Long
Private lInitBrightness As Long
Private bInit As Boolean
Public Sub EnableDim( _
ByVal Form As UserForm, _
ParamArray ExcludedControls() _
)
Const SM_CYCAPTION = 4&
Const SM_CXBORDER = 5&
Const SM_CXDLGFRAME = 7&
Const RGN_OR = 2&
Dim vExcludedControls() As Variant
Dim Ctrl As MSForms.Control, oAcc As IAccessible
Dim lLeft As Long, lTop As Long, lWidth As Long, lHeight As Long
Dim YOffset As Long, UpShift As Long
Dim hRectRgn As LongPtr
bInit = True
Set oForm = Form
Call IUnknown_GetWindow(Form, VarPtr(hwnd))
If UBound(ExcludedControls) <> -1 Then
vExcludedControls = ExcludedControls
End If
hEllipRgn = CreateRectRgn(0&, 0&, 0&, 0&)
YOffset = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CXDLGFRAME)
For Each Ctrl In Form.Controls
If TypeOf Ctrl Is MSForms.TextBox Or _
TypeOf Ctrl Is MSForms.ListBox Or IsControlExcluded(Ctrl, vExcludedControls) Then
Set oAcc = Ctrl
oAcc.accLocation lLeft, lTop, lWidth, lHeight, 0&
If TypeOf Ctrl Is MSForms.ListBox Then
UpShift = 10&
Else
UpShift = 0&
End If
hRectRgn = CreateRectRgn(lLeft - 2&, lTop - YOffset, lLeft + lWidth - 4&, _
lTop + lHeight - YOffset - UpShift)
Call CombineRgn(hEllipRgn, hRectRgn, hEllipRgn, RGN_OR)
Call DeleteObject(hRectRgn)
End If
Next Ctrl
Call DisableUpDownKeys
Call HookForm(hwnd)
Call SetTimer(hwnd, NULL_PTR, 0&, AddressOf TakeFormSnapshot)
Call SetTimer(Application.hwnd, NULL_PTR, 0&, AddressOf TabKeyWatcher)
End Sub
Public Sub DisableDim(ByVal Form As MSForms.UserForm)
Call Cleanup
Call Form.Repaint
End Sub
Public Sub SetBrightness(Optional ByVal Brightness As Long)
Const SRCCOPY = &HCC0020
Const RGN_XOR As Long = 3&
Const AC_SRC_OVER = &H0
Dim hDC As LongPtr, hMemDC As LongPtr, hBmp As LongPtr, hPrevBmp As LongPtr
Dim tBF As BLENDFUNCTION, lBF As LongPtr
Dim tRect As RECT
Dim lWidth As Long, lHeight As Long
If oForm Is Nothing Then Exit Sub
If Brightness < 0& Or Brightness > 255& Then
Call Cleanup
MsgBox "Brightness must be between 0 and 255.", , "Error."
End
Exit Sub
End If
lInitBrightness = Brightness
If bInit Then bInit = False: oForm.Repaint: Exit Sub
lBrightness = Brightness
With tBF
.BlendOp = AC_SRC_OVER
.BlendFlags = 0&
.SourceConstantAlpha = Brightness '<== (0 TO 255)
.AlphaFormat = 0&
End With
Call CopyMemory(lBF, tBF, PTR_SIZE)
hDC = GetDC(hwnd)
Call GetClientRect(hwnd, tRect)
With tRect
lWidth = .Right - .Left
lHeight = .Bottom - .Top
End With
hMemDC = CreateCompatibleDC(hDC)
hBmp = CreateCompatibleBitmap(hDC, lWidth, lHeight)
hPrevBmp = SelectObject(hMemDC, hBmp)
Call ExtSelectClipRgn(hDC, hEllipRgn, RGN_XOR)
Call AlphaBlend(hMemDC, 0&, 0&, lWidth, lHeight, hInitMemDC, 0&, 0&, lWidth, lHeight, lBF)
Call BitBlt(hDC, 0&, 0&, lWidth, lHeight, hMemDC, 0&, 0&, SRCCOPY)
Call SelectObject(hMemDC, hPrevBmp)
Call DeleteObject(hPrevBmp)
Call DeleteObject(hBmp)
Call DeleteDC(hMemDC)
Call ReleaseDC(hwnd, hDC)
End Sub
'_______________________________________ PRIVATE ROUTINES _____________________________________________
Private Sub Cleanup()
Call KillTimer(Application.hwnd, NULL_PTR)
Call HookForm(hwnd, False)
Call DisableUpDownKeys(False)
Call SelectObject(hInitMemDC, hPrevInitBmp)
Call DeleteDC(hInitMemDC)
Call DeleteObject(hPrevInitBmp)
Call DeleteObject(hEllipRgn)
Set oForm = Nothing
lBrightness = 0&
lInitBrightness = 0&
End Sub
Private Sub TakeFormSnapshot()
Const SRCCOPY = &HCC0020
Dim hDC As LongPtr, hInitMemBmp As LongPtr
Dim tRect As RECT
Dim lWidth As Long, lHeight As Long
Call KillTimer(hwnd, NULL_PTR)
Call GetClientRect(hwnd, tRect)
lWidth = tRect.Right - tRect.Left
lHeight = tRect.Bottom - tRect.Top
hDC = GetDC(hwnd)
hInitMemDC = CreateCompatibleDC(hDC)
hInitMemBmp = CreateCompatibleBitmap(hDC, lWidth, lHeight)
hPrevInitBmp = SelectObject(hInitMemDC, hInitMemBmp)
Call BitBlt(hInitMemDC, 0&, 0&, lWidth, lHeight, hDC, 0&, 0&, SRCCOPY)
Call ReleaseDC(hwnd, hDC)
Call DeleteObject(hInitMemBmp)
lBrightness = lInitBrightness
DoEvents
Call SetBrightness(lBrightness)
End Sub
Private Sub HookForm(ByVal hwnd As LongPtr, Optional ByVal bHook As Boolean = True)
Const GWL_WNDPROC = (-4)
If bHook Then
If GetProp(hwnd, "lPrevProc") = 0 Then
lPrevProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WinProc)
Call SetProp(hwnd, "lPrevProc", lPrevProc)
End If
Else
If GetProp(hwnd, "lPrevProc") Then
Call SetWindowLong(hwnd, GWL_WNDPROC, GetProp(hwnd, "lPrevProc"))
Call RemoveProp(hwnd, "lPrevProc")
End If
End If
End Sub
Private Function WinProc( _
ByVal hwnd As LongPtr, _
ByVal uMsg As Long, _
ByVal wParam As LongPtr, _
ByVal lParam As LongPtr _
) As LongPtr
Const WM_ACTIVATE = &H6
Const WM_PARENTNOTIFY = &H210
Const WM_CANCELMODE = &H1F
Const WM_ENTERIDLE = &H121
Const WM_SETREDRAW = &HB
Const WM_ERASEBKGND = &H14
Const WM_MOVE = &H3
Const WM_EXITSIZEMOVE = &H232
Const WM_DESTROY = &H2
Const WM_HOTKEY = &H312
Static bCaptureChanged As Boolean
Dim hwndCtrl As LongPtr
If lBrightness = 0& Then GoTo Xit
If GetAsyncKeyState(VBA.vbKeyLButton) = 0& Then
If bCaptureChanged Then
bCaptureChanged = False
Call SetTimer(hwnd, NULL_PTR, 0&, AddressOf TimerProc)
End If
End If
Select Case uMsg
Case WM_CANCELMODE, WM_ENTERIDLE
If Is_Error Then
Debug.Print "Error trapped!!"
Call Cleanup: Exit Function
End If
Case WM_ACTIVATE, WM_HOTKEY
Call SetTimer(hwnd, NULL_PTR, 0&, AddressOf TimerProc)
Case WM_PARENTNOTIFY
bCaptureChanged = True
Call SetTimer(hwnd, NULL_PTR, 0&, AddressOf TimerProc)
Case WM_MOVE, WM_ERASEBKGND
Call SendMessage(hwnd, ByVal WM_SETREDRAW, 0&, 0&)
Case WM_EXITSIZEMOVE
Call SendMessage(hwnd, ByVal WM_SETREDRAW, 1&, 0&)
oForm.Repaint
Call SetTimer(hwnd, NULL_PTR, 0&, AddressOf TimerProc)
Case WM_DESTROY
bCaptureChanged = False
Call Cleanup
Exit Function
End Select
Xit:
WinProc = CallWindowProc(GetProp(hwnd, "lPrevProc"), hwnd, uMsg, wParam, lParam)
End Function
Private Sub TimerProc()
Call KillTimer(hwnd, NULL_PTR)
Call SetBrightness(lBrightness)
End Sub
Private Function Is_Error() As Boolean
Dim sBuffer As String * 256, lRet As Long
lRet = GetWindowText(GetActiveWindow, sBuffer, 256)
If InStr(Left(sBuffer, lRet), "Visual Basic") Then Is_Error = True
End Function
Private Function IsControlExcluded(ByVal Ctrl As Control, vExcluded() As Variant) As Boolean
Dim vCtrl As Variant
If Not (Not vExcluded) Then
For Each vCtrl In vExcluded
If vCtrl Is Ctrl Then
IsControlExcluded = True
Exit Function
End If
Next vCtrl
End If
End Function
Private Function IsControlKeyboardInteractive(Ctrl As Control) As Boolean
On Error Resume Next
If TypeOf Ctrl Is MSForms.ListBox Or TypeOf Ctrl Is MSForms.ComboBox _
Or TypeOf Ctrl Is MSForms.TextBox Then
IsControlKeyboardInteractive = True
End If
End Function
Private Sub TabKeyWatcher()
Static oPrev As Control
If oForm.ActiveControl Is oPrev Then
Call SetTimer(hwnd, NULL_PTR, 0&, AddressOf TimerProc)
End If
Set oPrev = oForm.ActiveControl
End Sub
Private Sub DisableUpDownKeys(Optional ByVal bDisbale As Boolean = True)
If bDisbale Then
Call RegisterHotKey(hwnd, 1&, 0&, vbKeyUp)
Call RegisterHotKey(hwnd, 2&, 0&, vbKeyDown)
Else
Call UnregisterHotKey(hwnd, 1&)
Call UnregisterHotKey(hwnd, 2&)
End If
End Sub