Application & Data Migration Blog Posts | Mobilize.Net

VBUC - Upgrade Stubs

Written by Will Vasquez | Aug 22, 2015 2:37:00 AM

Background

When you migrate an application from VB6 to .NET using the VBUC there are multiple ways in which the third party libraries are converted to the new platform.

  • Direct Mapping: When a component has a direct equivalent in .NET and there is a 'mapping' defined for such component in the VBUC, the migrated application will simply use the .NET component.
    This is what happens when controls such as vb.label and vb.commandbutton that are mapped to System.Windows.Forms.Label and System.Windows.Forms.Button respectively.
  • Helper: When the component doesn't have a direct equivalent in .NET but the VBUC team deemed it necessary to add support, a "Helper" class is generated.
    "Helper" classes are libraries generated as part of the source code of the migrated application that wrap .NET functionality with an interface similar to the source component in VB6.
    Among the most common is the ADORecordsetHelper (a .NET class that extends the System.Data.Dataset) that is used to migrate the ADODB.Recordset class.
  • COM Interop: For any unknown or fully unsupported libraries, the reference in the migrated application will be added as a COM Interop reference. An Interop wrapper reference will be added and the same names as in the original application will be used.
  • Upgrade Stubs: When a library has a "Direct Mapping" or is migrated by using "Helper" classes but some of their classes, properties, methods or events aren't already supported an Upgrade Stub will be generated.

The Upgrade Stubs are generated only when the corresponding option is selected in the VBUC Upgrade Options tab.

The way the stubs are generated is via a public class in an Upgrade Stubs project with instance or extension methods for each one of the methods and properties from the original code.

Objective

The idea of generating stub classes and methods is that they will become a centralized location for the manual modifications necessary to implement the equivalent functionality in .NET. That way when a class is used dozens of times, the fix has to be implemented just once.

The process of implementing the stubs is completely dependant on the library and in the approach is to identify the target component in .NET and verify a way to implement the same functionality with a mechanism similar to the mechanism in VB6.

Code Sample

The following example shows the generated code for the MSXML3 library being used to load an XML document and to execute an HTTP request to an XML Web Service.

VB6 Code

Private Sub CommandReadDoc_Click()
   Dim doc As MSXML2.DOMDocument
   Set doc = New MSXML2.DOMDocument
   doc.loadXML (XmlTextBox.Text)
   MsgBox "There are " & doc.documentElement.childNodes.length & " nodes"
End Sub
Private Sub CommandConsumeWebservice_Click()
   Dim req As MSXML2.XMLHTTP30
   Set req = New MSXML2.XMLHTTP30
   req.open "GET", UrlTextBox.Text, False
   req.send
   XmlTextBox.Text = req.responseText
End Sub

In this code, the first event handler is used to create a new DOMDocument (XML Document), load the text in a TextBox as the XML Document and then show a message with the number of nodes in it.

The second event handler just creates a new XMLHTTP request, loads an URL and places the response in the XML TextBox.

The VBUC 6.3 supports partially the MSXML library. Specifically, the functionality to load and process XML documents is supported but not the XMLHTTP requests. This means that the first event handler will be migrated correctly and the second one will be migrated with the help of Upgrade Stubs.

C# Green Code

This is the code generated by the VBUC for the above source:

private void CommandReadDoc_Click(Object eventSender, EventArgs eventArgs)
{
   XmlDocument doc = new XmlDocument();
   try
   {
      doc.LoadXml(XmlTextBox.Text);
   }
   catch
   {
   }
   MessageBox.Show("There are " + doc.DocumentElement.ChildNodes.Count.ToString() + " nodes", Application.ProductName);
}

private void CommandConsumeWebservice_Click(Object eventSender, EventArgs eventArgs)
{
   UpgradeStubs.MSXML2_XMLHTTP30 req = new UpgradeStubs.MSXML2_XMLHTTP30();
   req.open("GET", UrlTextBox.Text, false, Type.Missing, Type.Missing);
   req.send(Type.Missing);
   XmlTextBox.Text = req.getresponseText();
}

In addition to this, the Upgrade Stub class MSXML2_XMLHTTP30 class is generated this way:

public class MSXML2_XMLHTTP30
{
   public string getresponseText()
   {
      UpgradeHelpers.Helpers.NotUpgradedHelper.NotifyNotUpgradedElement("MSXML2.XMLHTTP30.responseText");
   return "";
   }
   public void open(string bstrMethod, string bstrUrl, object varAsync, object bstrUser, object bstrPassword)
   {
      UpgradeHelpers.Helpers.NotUpgradedHelper.NotifyNotUpgradedElement("MSXML2.XMLHTTP30.open");
   }
   public void send(object varBody)
   {
      UpgradeHelpers.Helpers.NotUpgradedHelper.NotifyNotUpgradedElement("MSXML2.XMLHTTP30.send");
   }
}

In this case the DOMDocument class and its PMEs were correctly mapped to standard .NET components in the System.XML namespace.

The XMLHTTP30 class however, even though is part of the same library (MSXML), is not supported by the VBUC. The generated code will then change the uses of the class with instances of the new stub class, and all the PMEs will be replaced with calls to the methods in that stub class.

Implementing the Stubs

The following is a way of implementing the same functionality from the above examples by using the .NET WebRequest class.

public class MSXML2_XMLHTTP30
{
   System.Net.WebRequest _request;

   public string getresponseText()
   {
      var stream = _request.GetResponse().GetResponseStream();
      var streamReader = new System.IO.StreamReader(stream);
      return streamReader.ReadToEnd();
   }
   public void open(string bstrMethod, string bstrUrl, bool varAsync, object bstrUser, object bstrPassword)
   {
      _request = System.Net.WebRequest.Create(bstrUrl);
      _request.Method = bstrMethod;
   }
   public void send(object varBody)
   {
   }
}

This implementation works for the scenario showed in the sample, however there are a few things that aren't taken into account and would have to be implemented depending on the usage of the particular application being migrated:

  • Async: The parameter sent to the open method is ignored. 
    In .NET the mechanism create the request is slightly different from the mechanism in VB6 and if needed, the response from the request should be obtained as asynchronous. Also, the mechanism to retrieve the string from the response request should also be implemented in a different way.
  • Credentials: In this case the user and password arguments are also being ignored, however they might need to be implemented if they were to be used by the application.

It is also possible that the functionality that was implemented in VB6 is available in a simpler way in .NET, in some cases allowing you to replace several calls with a couple of lines, however this might require additional manual changes through the application and would make the Stub class useless. This is especially true if the functionality is used in multiple places.

As part of the Mobilize.Net Migration Methodology we don't recommend the manual replacement of these uses during the migration process because the manual changes are prone to errors and the main objective during this stage should be to get the application working the same way as the VB6 app. 

Any improvements of this type, unless they are trivial and can be automated at least through a search and replace should be left for a refactoring phase after the application has been migrated and is functionally equivalent to the source application.

I will be adding additional samples of how to implement the Stub Classes for some of the most common libraries partially supported by the VBUC.

- Will