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.
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).