How to limit when a Class control triggers? - vba

In this post, I was shown how to create a class for a textbox, so I could use the Textbox_Change event to run other code, like this example from #Storax:
Option Explicit
Public WithEvents tb As MSForms.TextBox
' just to keep track of the box in the grid
Public x As Long
Public y As Long
' Just a simple example for the change event.
' you could use x and y to tell the different textboxes apart
Private Sub tb_Change()
Debug.Print tb.Text, x, y
End Sub
Unfortunately, it works too well.
It fires on every keystroke in the textbox. I think I can work around that, but I'd really like it to wait until the user has finished typing, or tabbed to another control. But Textbox controls in a class module do not have Enter or Exit events.
In my main module, I have lines that change the value of the text box, but I don't always want it to trigger the event. I've tried:
Application.EnableEvents = False
Textbox1.value = "Default"
Application.EnableEvents = True
...but the Change event triggers anyway.

It is indeed possible. Based on this post you need to copy the following code into a textfile, name it catchevent.cls and import it as a class module. This is important as it contains attributes which you cannot enter in the VBE of Excel.
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "CatchEvents"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
#If VBA7 And Win64 Then
Private Declare PtrSafe Function ConnectToConnectionPoint Lib "shlwapi" Alias "#168" (ByVal punk As stdole.IUnknown, _
ByRef riidEvent As GUID, ByVal fConnect As Long, ByVal punkTarget As stdole.IUnknown, ByRef pdwCookie As Long, _
Optional ByVal ppcpOut As LongPtr) As Long
#Else
Private Declare Function ConnectToConnectionPoint Lib "shlwapi" Alias "#168" (ByVal punk As stdole.IUnknown, ByRef riidEvent As GUID, _
ByVal fConnect As Long, ByVal punkTarget As stdole.IUnknown, ByRef pdwCookie As Long, Optional ByVal ppcpOut As Long) As Long
#End If
Private EventGuide As GUID
Private Ck As Long
Private ctl As Object
'All Other Control-Events also possible
Public Sub OnEnter()
Attribute OnEnter.VB_UserMemId = -2147384830
Select Case TypeName(ctl)
Case "TextBox": MsgBox "Your code for " & ctl.Name & " here!"
Case Else: MsgBox "You entered no TextBox but another control (" & ctl.Name & ")!"
End Select
End Sub
Public Sub OnExit(ByVal Cancel As MSForms.ReturnBoolean )
Attribute OnExit.VB_UserMemId = -2147384829
Select Case TypeName(ctl)
Case "TextBox": MsgBox "Your code for " & ctl.Name & " here!"
Case Else: MsgBox "You left no TextBox but another control (" & ctl.Name & ")!"
End Select
End Sub
Public Sub ConnectAllEvents(ByVal Connect As Boolean)
With EventGuide
.Data1 = &H20400
.Data4(0) = &HC0
.Data4(7) = &H46
End With
ConnectToConnectionPoint Me, EventGuide, Connect, ctl, Ck, 0&
End Sub
Public Property Let Item(Ctrl As Object)
Set ctl = Ctrl
Call ConnectAllEvents(True)
End Property
Public Sub Clear()
If (Ck <> 0) Then Call ConnectAllEvents(False)
Set ctl = Nothing
End Sub
Then you need to adjust your code in the userform like that
Option Explicit
Private AllControls(0 To 49) As New CatchEvents
Dim Grid(1 To 10, 1 To 5) As MSForms.TextBox
Private Sub UserForm_Initialize()
Dim x As Long
Dim y As Long
Dim i As Long
For x = 1 To 10
For y = 1 To 5
Set Grid(x, y) = Me.Controls.Add("Forms.Textbox.1")
AllControls(i).Item = Grid(x, y)
i = i + 1
With Grid(x, y)
.Name = "TextBox_" & x & "_" & y
.Width = 50
.Height = 20
.Left = y * .Width
.Top = x * .Height
.SpecialEffect = fmSpecialEffectFlat
.BorderStyle = fmBorderStyleSingle
End With
Next y
Next x
End Sub
Further reading here
PS: Why you need to import code sometimes: Code Attributes
https://stackoverflow.com/a/34688164/6600940

