Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic memory allocation in VB6

Is there such a thing?

I'm talking about something like a C++ new command i.e. allocation of memory which necessitates explicit releasing of the memory (or risk memory leaks).

I ask because I remember having to solve some GDI leak problems previously by setting forms/controls/other objects to Nothing but can't remember what or why now...

Do we ever have to worry about memory management when developing in VB6?

like image 809
jpoh Avatar asked Mar 31 '26 13:03

jpoh


1 Answers

There are several areas of concern as far as Memory management in VB6.

The first are circular references where a child class points back to a parent and vice versa. Without explicitly setting the reference to Nothing, This is sometimes true of forms as well especially a dialog that is an editor for a Target object. Again making sure everything set to nothing will solve the problem.

The fundamental principles are 1) If anything pointed to by an object is "alive" then it won't be garbage collected. So when you set the reference to the parent object of a circular reference the child is alive so the parent doesn't get garbage collected, since the parent still alive the child doesn't get garbage collected.

The same with forms. If you don't set the Target Property of a dialog that editing an object to nothing than it won't fire the final series of events as long as the Target Object is alive.

The most common side effects of doing this are that your application won't shut down properly and your memory footprint will grow the longer the application is used.

As for GDI leaks, anytime you use an external DLL that uses handles, pointers. You put yourself in the same realm as C++ for those functions. So you have to make sure that you follow all the rules of the particular API or DLLs you are using which often involves explicitly destroying that which you created after you are done with it.

There is an elegant solution for the circular reference problem. Instead of the child referencing a parent directly you use a proxy.

First make a Proxy Class for the parent object.

Option Explicit Public Event GetRef(ByRef RHS As MyObject)

Public Function GetMyObject() As MyObject
    Dim Ref As MyObject
    RaiseEvent GetRef(Ref)
    Set GetMyObject = Ref
End Function

Then define a private variable in the Parent

Private WithEvents MyProxy As MyObjectProxy

Private Sub Class_Initialize()
    Set MyProxy = New MyObjectProxy
End Sub

Then setup a read only property called Proxy and implement the GetRef event.

Public Property Get Proxy() As MyObjectProxy
    Set Proxy = MyProxy
End Property

Private Sub MyProxy_GetRef(RHS As MyObject)
    Set RHS = Me
End Sub

For the child or anything else that needs a reference the code is as follows.

Private ParentProxy As MyObjectProxy

Public Property Get Parent() As MyObject
    If ParentProxy Is Nothing Then
        Set Parent = Nothing
    Else
        Set Parent = ParentProxy.GetRef
    End If
End Property

Public Property Set Parent(RHS As MyObject)
    If RHS Is Me Then
        Set MyObjectProxy = Nothing
    ElseIf Target Is Nothing Then
        Set MyObjectProxy = Nothing
    Else
        Set MyObjectProxy = RHS.Proxy
    End If
End Property

Because the event mechanism doesn't set references or increments the COM reference count on either object it avoids the whole circular reference problem that is the bane of many VB6 programmers.

Note: The source I got it from called it a Proxy but thanks to Anthony's comment I find it also fits the definition of the Mediator Pattern. It uses a specific VB6 Centric feature; the Event API which isn't quite in the spirit of the Mediator Pattern.

Also realize that the .NET framework has equivalents to VB6's Event API although it is implemented differently (delegates, etc)

like image 143
RS Conley Avatar answered Apr 03 '26 04:04

RS Conley



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!