Option Explicit
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 CallNextHookEx Lib "user32" _
(ByVal hHook As Long, _
ByVal nCode As Long, _
ByVal wParam As Long, _
lParam As Any) As Long
Public Declare Function UnhookWindowsHookEx Lib "user32" _
(ByVal hHook As Long) As Long
Private Declare Function GetCurrentThreadId Lib "kernel32" _
() As Long
Private Declare Function GetClassName Lib "user32.dll" _
Alias "GetClassNameA" _
(ByVal hwnd As Long, _
ByVal lpClassName As String, _
ByVal nMaxCount As Long) As Long
Private Declare Function SetProp Lib "user32" Alias "SetPropA" _
(ByVal hwnd As Long, _
ByVal lpString As String, _
ByVal hData As Long) As Long
Private Declare Function RemoveProp Lib "user32" Alias "RemovePropA" _
(ByVal hwnd As Long, _
ByVal lpString As String) As Long
Private Declare Function GetProp Lib "user32" Alias "GetPropA" _
(ByVal hwnd As Long, _
ByVal lpString As String) As Long
Private Const WH_CBT As Long = 5
Private Const HCBT_CREATEWND As Long = 3
Private Const HCBT_DESTROYWND As Long = 4
'====================
'Public Routines.
'=====================
Public Sub StartWatching(ByVal Sh As Worksheet)
If GetProp(Application.hwnd, "hookHandle") Then Exit Sub
Names.Add "DV_Sheet", Sh.Name
SetProp Application.hwnd, "hookHandle", _
SetWindowsHookEx(WH_CBT, AddressOf CBTProc, 0, GetCurrentThreadId)
End Sub
Public Sub StopWatching()
On Error Resume Next
UnhookWindowsHookEx GetProp(Application.hwnd, "hookHandle")
RemoveProp Application.hwnd, "hookHandle"
Names("DV_Sheet").Delete
End Sub
'====================
'Private Routines.
'=====================
Private Function CBTProc _
(ByVal idHook As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
Select Case idHook
'/Was a window created ?
Case Is = HCBT_CREATEWND
If IsXlValDropDown(wParam) Then
If Worksheets([DV_Sheet]).ProtectContents Then
Worksheets([DV_Sheet]).Unprotect
Application.Cursor = xlDefault
End If
End If
Case HCBT_DESTROYWND
'/Was a window destroyed ?
If IsXlValDropDown(wParam) Then
If Worksheets([DV_Sheet]).ProtectContents = False Then
Application.OnTime Now, "ProtectSheet"
End If
End If
End Select
CBTProc = CallNextHookEx _
(GetProp(Application.hwnd, "hookHandle"), idHook, ByVal wParam, ByVal lParam)
End Function
Private Function IsXlValDropDown(ByVal hwnd As Long) As Boolean
Dim sBuffer As String
Dim lRetVal As Long
sBuffer = Space(256)
lRetVal = GetClassName(hwnd, sBuffer, 256)
IsXlValDropDown = Left(sBuffer, lRetVal) = "EXCEL:"
End Function
Private Sub ProtectSheet()
Worksheets([DV_Sheet]).Protect
End Sub