Use a class level variable to track where or not you want to listen for grid events.
Private Grid(1 To 10, 1 To 5) As New TextBoxListener
Private GridEventsEnabled As Boolean
Public Sub TextBoxGridChange(TextBox As MSForms.TextBox)
If Not GridEventsEnabled Then Exit Sub
Debug.Print TextBox.Value
End Sub
Private Sub UserForm_Initialize()
Dim x As Long
Dim y As Long
For x = 1 To 10
For y = 1 To 5
With Grid(x, y)
Set .TextBox = Me.Controls.Add("Forms.Textbox.1")
Set .UserForm = Me
With .TextBox
.Name = "TextBox_" & x & "_" & y
.Width = 50
.Height = 20
.Left = y * .Width
.Top = x * .Height
.SpecialEffect = fmSpecialEffectFlat
.BorderStyle = fmBorderStyleSingle
End With
End With
Next y
Next x
GridEventsEnabled = True
End Sub

Related

How to reference an element in a class collection

I have a collection of Toggle Buttons along with the object name of the toggle button, as is shown in the watch screen shot
I have tried to reference the sName for the second item in the collection with this line itbcollection.Item(2).sName but it gives me Object does not support this property or method error. What is the appropriate code to get to the sName?
There is a class that is used to capture Mouse Down events, assigned to several ToggleButtons.
Option Explicit
Private WithEvents cTB As MSForms.ToggleButton
Private sName As String
Public Property Let aTB(iTB As ToggleButton)
Set cTB = iTB
sName = cTB.Name
End Property
Private Sub cTB_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal Y As Single)
If Button = 1 Then Exit Sub
Module1.RightClickDay cTB.Caption
End Sub
and at form load a loop finds all ToggleButtons and loads the collection
Dim tbEvent As cObjectArray
Dim TB(42) As Object
x = 0
For Each o In UFShows.Controls
If o.Tag = "T" Then
Set TB(x) = o
x = x + 1
o.Visible = False
Set tbEvent = New cObjectArray
tbEvent.aTB = o
iTBcollection.Add tbEvent
End If
Next o
Please, use the next adapted class code and name it "TGButClass":
Option Explicit
Public WithEvents cTB As MSForms.ToggleButton 'if not Public, it will not be exposed!
Public sName As String 'if not Public, it will not be exposed!
Public Property Set aTB(iTB As MSForms.ToggleButton)'you need Set here (nothing to be extracted, you need to Set)
'and As TooggleButtin means a sheet control
Set cTB = iTB
sName = cTB.Name
End Property
Private Sub cTB_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal Y As Single)
If Button = 1 Then Exit Sub
Module1.RightClickDay cTB.Caption
End Sub
A testing called sub RightClickDay should look like:
Sub RightClickDay(strName As String)
MsgBox strName
End Sub
Then, in the form code module you should paste the next declarations and UserForm_Initializeevent:
Option Explicit
Private objMyEventClass As New Collection
Public tbEvents As TGButClass
Private Sub UserForm_Initialize()
Dim o As Control, x As Long
For Each o In Me.Controls
If o.Tag = "T" Then
x = x + 1
Set tbEvents = New TGButClass
Set tbEvents.aTB = o
objMyEventClass.Add tbEvents
Debug.Print objMyEventClass(x).sName 'to see the (now) exposed sName
End If
Next o
End Sub
Please, send some feedback after testing it.
If something not clear enough, do not hesitate to ask for clarifications.
A similar result can be obtained using an array instead of a collection, too.

One event sub for multiple textboxes instead of declaring it multiple time?

