What are your options to survive in the next decade?

clock May 29, 2008 07:51

Well, I really mean "what are the options to have your VB6 application survive in the next decade?". After nearly 30 years in the field - I started my Computer Science studies in 1979, go figure! - many of which spent consulting for companies in Europe and United States, I have seen many tecnology revolutions, including the advent of IBM PC and of Windows 1.0. Each one thaught me a little piece of experience.

Let's quickly see the alternatives. 

1) DO NOTHING (AKA "IF IT AIN'T BROKE, DON'T FIX IT")
If the application is at the end of its life cycle, for example because it doesn't fullfil a widespread need any longer, you might decide to have it die of a natural death. There is no reason to invest in a dying creature, therefore you might stay with VB6 and just fix some major bugs when your users complain aloud. Don't add any new feature or extend it in any way, because it would be too expensive too.

2) EXTEND THE VB6 APPLICATION USING COM INTEROP AND THE FORMS INTEROP TOOLKIT
In this case you leave the main application in VB6 but extend it by invoking .NET components using COM Interop, or display .NET forms using Microsoft's Forms Interop Toolkit. Version 2.0 of this add-on is a major improvement, as it even supports hosting of .NET controls inside VB6 forms. Best of all, the toolkit is fully supported by Microsoft and comes with full source code. [Thanks to Rob Windsor for remainding me of this option, see comments]

While the toolkit is free, adopting it has some obvious and hidden defects and costs, though. First and foremost, this approach isn't really a solution to the problem, is more of a technique to soften the migration path and lessen its impact on your organization. If you need to migrate because your app doesn't work well under Windows Vista, or because it's slow, or because you don't want to rely on a language that Microsoft doesn't support any longer, using COM Interop and the Forms Interop Toolkit is just a way to postpone the time when you truly need to find a reliable solution. Second, the communication between the VB6 and VB.NET portions of the application is often awkward and leads you to inefficiencies (due to COM Interop) and complex roundtrips that don't make your code easily maintanable.

The bottom line: you should use the Forms Interop Toolkit only in the bigger picture of a phased migration (as Rob suggests in this comment). That is, while a group of developers is working on the porting from VB6, another group is already extending the application using VB.NET. Before taking this approach, you should compare it with the effort required by migrating it to VB.NET in one step using a *good* migration tool (ours, that is :-) )

3) CONVERT TO VB.NET, USING THE UPGRADE WIZARD AVAILABLE IN VISUAL STUDIO
Why not giving it a try? it's free! While your hard disk spins for hours trying to convert your real-world business app, you can have enough time to google for less-then-gentle comments about this tool from the VB community. Let's skip to next option.

4) CONVERT TO VB.NET, USING VB MIGRATION PARTNER
Using our conversion tool to migrate to VB.NET makes sense in many cases. First, when the original application works well and is thoroughly tested, but needs to be extended with new features and implementing these extensions with VB6 would be too difficult or expensive. Second, when the application is so large that rewriting it from scratch would require a very intensive test phase. Third, if time-to-market is essential to beat your competition and make your existing users happy. In these cases you can leverage VB Migration Partner higher speed and precision (as noted by our beta testers)

5) CONVERT TO VB.NET, USING ANOTHER 3RD-PARTY TOOL
There are other VB6-to-VB.NET migration tools on the market. Choosing a conversion tool is a critical decision, so you might want to ask our competitors for a trial version and compare it with our VB Migration Partner. Please do it! Please compare its feature, precision, and speed with VB Migration Partner and then let us know. If you don't have time to waste, however, ask yourself the following questions before considering another conversion tool:

a) how many VB Migration Partner's feature does this tool support? for example, does it fully support all 60+ VB6 controls, drag-and-drop, graphic methods, arrays with any LBound, Gosubs, As New semantics, IDisposable objects, As Any parameters and callbacks in Declares, etc. 
b) are there any significant features that this tool support and that VB Migration Partner doesn't?
c) why they don't make their entire documentation available online before you buy?
d) why don't they dare to publish real-world VB6 apps and the VB.NET code that their tool generates?

As far as we know, Code Architects is the only vendor who has uploaded dozens of VB6 code samples and the corresponding, converted VB.NET project, to let potential customers see and test the VB.NET applications we produce. We don't upload artificially-conceived tiny VB6 projects that highlights the tool's strengths and hide its weakness. Instead, our code sample section gathers open-source VB6 projects taken from the Internet, and we guarantee that we edited neither the original VB6 code (which is in fact downloadable from its original URL) nor the converted VB.NET.

