' _,
' ___ _ _ _ ___(_)
'/ __| / \ | \| | _ | |
'\__ \/ \ \| \\ | _ \ |
'|___/_/ \_|_|\_|___/_|
'
Option Explicit
Option Compare Text
Private Const ProjectUDFName = "FormatHandleXL"
Private Const ProjectUDFFileName = "FormatHandle"
Private Const projectUDFVersion = "1.0"
Private Enum UDFCommandDirection
UCDFormatCustom
End Enum
Private Type TypeArguments
OnUndo As Boolean
timer As Single
Action As Long
Direction As Long
Target As Variant
address As String
caller As Range
formula As String
format As String
End Type
#If VBA7 Then
Private Declare PtrSafe Function SetTimer Lib "USER32" (ByVal Hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As LongPtr, ByVal lpTimerFunc As LongPtr) As Long
Private Declare PtrSafe Function KillTimer Lib "USER32" (ByVal Hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
#Else
Private Declare Function SetTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long) As Long
#End If
Private Works() As TypeArguments
'-------------------------------------------------------------------------------------------------------
Function FMCustom(Optional ByVal Cells, Optional formatString$ = vbNullChar) As Variant
FMCustom = "[Format]"
Call AddArgumentsFilter(UCDFormatCustom, Cells, formatString)
End Function
Private Function AddArgumentsFilter(Direction&, ParamArray arguments())
On Error Resume Next
Dim k%, i%, j%, r As Object, s$, f$
Set r = Application.ThisCell: If r Is Nothing Then Exit Function
f = r.formula
s = r.address(0, 0, , 1)
k = UBound(Works):
k = k + 1
ReDim Preserve Works(1 To k)
With Works(k): .Action = 1: .OnUndo = True: .Direction = 0: Set .caller = r: .address = s: .formula = f
End With
s:
With Works(k)
.Direction = Direction
Select Case Direction
Case UCDFormatCustom:
Select Case TypeName(arguments(0))
Case "Range": Set .Target = arguments(0): .format = arguments(1):
Case "Error": .format = vbNullChar
Case Else: .format = arguments(0)
End Select
.Action = 2: .timer = timer:
Call createProcTimer(True)
End Select
End With
End Function
''///////////////////////////////////////////////////////
Private Sub createProcTimer(first As Boolean)
Call SetTimer(Application.Hwnd, 541112 + first, 100, AddressOf S_FormatCustom_callback)
End Sub
#If VBA7 And Win64 Then
Private Sub S_FormatCustom_callback(ByVal Hwnd^, ByVal uMsg&, ByVal nIDEvent&, ByVal dwTimer&)
#Else
Private Sub S_FormatCustom_callback(ByVal Hwnd&, ByVal uMsg&, ByVal nIDEvent&, ByVal dwTimer&)
#End If
On Error Resume Next
Call KillTimer(Hwnd, nIDEvent)
Select Case nIDEvent
Case 541111: S_FormatCustom_working True
Case 541112: S_FormatCustom_working False
End Select
End Sub
Private Sub S_FormatCustom_working(first As Boolean)
On Error Resume Next
Dim ub%, a As Object, b As TypeArguments, o, sh, f$, i&, cfl%, su As Boolean, ac As Boolean, ee As Boolean, rg As Range
ub = UBound(Works)
Debug.Print "S_FormatCustom_working", timer
For i = 1 To ub
b = Works(i)
If a Is Nothing Then
Set a = Application
'su = a.ScreenUpdating: If su Then a.ScreenUpdating = False
'ee = a.EnableEvents: If ee Then a.EnableEvents = False
'ac = a.Calculation = xlCalculationAutomatic: If ac Then a.Calculation = xlCalculationManual
End If
Select Case b.Action
Case 2: Works(i).Action = 3
Set rg = b.Target
Err.Clear
If rg Is Nothing Then Set rg = Selection
If Err = 0 Then
Set Works(i).Target = rg
Select Case b.Direction
Case UCDFormatCustom: SendKeys "^z", False: GoTo E
End Select
End If
Case 3:
Set rg = b.Target
If Not rg Is Nothing Then
Select Case b.Direction
Case UCDFormatCustom:
rg.NumberFormat = IIf(b.format = vbNullChar, "General", b.format): GoTo E
End Select
End If
End Select
n:
Next
E:
If first Then
createProcTimer False
Else
Erase Works
End If
If Not a Is Nothing Then
'If su And a.ScreenUpdating <> su Then a.ScreenUpdating = su
'If ee And a.EnableEvents <> ee Then a.EnableEvents = ee
'If ac And xlCalculationAutomatic <> a.Calculation Then a.Calculation = ac
End If
End Sub