PRB: Memory Leak and Array Parameters Are Cleared When Method Object in MTS Doesn't Work (236332)



The information in this article applies to:

  • Microsoft Transaction Server 2.0

This article was previously published under Q236332

SYMPTOMS

If an object's method receives an array as a parameter and the object is configured to run in MTS, then the argument is cleared out if the object returns with an error. This only happens under the following circumstances:
  • The parameter is a Visual Basic typed array, as in ParamName() as a string, or a SAFEARRAY *.
  • The method is called using early binding (using a variable declared As ClassName and not As Object).
  • The method returns an error (something other that S_OK).
The symptoms experienced vary according to the client language or environment, and as such are detailed here:
  • Visual Basic clients:

    The Visual Basic array variable maintains the same structure (number and bounds of dimensions) but the elements in it changes. According to the type of the array, you see the following data in the array elements:

    • Strings: "" (zero-length strings)
    • Numbers (Long, Integer, etc.): 0 (zero)
    • Variants: Empty
    • Dates: #00:00:00#
  • Visual C++ clients:

    The SafeArray pointer passed as the method argument is made null, and the information stored within it (dimensions, bounds, elements, etc.) is destroyed.
  • Memory Leak:

    The array memory is lost in the MTS package, thus for each call when there is an error there is a memory leak proportional in size to the memory used by the array argument.

CAUSE

The cause is a bug in the stub provided by MTS.

RESOLUTION

Workaround

The simplest workaround is to use late binding; that is to declare the object As Object instead of the specific class type. To do this in Visual Basic, change the Dim statement for your object variable on which the method is executed. Instead of:
Dim oTest As TestArray.Test

use this:
Dim oTest As Object

Note that this method avoids both the argument cleaning and the memory leak.

Note to Visual C++ clients: You have to make your call through IDispatch to use this workaround. This includes packing the method parameters in a DISPPARAMS structure and providing for all the required information in the GetIdsOfNames and Invoke calls. Please review the Platform SDK for more information on this.

If this is not a valid workaround in your scenario another solution is to pass as an argument a copy of the array, not the real array itself.
To accomplish this, make a copy of the array and use that as the call argument. If an error occurs, only the copy is destroyed and you still have the original data. However, in this case the memory leak still occurs.

NOTE: For Visual C++ clients, you need to copy SafeArray, not just alias a pointer to it. To do this use the SafeArrayCopy function in the Oleauto.h file.

If no error occurred in the method call and if you expect the server to modify the contents of this array, then copy back the contents of the argument array to the original variable and continue working as usual. If an error did occurred, use the original array in your error handling (the copy is cleared).

STATUS

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

MORE INFORMATION

Steps to Reproduce Behavior

  1. Create an ActiveX DLL. Name the project "TestArray" and name the default class provided "Test".
  2. Add a method as follows:
    Public Sub CleanMyArray(RaiseAnError As Boolean, Data() As String)
    
        If RaiseAnError Then Err.Raise 1234
    
    End Sub
    						
  3. Compile the DLL and locate it within Windows Explorer. Create a new empty package in Microsoft Transaction Server and perform drag the DLL into the components right pane to register the TestArray.Test object with MTS.
  4. Create a Visual Basic 6.0 Standard EXE test client. Add a reference to the TestArray type library by selecting References from the Project menu and checking the TestArray item. This allows you to declare the object reference as belonging to the appropriate class and use early binding.
  5. Create a button on the Form1 form and add the following code to its Click event handler:
    
    On Error Goto ErrHandler
        Dim oTest As TestArray.Test
        
        Dim aData(1 to 2) As String
        aData(1) = "vee-bee"
        aData(2) = "edjez"
    
        Set oTest = New TestArray.Test
    
        'No error is raised.
        oTest.CleanMyArray False, aData
    
        MsgBox "OK! aData(1) = """ & aData(1) & """"
    
        'Now you raise an error: 
        oTest.CleanMyArray True, aData
    
    
    Cleanup:
        Set oTest = Nothing
    
    Exit Sub
    ErrHandler:
        MsgBox "ERROR! aData(1) = """ & aData(1) & """"
        Resume Cleanup
    
    						
  6. Run the project. Notice two message boxes; one showing the contents are acceptable and the other showing the array contents were cleared.
To work around this problem, use late binding by declaring the test variable As Object. Here is similar code that implements this, please note that the only modification is the Dim statement.

On Error Goto ErrHandler
    Dim oTest As Object 
    'We do this instead of TestArray.Test to use late binding
    
    Dim aData(1 to 2) As String
    aData(1) = "vee-bee"
    aData(2) = "edjez"

    Set oTest = New TestArray.Test

    'No error is raised:
    oTest.CleanMyArray False, aData

    MsgBox "OK! aData(1) = """ & aData(1) & """"

    'Now we raise an error 
    oTest.CleanMyArray True, aData


Cleanup:
    Set oTest = Nothing

Exit Sub
ErrHandler:
    MsgBox "ERROR! aData(1) = """ & aData(1) & """"
    Resume Cleanup
				

When you run this code, notice that the array content is preserved. If you look at the private byte count for the package MTX.exe instance using the Windows NT Performance Monitor notice that in this case there is no leak either.

REFERENCES

For additional information and a partial fix, click the article number below to view the article in the Microsoft Knowledge Base:

244795 FIX: Memory Leak in MTS when COM Exception Raised



Modification Type:MajorLast Reviewed:6/18/2001
Keywords:kbprb KB236332 kbAudDeveloper