Jaafar Tribak
Well-known Member
- Joined
- Dec 5, 2002
- Messages
- 9,806
- Office Version
- 2016
- Platform
- Windows
I stumbled on an oddity while experimenting with lightweight objects in vba that I thought maybe would be worthwhile sharing .. Not of much use but, interesting nevertheless.
I discovered by accident that when a runtime error occurs while there is a lightweight object in memory, Macros get completly disabled !... and that includes events, UDFs etc...
So I thought I would turn this "side effect' into my advantage and allow it to disable macros programmatically at runtime.
One issue with this is that it disables macros at the application level scope so all other macro enabled workbooks that happen to be open in the current application instance also get affected.
Tested on Excel 2010 - Win 10 .. Not sure if this will work in other systems.
Here is the code in a Standard Module: (run the DisabelMacros routine)
I discovered by accident that when a runtime error occurs while there is a lightweight object in memory, Macros get completly disabled !... and that includes events, UDFs etc...
So I thought I would turn this "side effect' into my advantage and allow it to disable macros programmatically at runtime.
One issue with this is that it disables macros at the application level scope so all other macro enabled workbooks that happen to be open in the current application instance also get affected.
Tested on Excel 2010 - Win 10 .. Not sure if this will work in other systems.
Here is the code in a Standard Module: (run the DisabelMacros routine)
Code:
Option Explicit
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If]#If[/URL] VBA7 Then
Private hHook As LongPtr
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) 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 GetDlgItem Lib "user32" (ByVal hDlg As LongPtr, ByVal nIDDlgItem As Long) As LongPtr
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 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 CallNextHookEx Lib "user32" (ByVal hHook As LongPtr, ByVal ncode As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr
Private Declare PtrSafe Function GetCurrentThreadId Lib "kernel32" () As Long
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else]#Else[/URL]
Private hHook As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length 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 GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetDlgItem Lib "user32" (ByVal hDlg As Long, ByVal nIDDlgItem As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) 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 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
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End]#End[/URL] If
Private Const WH_CBT = 5
Private Const HCBT_ACTIVATE As Long = 5
Private Const BM_CLICK = &HF5
Private unk As IUnknown
Sub DisabelMacros()
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If]#If[/URL] VBA7 Then
Dim unkVtable(0 To 2) As LongPtr, pVtable As LongPtr
unkVtable(2) = VBA.CLngPtr(AddressOf Release)
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else]#Else[/URL]
Dim unkVtable(0 To 2) As Long, pVtable As Long
unkVtable(2) = VBA.CLng(AddressOf Release)
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End]#End[/URL] If
pVtable = VarPtr(unkVtable(0))
CopyMemory unk, VarPtr(pVtable), LenB(pVtable)
hHook = SetWindowsHookEx(WH_CBT, AddressOf HookProc, 0, GetCurrentThreadId)
MsgBox "Macros have been Disabled.", vbInformation
Err.Raise 11
End Sub
Private Function Release() As Long
End Function
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If]#If[/URL] VBA7 Then
Private Function HookProc(ByVal idHook As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else]#Else[/URL]
Private Function HookProc(ByVal idHook As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End]#End[/URL] If
Dim sBuffer As String * 256, lRet As Long
If idHook = HCBT_ACTIVATE Then
lRet = GetClassName(wParam, sBuffer, 256)
If Left(sBuffer, lRet) = "#32770" Then
lRet = GetWindowText(wParam, sBuffer, 256)
If Left(sBuffer, lRet) = "Microsoft Visual Basic" Then
Call SendMessage(GetDlgItem(wParam, &H12C0), BM_CLICK, 0, 0)
UnhookWindowsHookEx hHook
End If
End If
End If
HookProc = CallNextHookEx(hHook, idHook, ByVal wParam, ByVal lParam)
End Function