Four new (amazing!) code samples

clock January 23, 2008 12:06

We have made four new migrated programs available in our Code Sample section. All of them are quite interesting - because they show VB Migration Partner's muscles, but also because they are intriguing in themselves.

EGL25 is an amazing ray tracer written in VB6, which is so fast that you can interactively rotate complex objects made of thousands polygons in real time. What is even more amazing is that VB Migration Partner managed to convert it to VB.NET at the first attempt!

Spell Checker is what its name implies: it comes with a dictionary of over 450,000 English words and uses a sophisticated Soundex-like algorithm to suggest words that are "similar" to the one you entered. Also in this case we managed to convert this code at the first attempt.

ID Card Maker allows you to create your own ID card. Very simple, but it is a good demonstration of VB Migration Partner's graphic capabilities. 

Type-n-Sign teaches you the sign language and shows how well VB Migration Partner deals with API Declares, non-rectangular forms, and other advanced programming techniques.



Version 0.93 has been released

clock January 22, 2008 11:47

We just uploaded version 0.93 and made it available to beta testers.

The most important new feature is the EnableAppFramework pragma, which allows you to select a splash screen and the other settings that are available in the Application tab of the My Project designer in VB2005. 

Another minor but important feature - that can save you hours of hard debugging - is a new warning that VB Migration Partner emits when it detects a misuse of a Windows API, such as GetSystemDirectory or GetWindowText. You can find more details in this KB article: [PRB] A call to a Windows API Declare returns a string filled with spaces.

We are approaching the "feature complete" status and don't plan to add many new features until version 1.0 finally ships. We are quite busy in smashing bugs, though, and this version fixes over 60 of them. (Beta users can have a look at the Version History.txt file for more details.) For example, VB Migration Partner now works great on 64-bit platforms; conversions between strings and Byte array work *exactly* as in VB6; #If block convert correctly; and so forth.

We plan to release version 0.94 in a couple of weeks. In the meantime, we are working closely with many Italian companies and are testing VB Migration Partner on a few huge projects (over 2 million lines of code each!). These migration processes will take months, but our customers are thrilled by the results reached so far, and so are we.



New feature: Automatic array rank detection

clock January 10, 2008 11:28

VB Migration Partner supports the ArrayRank, which allows you to specify the rank of an uninitialized multi-dimensional array:

    Sub Test(arr() As String)
         '## arr.ArrayRank 2
         '...
    End Sub

which is converted to VB.NET as follows:

    Sub Test(ByRef arr(,) As String)
         '...
    End Sub

(Notice that you never need this pragma if the array is initialized by means of a Dim or a ReDim statement.)

In most applications you don't need to use this pragma often, because most arrays are just 1-dimensional vectors. However, there are exceptions. For example, a few days ago we upload the Waves project to our Code Sample section. This VB6 application does a lot of 3D graphcis and uses a lot of 2-dim arrays. All these arrays appeared as parameters of methods and forced us to insert as many as 30 ArrayRank pragmas. I began to wonder whether VB Migration Partner could do better than that, and automatically imply the rank of an array by some other hints and evidences. Actually, the job was relatively simple and it took me about one hour to implement it.

In the next beta release (version 0.93), VB Migration Parter can imply the rank of an array in manydifferent ways:

1) if your code accesses an element in the array, the code analyzer can just count the number of indices. For example, in this code snippet arr is clearly a 2-dim array:

    Function GetElement(arr() As String) As String
         GetElement = arr(0, 0)
    End Sub

2) if an array whose rank is know is assigned to another array whose rank isn't known - or viceversa - the rank of the unknown array can be deduced from the rank of the known array. In following example, the rank of the arr2 array can be deduced as being equal to 2,that is the rank of the arr array (which in turn was implied by the indexing operation:

    Sub Test(arr() As String, arr2() As String) 
         arr(1,2) = "abc"
         arr2 = arr
    End Sub 

A special case of this rule is when your code assigns the return variable of a Function or Property Get procedure; in the following example VB Migration Partner can deduce that the array returned by EvalArray is 2-dim:

    Function EvalArray(arr() As String) As String()
         arr(1,2) = "abc"
         EvalArray = arr
    End Sub 

3) if your code passes an array whose rank is known to a parameter array whose rank isn't known, then VB Migration Partner can deduce the rank of the parameter. For example, in this code rank of the vector parameter is unknown. However, the arr array (whose rank can be evaluated and is equal to 2) is passed to the vector parameter, therefore the rank of vector can be deduced to be equal to 2 as well:

    Function GetElement(arr() As String) As String
         Test arr
         GetElement = arr(0, 0)
    End Sub

    Sub Test(vector() As String) 
         ' ...
    End Sub