Is it possible to have one change event procedure for multiple textboxes in the same workbook?
If for example, I have a textbox named "textbox3" in the 1st, 2nd, and 3rd sheet of the workbook and I would like this single code below to work for all of them (the textboxes) rather than having to declare it on each sheet. Right now, I have to declare the same procedure on all the sheets but I only want to declare it once since it does the same thing on all of them.
'my procedure
Sub testObj()
Dim i As Integer, obj As oleobject
Set ac = ThisWorkbook.ActiveSheet
For Each obj In ac.oleobjects
If TypeName(obj.Object) = "TextBox" And obj.name = "TextBox3" Then
i = i + 1
ReDim Preserve TextArray(1 To i)
Set TextArray(i).TextBoxEvents = obj
End If
Next obj
Set obj = Nothing
End Sub
'My class1
Public WithEvents TextBoxEvents As MSForms.TextBox
'Public WithEvents TextBoxEvents As OLEObject
Private Sub TextBoxEvents_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = vbKeyTab Then
TextBox12.Activate
End If
End Sub
Here's an example
Class module named clsTextBox:
Option Explicit
Public WithEvents TextBoxEvents As MSForms.TextBox
Private Sub TextBoxEvents_Change()
Debug.Print TextBoxEvents.Name & ": " & TextBoxEvents.Text
End Sub
'Private Sub TextBoxEvents_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
' If KeyCode = vbKeyTab Then
' TextBox12.Activate 'unclear what you're aiming for here?
' End If
'End Sub
Regular module:
Dim ColTB As Collection
Sub testObj()
Dim i As Integer, obj As OLEObject, ac As Worksheet
Set ac = ThisWorkbook.ActiveSheet
Set ColTB = New Collection
For Each obj In ac.OLEObjects
If TypeName(obj.Object) = "TextBox" Then
ColTB.Add EventObj(obj.Object)
End If
Next obj
Set obj = Nothing
End Sub
Function EventObj(obj As MSForms.TextBox) As clsTextBox
Dim o As New clsTextBox
Set o.TextBoxEvents = obj
Set EventObj = o
End Function

Use data from one userform to formula in another

Quite new to vba and have been trying to figure out how to use data from my first userform to my second userform.
let's call them userform1 and userform2
So in userform1, user will enter data for a, b, c ,and d. Upon clicking OK, userform2 will open:
Private Sub OK_Click()
l = cdbl(a.value)+cdbl(b.value)
w = cdbl(c.value)+cdbl(d.value)
userform1.hide
userform2.show
End Sub
In userform2, i need the values of a and b (entered by user in userform1) to compute for x and y:
Private Sub OK_Click()
x = cdbl(a.value)+cdbl(d.value)
y = cdbl(b.value)+cdbl(c.value)
End Sub
tried placing a placing a b c d l w x and y in a module and setting in Public but code still doesn't work. Error "object required"
Thanks very much in advance.
A simple maybe not the best way is to declare variables a and b in the class modules. The better way might be to pass them via properties.
Code in Userform1
Option Explicit
Public a As Double
Public b As Double
Private Sub CommandButton1_Click()
a = TextBox1.Value
b = TextBox2.Value
Me.Hide
End Sub
Code in Userform 2
Option Explicit
Public x As Double
Public y As Double
Private Sub CommandButton1_Click()
TextBox1.Value = x + y
End Sub
And you can test it like that
Sub Demo()
Dim f1 As New UserForm1
Dim f2 As New UserForm2
f1.Show
f2.x = f1.a
f2.y = f1.b
f2.Show
End Sub
PS No checks or whatsover if the values entered in the textboxes are really valid.
a rough way
1) declare some Public variables of Double type
hence put this a the top of any module of your choice in the project
Public aValue As Double, bValue As Double, cValue As Double, dValue As Double
2) change your code as follows
UserForm1
Option Explicit
Private Sub OK_Click()
Dim l As Double, w As Double
aValue = CDbl(a.Value)
bValue = CDbl(b.Value)
cValue = CDbl(c.Value)
dValue = CDbl(d.Value)
l = aValue + bValue
w = cValue + dValue
Me.Hide
With UserForm2
.Show
End With
End Sub
UserForm2
Private Sub OK_Click()
Dim x As Double, y As Double
x = aValue + dValue
y = bValue + cValue
End Sub
and the likes ...

Drag&drop between listboxes which are classes in a collection

