Microsoft KB Archive/320106

= BUG: Class Terminate Event May Not Fire When You Use a UDT That Contains a Dynamic Array =

Article ID: 320106

Article Last Modified on 8/15/2005

-

APPLIES TO


 * Microsoft Visual Studio 6.0 Professional Edition
 * Microsoft Visual Studio 6.0 Service Pack 1
 * Microsoft Visual Studio 6.0 Service Pack 2
 * Microsoft Visual Studio 6.0 Service Pack 3
 * Microsoft Visual Studio 6.0 Service Pack 4
 * Microsoft Visual Studio 6.0 Enterprise Edition

-



This article was previously published under Q320106



SYMPTOMS
If a class has a public user-defined type (UDT) that contains a dynamic array as a property, the Terminate event of the class may fail to fire when the client accesses the dynamic array directly through the public UDT property. This may lead to memory leak.



RESOLUTION
To work around this problem, use one of the following methods:
 * Do not select Optimize for Fast Code when you compile the client project.
 * Replace the string array inside the UDT with a Variant.
 * Do not access the string array elements directly from the UDT that is returned.

For more information about how to implement these workarounds, refer to the &quot;More Information&quot; section.



STATUS
Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.



Create the Server
 Create an ActiveX DLL project named ReproServer in Visual Basic 6.0. A default class, Class1, is created.  Add the following code to Class1: Public Type T   sFields As String End Type

Private m_T As T

Private Sub Class_Initialize MsgBox &quot;Class_Initialize&quot; End Sub

Public Property Get Data As T   ReDim m_T.sFields(1) m_T.sFields(0) = &quot;Hello&quot; Data = m_T End Property

Private Sub Class_Terminate MsgBox &quot;Class_Terminate&quot; End Sub  Add another class named Collection1.  Add the following code to Collection1: 'Local variable to hold collection. Private m_Col As Collection

Public Function Add(sKey As String) As Class1 'Create a new object. Dim objNewMember As Class1 Set objNewMember = New Class1

If Len(sKey) = 0 Then m_Col.Add objNewMember Else m_Col.Add objNewMember, sKey End If

'Return the object that is created. Set Add = objNewMember Set objNewMember = Nothing End Function

Public Property Get Item(vntIndexKey As Variant) As Class1 'This is used when you reference an element in the collection. 'vntIndexKey contains either the Index or Key to the collection, 'which is why it is declared as a Variant. 'Syntax: Set obj = x.Item(xyz) or Set obj = x.Item(5) Set Item = m_Col(vntIndexKey) End Property

Public Property Get Count As Long Count = m_Col.Count End Property

Public Sub Remove(vntIndexKey As Variant) m_Col.Remove vntIndexKey End Sub

Public Property Get NewEnum As IUnknown 'This property allows you to enumerate 'this collection with the For...Each syntax. Set NewEnum = m_Col.[_NewEnum] End Property

Private Sub Class_Initialize 'Create the collection when this class is created. Set m_Col = New Collection End Sub

Private Sub Class_Terminate 'Destroy the collection when this class is terminated. Set m_Col = Nothing End Sub  Compile the server, ReproServer.</ol>

Create and Test the Client
<ol> Create a Standard EXE project named Project1 in Visual Basic. A default form, Form1, is created.</li> Add a CommandButton control (Command1) to Form1.</li>  Add the following code to Form1: Dim c As ReproServer.Collection1 Private Sub Command1_Click 'Add an item (an instance of Class1) with a key named k1. c.Add &quot;k1&quot; dim s as String s = c(&quot;k1&quot;).Data.sFields(0) MsgBox s   'Remove the item. c.Remove &quot;k1&quot; End Sub

Private Sub Form_Load 'Create an instance of the collection. Set c = New ReproServer.Collection1 End Sub </li> Press F5 to run the client application, and then click Command1. Notice that three dialog boxes appear that contain the following messages respectively:

Class_Initialize

Hello

Class_Terminate

</li> On the Project menu, click Project Properties.</li> In the Project Properties dialog box, click the Compile tab. Make sure that Compile to Native Code and Optimize for Fast Code are selected.</li> Compile the project. Notice that Project1.exe is created.</li> Run Project1.exe, and then click Command1. Notice that you receive only two messages:

Class_Initialize

Hello

You do not receive the dialog box that contains the Class_Terminate message.</li></ol>

Workarounds
<ul> Do not select Optimize for Fast Code when you compile the client, Project1.exe.</li>  Replace the string array inside the UDT with a Variant. For example, use the following code in Class1: Public Type T   sFields As Variant End Type

Private m_T As T

Private Sub Class_Initialize MsgBox &quot;Class_Initialize&quot; End Sub

Public Property Get Data As T   Dim s(1) As String s(0) = &quot;Hello&quot; m_T.sFields = s   Data = m_T End Property

Private Sub Class_Terminate MsgBox &quot;Class_Terminate&quot; End Sub </li>  Do not access the string array elements directly from the UDT that is returned. For example, use the following code in the client application: Private Sub Command1_Click 'Add an item (instance of Class1) with a key named k1. c.Add &quot;k1&quot; 'Create a temporary structure. Dim sT As ReproServer.T   sT = c(&quot;k1&quot;).Data 'Get the field from the temporary structure rather than from that 'of the returned object, c(&quot;k1&quot;).Data.sField(0) MsgBox sT.sFields(0) 'Remove the item. c.Remove &quot;k1&quot; End Sub </li></ul>

Keywords: kbbug kbnofix KB320106

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.