4) if an array whose rank is unknown is passed as an argument to a parameter whose rank is known, then VB Migration Partner can deduce the rank of the array passed as an argument. In the following example, the code analyzer can deduce that arr is a 2-dimensional array, and then implies that arr2 is also a 2-dim array because it is passed to the arr parameter.

    Sub Test(arr() As String) 
         arr(1,2) = "abc"
    End Sub 

    Sub Test2(arr2() As String) 
         Test arr2
    End Sub

5) the rank of an array that is being assigned the value returned by a Function or Property can be deduced if the rank of the Function/Property is also known. In the following case, the rank of the arr2 variable can be found equal to 2 because it is implied by the rank of the EvalArray function, which in turn was deduced by the assignment of the arr variable to the return EvalArray variable:

    Function EvalArray() As String()
         Dim arr(1,2) As String
         EvalArray = arr
    End Sub 

    Sub Test(arr() As String) 
         arr2 = EvalArray()
    End Sub 

Note: technique #5 can fail under certain circumstances, because it depends on the order in which methods and files are parsed. (It always works if the Function/Property is located previously in the same file.) Ensuring that it works under all circumstances would require that the parser be revised in depth, but I don't think the result would be worth the effort.

 

 



Three new code samples are available

clock January 9, 2008 09:45

Yesterday we added three new samples to our code samples section:

Virtual Night Sky shows how the sky appears at the specified place and time, and provides info on stars under the mouse cursor.
Barcode Generator displays Bar Codes 39 and 128 and lets you copy them to clipboard and save to file.
Grid-Net Waves 3D animates a 3D graph.

What they have in common is that they display graphic output using a combination of VB6 and API methods. VB Migration Partner fully supports both techniques and converts these samples with little or no effort (in all cases you need pragmas to release the device context handle).

I especially like the Virtual Night Sky sample: it took me just two convert-test-fix cycles to have a fully working version, and the entire process took me less than five minutes! I didn't even had to study the source code to understand how it works: the entire process was quite "mechanical", in the sense that I run the VB6 code through the tool a first time to see which compilation errors I got. I added a few pragmas and got a zero-compilation and zero-runtime error VB.NET code, which worked at the first attempt. If only all VB6 applications could be converted so simply!

BTW, this sample showed an interesting (and undocumented, of course) difference between the PictureBox control in VB6 and VB.NET. The original VB6 application allows you to use the Shift+left and Shift+right key combinations to move your point of view on the horizon. Oddly, these key combinations aren't trapped by the VB.NET PictureBox control: instead, they are translated to the Tab and Shift-Tab sequences. In other words, they move the input focus to a different control on the form. We decided NOT to replicate this minor difference in VB Migration Partner's support library: instead, we changed the converted app to use the Alt+left and Alt+right key combinations to achieve the same result. Spotting and fixing this issue took me five more minutes, but I can now explore my night sky with a fully .NET application. 

Note to Beta Testers: if you migrate these three samples with current version 0.92 you'll need to manually fix a few VB.NET statements. These fixes won't be necessary with the upcoming version 0.93.



Project Dependency Collection tool

clock January 8, 2008 02:55
Many of the code samples on which we've tested our VB Migration Partner tool have been downloaded from Planet Source's All-Time Hall of Fame, a page that gathers hundreds of VB6 samples that have won Planet Source's monthly contest or that have proved to be superior quality code. Even if you don't care for VB6 any longer, you can find some compelling code in that page. Pay it a visit, it won't be a waste of time.
Today I stumbled into a nice and very useful utility, named Rutu's Project Dependency Collection tool. It analyzes a VB6 project, lists all the type libraries and DLLs it depends on (and highlights missing DLLs), optionally extracts them to a folder, and include a BAT file that registers all of them. It even comes with a Shell Menu extension that allows you to run the tool from inside Windows Explorer.

It's useful, it's free, and even comes with full VB6 source code!



Release 0.92 is available to beta testers

clock January 4, 2008 11:58