Now ask yourself: why no other vendor took this obvious step to show the world how powerful their tool is?

6) MANUALLY RE-WRITE IT TO VB.NET
In some cases, manually re-writing the application to VB.NET is a viable solution. Well, let me be absolutely honest on this point: in (very) few cases, this is the solution we recommend to our customers. If the application is a huge amount of contorted spaghetti code, has a orrible architecture and a ugly user interface....well, in this case you don't want to spend more time and money on automatic porting, because you would also port these issues to VB.NET. 

When weighing a complete re-writing from scratch against automatic porting, you should take several factors into account, including:

a) rewriting often takes from 50% to 90% of the time and money that was necessary to write the original application. (Sorry, no official statistics on this, just our field experience...)
b) you need a team of developer who are experienced in both VB6 and VB.NET, and they also need to be familiar with issues related to the specific application, therefore you can't simply hire them from outside your company
c) how do you cope with continuous edits/improvements to the original VB6 code during the months required by the rewrite? In other words, can you count on something similar to our convert-test-fix methodology?
d) can really you afford the extra time required by a complete re-write? what will your competitor do in the meantime?

7) MANUALLY RE-WRITE TO C#, JAVA, OR ANOTHER LANGUAGE
I heard that a few ISVs are taking this path. In my opinion this is an irrational decision, often motivated by the anti-VB (or even anti-Microsoft) feeling that is so fashionable today. Let me explain why you shouldn't even think of jumping from VB6 to any .NET language other than VB.NET.

Rewriting a complex VB6 application into a different language has all the drawbacks of rewriting it to VB.NET (see point 6), plus the many problems that you have when switching from VB.NET to C# or Java. How do you implement On Error Resume Next in C#? How do you render a DTPicker control in Java without carefuly mapping each and every property, method, and event? But the decisive argument is: do you have enough developers who are equally familiar with VB6 and C# or Java and the application being migrated?

Briefly stated: taking this route is a technological suicide similar to point 1), except it takes longer, costs more, and is more agonizing. You can only hope that your competitors are in love enough with C# or Java to invest their energies in this option. If you hear that they are doing it, relax and be happy: you don't have anything to worry about for a long time :-)

8) CONVERT IT TO C# USING AN AUTOMATIC CONVERSION TOOL
Come on! To get an idea of how tough this "solution" (so to speak) is, take all the issues listed at point 5) and multiply them by all the problems mentioned at point 7). Then double the result to have a more reasonable estimate of the actual cost and effort.

More seriously, just think of this: there are a few commercial tools on the market that can automatically migrate VB.NET to C#, for example Instant C# or C-Sharpener for VB. I have actually used a couple of these tools, they do a great job. However, they still require a few manual edits after the conversion, to adjust minor differences between VB.NET and C#. The main reason is that the resulting C# code doesn't look like native C# and requires some fixes to be more readable and easily maintainable.

Before your consider this approach, ask yourself two questions:

a) if you believe that automatic conversion between two .NET languages (VB.NET and C#) is difficult, how can you expect that a tool be able to automatically convert from VB6 to C# in one single step?
b) on the other hand, if you think that conversion from VB.NET to C# can be fully automated, why not going from VB6 to VB.NET using our VB Migration Partner (or another tool, if you prefer) first and then using Instant-C, C-Sharpener for VB, or another similar tool for doing the final move to C#?

If you really want a C# app as the final deliverable of your conversion efforts, keep in mind that jumping from VB6 directly to C# doesn't give you more than switching from VB6 to VB.NET first and then from VB.NET to C#. Well, it actually does give you something more.... many more headaches, for precision's sake :-)



Dealing with 3rd-party ActiveX controls

clock November 12, 2007 17:12

Another common question among our customers is: does VB Migration Partner handle 3rd-party ActiveX controls? Here’s a simple question that calls for an articulate answer.

First and foremost, VB Migration Partner can convert virtually all the controls in the VB6 toolbox, plus a few which aren’t distributed with VB6 but are quite common in VB6 applications, such as the ScriptControl and the WebBrowser controls. The only VB6 controls that VB Migration Partner doesn’t currently convert are the OLE container control, the Repeater control, and the Coolbar control.

