Support Statement: Stub Replacement
- Mark Juras
- George Juras
Q:Â So, what are all these stubs??
The gmStudio Platform includes a generalized COM replacement technology that allows upgrade teams to migrate any COM API or control to an appropriate, user-specified .NET replacement.  This feature requires setup depending on the team's COM upgrade strategies . The default COM upgrade strategy is the COM Stub Support Framework.  In this strategy, references to COM services in the upgraded code are satisfied by a stub classes generated by gmStudio based on specific COM usage in the application. Another portion of the stub framework is provided to provide cleaner translations of VB6 services that may need to be reworked or migrated to runtime support services. Â
The intent of the stub framework is to provide a pure .NET result that clearly preserves the intent of the legacy code expressed as .NET projects that build.  The stub framework is not useful for running the translations. In fact stub methods are designed to throw NotImplementedException:
Here is a sample stub method. Notice that it raises NotImplementedException. The if test is used to avoid exceptions from code executing in the forms designer so that you can view the forms even in initial translations.
Namespace gmRTL.Core Public Class InformationHelper Public Shared Function IsNumeric(ByVal Expression As Object) As Boolean If (System.Diagnostics.Process.GetCurrentProcess().ProcessName <> "devenv") Then Throw New System.NotImplementedException("UPGRADE_TODO: stubbed [gmRTL.Core].InformationHelper.IsNumeric") IsNumeric = False End Function End Class
IsNumeric is a VB6 method designed to work with Variants. It does not have an exact replacement in standard .NET, and it may not be needed depending on how you decide to finish your translation. We have an implementation of IsNumeric our Sample Runtime library that emulates VB6 behavior if you need it. You may configure gmStudio to express IsNumeric in a different form if desired; it is even possible to migrate IsNumeric to different forms based on usage context using dynamic migration rules implemented in gmSL or gmAPI. See this article on Custom VB6 Language Replacement for additional information on this capability.
The stub framework allows the upgrade team to avoid the complexities of interop and migration during their Standard Upgrade. The stub framework is typically replaced with a user-specified implementation during the Custom Upgrade.  This incremental methodology is described in the Upgrade Project Overview.
Question: 11-Sep-2013
Q: I observe that the tool-generated C# code ADODB.cs contains only skeletal code and methods. Is this intentional?
Â
- rewriting the code to use in-house data-access API standard (e.g.. Entity Framework or other)
- rewriting the code to use System.Data directly  (see the RDO sample on our site and this: http://www.greatmigrations.com/pubs/ComponentReplacement.pdf)
- rewriting the code to use a .NET emulation of ADODB (e.g. gmRTL.DataLib)
- rewriting the code to use COM interop to ADODB
Question: 3-Feb-2020
Thank you for the question.
gmStudio is designed to help teams complete our Tool-Assisted Rewrite methodology. This methodology begins with a Standard Upgrade where in COM dependencies are satisfied by a stub framework generated by the tool (e.g. the ADODB stub you asked about). The content of the stub framework is based on the COM usage identified in the application code. Standard Upgrade results are typically used for planning the next phase of the upgrade, the Custom Upgrade.  In the Custom Upgrade phase, the team will produce results that use .NET types and APIs that fit their standards and budget constraints. Â
The transition from Standard to Custom translations is described here:
https://greatmigrations.atlassian.net/wiki/display/GMG/Incremental+Upgrade+Cookbook
Regarding ADODB specifically, there are many ways for upgrading ADODB to .NET data access:
- Implement the Standard ADODB stubs manually
- Rewriting the code to use some proprietary in-house or generally available data-access API standard (e.g. Entity Framework or some other ORM)
- Rewriting the code to use System.Data directly Â
- Rewriting the code to use COM interop to ADODB
For each of the above options, teams may use custom translation rules to automatically generate the custom translations, or they may modify the standard translations by hand, or they may blend by-tool and by-hand techniques. The optimal choice depends on your requirements, expected benefits, and time/budget constraints. Generally, the blended approach is the most cost effective, but that depends on many factors.
A sample ADODB emulation (i.e. stub implementation) called MigrationSupport.DataLib is available as a compiled assembly with the gmStudio Samples.  The FMStocks sample uses the DataLib sample. Â
Several articles describing how to develop custom COM upgrades (e.g. for ADODB) are published on our web site:
- https://greatmigrations.atlassian.net/wiki/display/GMG/Custom+COM+Replacement
- https://greatmigrations.atlassian.net/wiki/display/GMG/RDO+to+SQLClient+Sample
- https://greatmigrations.atlassian.net/wiki/display/GMG/gmapiSamples
We also distribute MigrationSupport.DataLib as source with gmStudio licenses.  This sample source code is distributed As-Is, No Warranty.  Â
As discussed here: https://greatmigrations.atlassian.net/wiki/display/GMG/Runtime+Library+Requirements+and+Support
Great Migrations can assist you with developing runtime support code subject to a statement of work and measurable acceptance criteria.
Question 24-Aug-20
I understand what’s expected is that I should actually have just filled out the COM stub by forwarding the calls on to Replacement API.
No: this is not what is expected.  Implementing a stub as an API wrapper is only one possible option. It is also possible to use gmStudio to generate application code that directly references and uses a similar .NET API providing the platform services formerly provided by COM. There are many possible API replacement strategies:
- something like your replacement .NET assembly which may be nearly identical,
- a runtime callable wrapper interop assembly (generated using tlbexport)
- some other managed API from the .NET distribution, from open source, from in-house development, from a commercial vendor,
- stub implementation by extending/encapsulating/inheriting an appropriate .NET API,
- or a combination of these options.
There is no way for us to predict and generalize and implement all of these Custom API Replacement strategies in advance, and they are not done as part of a Standard Upgrade. However, we have generalized the technology to facilitate and automate most types the API replacement work. The amount of cost/benefit of each replacement strategy depends on both business and technical factors.
See this article https://greatmigrations.atlassian.net/wiki/display/GMG/Custom+COM+Replacement and the gmStudio Samples https://greatmigrations.atlassian.net/wiki/display/GMG/Samples
We offer the Standard Upgrade as a first step; it is just a foundation. The Standard Upgrade uses the Stub APIs because they can be controlled and generalized to provide .NET application codes that build. We hope teams will consider using gmStudio to help them to Custom Upgrades after the Standard Upgrade.  However, this is not a requirement: you may choose to finish your Custom Upgrade without gmStudio.Â
Should the stub API be identical to the real API used by the assembly? If not, why?
No: Stubs may not be identical to the "real API" used by the application:
Stubs are generated based on an Interface Description File (IDF) file generated from an IDL file generated from the COM file referenced. In the case where the COM file is an interop TLB for a .NET assembly, there has already been one transformation made by the tlbexport process where the "real API" (i.e. the .NET assembly) is used to generate a corresponding TLB; that transformation can introduce differences to make the interop TLB more compatible with the COM conventions expected by VB6.
If the APIs are identical, should I be able to replace the stub with the real assembly? If not, why?
Yes: if the API defined in the assembly is identical to the API declared in the stub, you should able to replace the stub with the assembly. However, if there are differences in the stub and the assembly with respect to API elements referenced in your code, you will probably get compiler errors or warnings. These differences may be addressed by adding migration rules to your upgrade solution to produce code that is compatible with the "real" assembly.Â
What would be causing the inconsistencies between the stub and the assembly and how can we fix them? A few examples are
Some shorts are getting translated to ints in the stub, which resulted in a compiler error when I tried to use the assembly
The process that generates the IDF from the IDL converts COM Shorts to Integer by default. This results in ints in the C# stub where the COM has shorts. We do this because we assume most .NET APIs will standardize on int rather than short for fixed point values. However, if the "real API" still uses short, this assumption is not true, the default IDF will not be identical to the "real API". It is possible to generate IDFs that keep COM Short as short. It is also possible to use a RefactorLibrary to override specific API elements so that they have a different type than the one specified in the IDF. I used this for many weak-to-strong typing modifications for the API. Â
If you need/want to stick with short in your .NET version of the API, I will be happy to re-generate the IDF from the IDL to retain short in the stubs and in the application code that references the API.Â
Can we improve things by sending you the real assemblies we will want to use in the C# project?
The IDF generation based on COM files, not .NET assemblies. In these cases, the COM files are COM-Callable-Wrappers (CCWs) files generated by the .NET SDK tlbexport tool. It might be helpful to look at the process you use for generating those tlb files. I understand the short/int difference and can address that with the TLB, I am not sure about the ref/out matter yet.Â
If we have to use the stubs, how can we get around the problem of passing Sketch objects to our other C# components?
We do not require you to use the stubs.
RE: I also have a question regarding standard GUI controls such as those found in MSComctl (not third-party ones). Is it expected that we will replace these controls ourselves (presumably by leveraging the stubs), or can you migrate them to the WinForm equivalents? Or do the stub classes only include things that couldn’t be migrated?
The Windows Common Controls found in MSComctl are NOT standard controls – one must explicitly add a reference to MSCOMCTL.OCX to use them.Â
The Standard Controls are those that do not require adding a reference to the VB6 IDE Toolbox and/or Project files (e.g. PictureBox, Label, TextBox, etc.).Â
In a Standard Upgrade, most of the Standard Controls are migrated to their obvious Winforms replacement although the WinForms replacements are not "perfect". Furthermore, some Standard VB6 controls (e.g. DriveListBox, FileListBox, DirListBox, Line, Shape, Data, OLE) are upgraded to Stubs in a Standard Upgrade since there is no obvious, general WinForms replacement.Â
Our MigrationSupport sample implementation includes sample implementations of DriveListBox, FileListBox, DirListBox that you can see used in the our samples. We also have done a sample implementation of a Data Control. More about that is here: https://greatmigrations.atlassian.net/wiki/display/GMG/Runtime+Library+Requirements+and+Support
It is also possible to configure gmStudio to upgrade these VB6-standard-but-not-WinForms Controls to .NET replacements rather than stubs using Custom Upgrade techniques similar to those used for COM Control upgrades.
Question: 14-Jun-2021
Q: RE: I did try your tool on a 9k LOC project, and the result is not as I expected. I see you have prepared a externs folder to contain helper classes like MSFlexGrid, FpSpread... but actually all they do is return null and 0 to avoid compilation errors.  Is this a trial-version thing?
A: It is not a trial-version thing, it is a default translation thing. We designed our tool to enable a "Tool Assisted Rewrite" methodology that enables small teams to complete large, complex migrations in a way that provides for a high level of control, precision, and scalability. The default translations are an important initial step in that methodology. Â
Our process of transforming source code begins with reading and interpreting the original source and storing all the details (symbol tables and operation streams) in a migration model. It is critical that the initial model be accurate and complete. The default translations are in "Standard Upgrade" form: code integrating the application translations with Stub Framework files. Note that the Stub Framework is generated based on the particular COM usage in the source code. We use the .NET compiler to build the default translation and test if it is well-formed, complete, and internally consistent.  This is a foundational milestone in our methodology.  Please read more about our methodology here: https://greatmigrations.atlassian.net/wiki/display/GMG/Upgrade+Project+Overview
Once the Standard Upgrade milestone is reached, teams typically move on with implementing a Custom Upgrade solution.  The Custom Upgrade will contain features such as COM API replacements, structural changes, cleanup, etc.  Read about the incremental migration model here: https://greatmigrations.atlassian.net/wiki/display/GMG/Incremental+Upgrade+CookbookÂ
Custom Upgrade features are supported by the Trial, but they are not activated in a default translation, and at present, they are not activated by clicking check boxes on a GUI. Custom Upgrade rules are implemented by various rules files: XML configuration files and dynamic transformation extensions written in our scripting language or in C# using our .NET API.  These "rules" are developed for different upgrade features and integrated to create a full Custom Upgrade.  Rules may also be optimized as requirements evolve and may be reused on future upgrade projects at the organization.  We have a library of rules files here: https://greatmigrations.atlassian.net/wiki/display/GMG/gmStudio+Extensions and you can see custom upgrades samples here:  https://greatmigrations.atlassian.net/wiki/display/GMG/Samples
Regarding Grids:
Our tool provides an open, precise, and flexible COM transformation feature.  It is not limited to pre-defined migration targets since different teams have unique requirements.  For example, just for Grids there are at least half a dozen replacements to choose from (Microsoft WinForms Microsoft WPF, Telerik, SyncFusion, Infragistics, Xceed, open source, in-house custom).  Grids are just one of many COM APIs that may be used in a VB6 application and will need to be replaced. And, all these COM APIs may be upgraded using Custom Upgrade rules defined by the team. A more detailed discussion of this is here: https://greatmigrations.atlassian.net/wiki/display/GMG/Custom+COM+Replacement