We have fixed over 40 known bugs in this release, but above all we have added many new features, including:

  • the AddSourceFile pragma allows you to add a VB.NET source file to the migrated project
  • the AddLibraryPath pragma tells VB Migration Partner where to search for type libraries that have been already converted to .NET
  • the ShiftIndex pragma tells VB Migration Partner that the indexes of a given array must be offset by a specified value
  • the FixParamArray pragma tells VB Migration Partner to generate special code that ensures that arguments passed to a ParamArray parameter and modified by the callee are returned to the caller
  • the ParseReplace pragma allows you to replace a VB6 statement with another statement before the parsing process begins
  • the user interface shows migration progress (with a progress bar) and you can terminate the migration by pressing the Esc key
  • a special migration warning draws your attention to inefficiente string concatenations inside a loop
  • the new StringBuilder6 type allows you to speed up string concatenations by replacing just the variable declaration

Let me briefly illustrate more in detail the most important improvements.

When you convert a complex application that consistes in multiple DLLs - for example, we are now migrating a few real-world apps that consists of some hundreds DLLs! - you typically convert one DLL at a time, starting with the DLLs that don't depend on other DLLs and then continuing with the projects that depend on the DLLs that you have already migrated. For example, say that you have an ActiveX DLL project named MyDll and that exposes a VB6 class named MyDll.MoneyTransfer, which is converted to a VB.NET class named MyNetDll.MoneyTransfer. Of course, when you later convert projects that reference the MyDll project, you want that all references to the "old" MyDll type library are converted into references to the MyNetDll library. In earlier versions of VB Migration Partner you were asked to store the converted VB.NET DLL (MyNetDll, in our example) inside VB Migration Partner's installation directory, but this approach was a bit too weak and introduced a few problems if you were converting several VB6 projects in the same period.

The AddLibraryPath pragma offers a nice solution to this problem: you just need to store all the .NET DLLs into a directory, or a directory tree, and then mention that folder in an AddLibraryPath, as in this example:

     '## AddLibraryPath "c:\mynetdlls", True

where the second argument specifies whether the search is extended to child folders (if False or omitted, the search is limited to the specified directory). You can include multiple AddLibraryPath pragmas to specify multiple search folders. This pragma should be included in a *.pragmas file, and is ignored if included in the application's source files. Another important effect of the AddLibraryPath pragma is that all the DLLs in the search folders are never copied to the \SupportDLLs directory under the VB.NET project.

The ShiftIndex pragma is useful for arrays under the scope of an ArrayBounds pragma. For example, consider this VB6 code:

    '## arr.ArrayBounds Shift
    Dim arr(1 To 10) As Integer
    arr(1) = 5: arr(2) = 7: arr(3) = 11: arr(4) = 13

which is converted to VB.NET as follows:

     Dim arr(9) As Short
    arr(1) = 5: arr(2) = 7: arr(3) = 11: arr(4) = 13

The resulting code is not correct and in previous releases of VB Migration Partner you were forced to manually fix the indexes in the second line. The ShiftIndexes pragma solves this problem quite nicely:

    '## arr.ArrayBounds Shift
    '## arr.ShiftIndexes 1
    Dim arr(1 To 10) As Integer
    arr(1) = 5: arr(2) = 7: arr(3) = 11: arr(4) = 13

 here's the converted code:

     Dim arr(9) As Short
    arr(0) = 5: arr(1) = 7: arr(2) = 11: arr(3) = 13

The last important improvement is that now VB Migration Partner solves a subtle but serious problem in the VB6 to VB.NET conversion. Before I show the solution, let's have a look at the problem, which stems from the fact that VB6 accepts by-reference ParamArray parameters, where VB.NET accepts only by-value ParamArray parameters. The neat effect is that the following code can't be converted correctly

    Sub Increment(ParamArray args() As Variant)
        Dim i As Integer
        For i = 0 To UBound(args)
            args(i) = args(i) + 1
        Next
    End Sub

    Sub Main()
        Dim a As Integer, b As Integer
        a = 10: b = 20
        Increment a, b
        Debug.Print a, b    ' => 11, 21
    End Sub

When you migrate this code to VB.NET, VB Migration Partner issues a migration warnings that draws your attention to the fact that one or more elements of the args parameter are modified inside the method but the changes won't be propagated to the caller. If you realize that one or more callers actually relies on the by-reference nature of that parameter, you should add a FixParamArray pragma, as in this code:

    '## FixParamArray 5
    Sub Increment(ParamArray args() As Variant)
    '... remainder of code as in previous example
 

The effect of that pragma is that VB Migration Partner generates the code that replaces the args ParamArray parameter with exactly 5 Optional ByRef parameters, so that changes to these parameters are propagated back to callers exactly as it happens in VB6. (More details in an upcoming post.)

That's all for now. Let's play a little with this release and get ready for version 1.0 later this month.