Today I had to face a very subtle migration issue. I was
refining the Archive
Explorer sample application to make it ready for publishing on this site.
This application extracts one or more compressed files from a .ZIP archive and works
magnificently under VB6. The converted VB.NET program worked equally well,
except for a minor but disturbing detail: I was able to extract a given file from
the compressed .zip file only if it was the first file in the list of files to
be uncompressed. In all other cases I had an IndexOutOfRange runtime exception.
It was clearly a problem related to how an array was created
or initialized, but I had no clue about where the VB.NET diverged from the
original VB6 application. Archive Explorer counts only 4,000 lines, yet it is
such a complex application and for sure I am not an expert of compression
techniques. I was lost, because I didn’t know where to start from. In a sense,
this is the same situation in which you find yourself when migrating a complex
VB6 business application that you didn’t write yourself and for which no
thorough documentation exists.
It took me hours to narrow down the problem to two of the most
innocent statements:
LitLen = TempLit
Dist
= TempDist
The four variables LitLen, TempLit, Dist, and TempDist are
all of the same UDT type:
Friend Structure
CodesType
Public Lenght()
As Integer
Public Code() As
Integer
End Structure
Can you see what happened? When you assign a structure to
another structure, VB6 makes an exact copy of each element in the structure; in
this specific case it creates a distinct copy of the Length and Code arrays. Also
VB.NET makes a copy of each element in the structure, except that .NET arrays
are reference types, therefore only the
pointer to the array is copied! In other words, after the assignment, the
Length array in LitLen variable points to the same Length array defined by
TempLit. If the application modifies an element of the TempLit.Length array
after the assignment, the corresponding element of the LitLen.Length array is
also affected! It was precisely what happened and explained the observed behavior.
Once the problem was clear, it took me only half an hour to
have VB Migration Partner take this detail into account. In the release version,
if a structure contains one or more arrays or fixed-length strings, the
structure implements a special Clone method that performs a “real” copy:
Friend Structure
CodesType
Public Lenght()
As Integer
Public code() As
Integer
Public Function
Clone() As CodesType
Dim copy As
CodesType = Me
copy.Lenght
= Me.Lenght.Clone()
copy.code = Me.code.Clone()
Return
copy
End Function
End Structure
When translating an assignment statement, VB Migration
Partner emits code that leverages the new Clone method:
LitLen = TempLit.Clone()
Dist
= TempDist.Clone()
Two questions for you: Did you ever meet this
problem in converting your VB6 apps? How does your conversion tool – if you use
one – handle this issue?