Being a self-taught VBA programmer I usually search the internet until I find a satisfactory solution for the problems (and the limitations of VBA) I stumble upon. I do not simply copy code of others, I really try to understand it as well, so I can learn from it. Long story short: I used code I found for dragging data from one listbox to another. Originally, the code (for 2 listboxes) was simply put in the form's code module but I wanted to use it in a class module so I don't have to copy/paste the same code for each and every d&d listbox I use on a form. The code I use:
(Code module of the form; just the listbox part)
Option Explicit
Private collection_ListBox As New collection
Private collection_ComboBox As New collection
Private collection_Textbox As New collection
Private Sub UserForm_Initialize()
Dim frm_control As Control
Set collection_ListBox = New collection
Set collection_ComboBox = New collection
Set collection_Textbox = New collection
For Each frm_control In Me.Controls
Select Case TypeName(frm_control)
Case "ListBox"
Dim obj As CfrwxDragDropList: Set obj = New CfrwxDragDropList
Set obj.FRWX_Control = frm_control: obj.Initialize
collection_ListBox.Add obj
Case "ComboBox"
Case "TextBox"
End Select
Next frm_control
'***TEMP for testing purposes***
ListBox1.List = Array("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7")
End Sub
(Code module of the class)
Option Explicit
Private WithEvents FRWX_DragDrop As msforms.ListBox
Private Item_Source As msforms.ListBox
Public Property Get FRWX_Control() As msforms.ListBox
Set FRWX_Control = FRWX_DragDrop
End Property
Public Property Set FRWX_Control(reg_Control As msforms.ListBox)
Set FRWX_DragDrop = reg_Control
End Property
Public Sub Initialize()
'Nothing here yet!
End Sub
Private Sub FRWX_DragDrop_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, _
ByVal X As Single, ByVal Y As Single)
If FRWX_Control.ListIndex < 0 Then Exit Sub
If Button = 1 Then
Call SetDraggedItem(FRWX_Control)
End If
End Sub
Private Sub FRWX_DragDrop_BeforeDragOver(ByVal Cancel As msforms.ReturnBoolean, _
ByVal Data As msforms.DataObject, ByVal X As Single, ByVal Y As Single, _
ByVal DragState As Long, ByVal Effect As msforms.ReturnEffect, _
ByVal Shift As Integer)
Cancel = True
Effect = fmDropEffectMove
End Sub
Private Sub FRWX_DragDrop_BeforeDropOrPaste(ByVal Cancel As msforms.ReturnBoolean, _
ByVal Action As msforms.fmAction, _
ByVal Data As msforms.DataObject, ByVal X As Single, ByVal Y As Single, _
ByVal Effect As msforms.ReturnEffect, ByVal Shift As Integer)
Cancel = True
Effect = fmDropEffectMove
Call AddDroppedItem(FRWX_Control, Data, Y)
Call DeleteDraggedItem(Item_Source)
End Sub
Private Sub SetDraggedItem(lb As msforms.ListBox)
Set Item_Source = lb
Dim dataObj As New DataObject
dataObj.SetText lb.Text
Call dataObj.StartDrag(fmDropEffectMove)
End Sub
Private Sub AddDroppedItem(lb As msforms.ListBox, dataObj As DataObject, Y As Single)
lb.AddItem dataObj.GetText, FixDropIndex(lb, Y)
End Sub
Private Sub DeleteDraggedItem(lb As msforms.ListBox)
Dim selIndex As Long
With lb
selIndex = .ListIndex
.Selected(selIndex) = False
.RemoveItem selIndex
End With
Set Item_Source = Nothing
End Sub
Private Function FixDropIndex(lb As msforms.ListBox, Y As Single) As Long
Dim toIndex As Long
With lb
toIndex = .TopIndex + Int(Y * 0.85 / .Font.Size)
If toIndex < 0 Then toIndex = 0
If toIndex >= .ListCount Then toIndex = .ListCount
End With
FixDropIndex = toIndex
End Function
So far so good; everything works fine except for one tiny little thing: I get an error on
Call DeleteDraggedItem(Item_Source)
in the sub FRWX_DragDrop_BeforeDropOrPaste. I know WHY I get this error: when I drop the DataObject in ListBox2, Item_Source in the corresponding instance of the class will be empty for it was filled in the ListBox1 instance of the class. So I need a way to let ListBox2 know the source of the dropped text. I can think of 2 ways of fixing this.
The first one sends shivers down my spine only thinking of it, for it feels almost like blasphemy: I could send it with the DataObject along with the text itself by 'expanding' lb.Text with "|" followed by lb.Name and split the string in the receiving instance. It will work, but I don't like this kind of solutions.
I could pass the name of the source ListBox to the parent (being the form itself) from instance 1, so instance 2 can ask for it there. I haven't tried that solution yet, but I'm sure I'll get it to work.
So now for my questions:
1. is solution 2 a/the right way to go?
2. are there other/better solutions I haven't thought of yet?
Any help will be highly appreciated!
***** UPDATE *****
As mentioned below, I found another (I think better) fix myself. The events are still triggered from the class instances for each listbox, but I used a separate, single instance of a class that performs the actual actions attached to them. Here's the updated code:
(Code module of the form; just the listbox part)
Option Explicit
Private collection_ListBox As New collection
Private collection_ComboBox As New collection
Private collection_Textbox As New collection
Private Sub UserForm_Initialize()
Dim frm_control As Control
Set collection_ListBox = New collection
Set collection_ComboBox = New collection
Set collection_Textbox = New collection
Dim handler As CfrwxDragDropList_EventHandler: Set handler = New CfrwxDragDropList_EventHandler
For Each frm_control In Me.Controls
Select Case TypeName(frm_control)
Case "ListBox"
Dim obj As CfrwxDragDropList: Set obj = New CfrwxDragDropList
Set obj.FRWX_Control = frm_control: obj.Initialize
Set obj.FRWX_EventHandler = handler
collection_ListBox.Add obj
Case "ComboBox"
Case "TextBox"
End Select
Next frm_control
'***TEMP for testing purposes***
ListBox1.List = Array("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7")
End Sub
(Code module of the listbox class "CfrwxDragDropList"
Option Explicit
Private WithEvents FRWX_DragDrop As MSForms.ListBox
Private FRWX_DragDrop_Handler As CfrwxDragDropList_EventHandler
Private Item_Source As MSForms.ListBox
Public Property Get FRWX_Control() As MSForms.ListBox
Set FRWX_Control = FRWX_DragDrop
End Property
Public Property Set FRWX_Control(reg_Control As MSForms.ListBox)
Set FRWX_DragDrop = reg_Control
End Property
Public Property Get FRWX_EventHandler() As CfrwxDragDropList_EventHandler
Set FRWX_EventHandler = FRWX_DragDrop_Handler
End Property
Public Property Set FRWX_EventHandler(handler As CfrwxDragDropList_EventHandler)
Set FRWX_DragDrop_Handler = handler
End Property
Public Sub Initialize()
'Nothing here yet!
End Sub
Private Sub FRWX_DragDrop_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, _
ByVal X As Single, ByVal Y As Single)
If FRWX_Control.ListIndex < 0 Then Exit Sub
If Button = 1 Then
Call FRWX_DragDrop_Handler.SetDraggedItem(FRWX_Control)
End If
End Sub
Private Sub FRWX_DragDrop_BeforeDragOver(ByVal Cancel As MSForms.ReturnBoolean, _
ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, _
ByVal DragState As Long, ByVal Effect As MSForms.ReturnEffect, _
ByVal Shift As Integer)
Cancel = True
Effect = fmDropEffectMove
End Sub
Private Sub FRWX_DragDrop_BeforeDropOrPaste(ByVal Cancel As MSForms.ReturnBoolean, _
ByVal Action As MSForms.fmAction, _
ByVal Data As MSForms.DataObject, ByVal X As Single, ByVal Y As Single, _
ByVal Effect As MSForms.ReturnEffect, ByVal Shift As Integer)
Cancel = True
Effect = fmDropEffectMove
Call FRWX_DragDrop_Handler.AddDroppedItem(FRWX_Control, Data, Y)
Call FRWX_DragDrop_Handler.DeleteDraggedItem
End Sub
(Code module of the eventhandler class "CfrwxDragDropList_EventHandler"
Option Explicit
Private Item_Source As MSForms.ListBox
Public Sub SetDraggedItem(lb As MSForms.ListBox)
Set Item_Source = lb
Dim dataObj As New DataObject
dataObj.SetText lb.Text
Call dataObj.StartDrag(fmDropEffectMove)
End Sub
Public Sub AddDroppedItem(lb As MSForms.ListBox, dataObj As DataObject, Y As Single)
lb.AddItem dataObj.GetText, FixDropIndex(lb, Y)
End Sub
Public Sub DeleteDraggedItem()
Dim selIndex As Long
With Item_Source
selIndex = .ListIndex
.Selected(selIndex) = False
.RemoveItem selIndex
End With
Set Item_Source = Nothing
End Sub
Private Function FixDropIndex(lb As MSForms.ListBox, Y As Single) As Long
Dim toIndex As Long
With lb
toIndex = .TopIndex + Int(Y * 0.85 / .Font.Size)
If toIndex < 0 Then toIndex = 0
If toIndex >= .ListCount Then toIndex = .ListCount
End With
FixDropIndex = toIndex
End Function
That's it! It works between 2 listboxes, but if you want to use more it'll work as well. You can move items between listboxes, but also change the order of items within a listbox.

Tearing Down Circular References

The following code creates a circular reference for each element in the collection. Is the code in the UserForm_Terminate routine sufficient to tear down the relationships to allow the memory to be released? Or is there a requirement to use pointers and weak references?
If so/not what is the best method for testing whether the objects have been released?
Userform Code:
Option Explicit
Implements IBtnClick
Dim coll As Collection
Private Sub UserForm_Initialize()
Dim x As Long
Dim e As CBtnEvents
Set coll = New Collection
For x = 1 To 5
Set e = New CBtnEvents
Set e.btn = Me.Controls.Add("Forms.CommandButton.1")
e.ID = x
e.Register Me
With e.btn
.Height = 30
.Width = 30
.Top = 10
.Left = .Width * x
End With
coll.Add e
Next x
End Sub
Private Sub UserForm_Terminate()
Dim itm
For Each itm In coll
msgbox itm.ID
itm.Unregister
Next itm
End Sub
Private Sub IBtnClick_click(ID As Long)
MsgBox ID
End Sub
IBtnClick Code:
Public Sub click(ID As Long)
End Sub
CBtnEvents Code:
Private WithEvents p_btn As MSForms.CommandButton
Private p_ID As Long
Private click As IBtnClick
Public Property Set btn(value As MSForms.CommandButton)
Set p_btn = value
End Property
Public Property Get btn() As MSForms.CommandButton
Set btn = p_btn
End Property
Public Sub Register(value As IBtnClick)
Set click = value
End Sub
Public Sub Unregister()
Set click = Nothing
End Sub
Private Sub p_btn_Click()
click.click p_ID
End Sub
Public Property Get ID() As Long
ID = p_ID
End Property
Public Property Let ID(ByVal lID As Long)
p_ID = lID
End Property
Private Sub Class_Terminate()
MsgBox p_ID
End Sub
I have included the VB6 tag as I think the question applies equally, but I am using Excel VBA.
This is how we (manually) keep our instance book-keeping collection:
In every class/form/control we place something like this
Option Explicit
DefObj A-Z
Private Const MODULE_NAME As String = "cTransStub"
'=========================================================================
' Constants and member variables
'=========================================================================
' Consts here
' Vars here
#If DebugMode Then
Private m_sDebugID As String
#End If
' Props here
' Methods here
'=========================================================================
' Base class events
'=========================================================================
#If DebugMode Then
Private Sub Class_Initialize()
DebugInstanceInit MODULE_NAME, m_sDebugID, Me
End Sub
Private Sub Class_Terminate()
DebugInstanceTerm MODULE_NAME, m_sDebugID
End Sub
#End If
Sample implementation of helper DebugInstanceInit/Term subs that populate DebugIDs collection:
Public Sub DebugInstanceInit(sModuleName As String, sDebugID As String, oObj As Object)
Dim sCount As String
Dim lObjPtr As Long
Dim sObjCtx As String
On Error Resume Next
sDebugID = sDebugID & GetDebugID()
If DebugIDs Is Nothing Then
Else
...
lObjPtr = ObjPtr(oObj)
DebugIDs.Add sDebugID & " " & LIB_NAME & "." & sModuleName & "|&H" & Hex(lObjPtr) & "|" & Format$(time, "hh:mm:ss") & "|" & sObjCtx & "|", "#" & sDebugID
End If
...
If Not DebugConsole Is Nothing Then
DebugConsole.RefreshConsole
End If
On Error GoTo 0
End Sub
Public Sub DebugInstanceTerm(sModuleName As String, sDebugID As String)
On Error Resume Next
If DebugIDs Is Nothing Then
Else
DebugIDs.Remove "#" & sDebugID
End If
...
If Not DebugIDs Is Nothing Then
If DebugIDs.Count = 0 Then
Debug.Print "DebugIDs collection is empty"; Timer
End If
End If
If Not DebugConsole Is Nothing Then
DebugConsole.RefreshConsole
End If
On Error GoTo 0
End Sub
Upon program termination we warn for any object leaking in DebugIDs collection.