It’s important to notice that most of the controls in the VB6 toolbox are migrated to “fully managed” Windows Forms controls defined in our support library. The exceptions to this rule can be gathered in two distinct groups: invisible controls (INet, MAPISession, MAPIMessage, MSComm, Winsock, ScriptControl) and visible controls (DataGrid, MSHierarchicalFlexGrid, MS Chart, and MM Control). Controls in the first group are rendered as wrappers around the original type library (using the TlbImp tool), whereas controls in the second group are substituted by .NET wrappers created using the AxImp tool.

By default, all the controls that VB Migration Partner doesn’t recognize are rendered as VB6Placeholder controls, which appear as red rectangles on VB.NET forms. In most cases you’ll see no compilation errors, because VB Migration Partner generates a “dummy” form-level Object variable named after the original control, therefore all control references are successfully resolved at compile time. (Needless to say, any reference to these variables would fail at runtime, but at least you can test all the forms in your apps that don’t contain unsupported ActiveX controls.)

If the ActiveX control is authored in VB6 and you own it’s source code, you can use our tool to migrate it to VB.NET. In this case VB Migration Partner generates all the attributes that VB Migration Partner itself needs to recognize the new VB.NET UserControl as a replacement for a VB6 control. All you need to do is recompile the VB.NET UserControl, deploy the DLL in VB Migration Partner’s main folder (C:\Program Files\Code Architects\VB Migration Partner by default), and try to migrate the main application again.

Let’s see now what your options are if your VB6 application contains ActiveX controls from other vendors and the control hasn’t been authored in VB6 or you don’t have the its source code.

The simplest and most cost-effective strategy is simply to replace the VB6Placeholder control with the .NET Framework control that most closely resembles the original ActiveX control. For example, you might decide to replace a 3-rd party grid with the DataGridView control and then fix all the references to properties, methods, and events. Needless to say, this strategy can take anything from a five minutes to a few hours, depending on how much the VB6 and VB.NET controls differ. An additional problem of this approach is that it doesn’t work well with the convert-test-fix cycle: if you later re-convert the VB6 application you’ll have to re-apply your fixes.

Alternatively, you can use the AxWrapperGen tool that we provide with VB Migration Partner. This utility generates the VB.NET source code of an “alias” class that wraps the ActiveX control and that is decorated with all the attributes that VB Migration Partner requires to recognize the class as a replacement for the ActiveX control. You must recompile this project and deploy the executable DLL in VB Migration Partner’s folder, as you’d do with UserControl classes migrated from VB6.

The last option requires you write a “pure” VB.NET alias control that replicates the same properties, methods, and events as the original ActiveX control – but doesn’t depend on the ActiveX control itself - and then decorate the class with the attributes that VB Migration Partner. In most cases, you can have the VB.NET class inherit from the .NET control that offers as many similarities to the original ActiveX control as possible. For example, an alias class for the Microsoft Calendar control should derive from the MonthView control:

     <VB6Object("MSACAL.Calendar")> _
     Public Class VB6Calendar
           Inherits MonthView
           Implements IVB6Control
          
     End Class

Alas, this option is also the most complex of the group, because you need to understand how VB Migration Partner’s support library worksand we haven’t completed this portion of the documentation yet.

To summarize, here’s what you can do:

  • Before doing anything else, check our Web site to see whether we’ve created an “alias” class for the control. We plan to add support for the most common 3-rd party controls when we have time and enough requests from our customers. The simplest way to be informed of our additions is subscribing to our newsletter.
  • If you have the control’s VB6 source, the strategy is clear: just convert it to VB.NET and deploy the compiled DLL to VB Migration Partner’s folder. This approach delivers a fully managed solution and supports the convert-test-fix cycle.
  • If you don’t have the source code, the AxWrapperGen utility offers the simplest and quickest strategy. The downside is that the control isn’t fully managed, it still depends on the original ActiveX control, and it might suffer from a few bugs in the COM Interop portion of the .NET Framework.
  • If you’ve used the control sparingly in your application, you can manually replace all ActiveX control occurrences after the migration with the VB.NET control that most closely resembles the original control. This option isn’t always possible or practical, and doesn’t support the convert-test-fix cycle.
  • A good compromise between the last two strategies: you use the AxWrapperGen utility to generate an “alias” class and then use such a class during the convert-test-fix cycle. When the VB.NET application is working fine and you don’t plan to run VB Migration Partner again, just throw away the “alias” control and manually replace all its occurrences with a fully managed controls.
  • If you have time, write your own “alias” class for the ActiveX control. (This option will be viable when we release detailed documentation about alias classes.)
  • If you don’t like any of these options, contact us for writing an “alias” control for you.


The devil is in the details

clock November 10, 2007 03:31

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?