Blog from September, 2013

Update: We added support for VS2013 in the March 2014 Release of gmStudio.
Update: We added support for VS2015 in the June 2016 Release of gmStudio. 
Update: We added support for VS2017 in the February 2018 Release of gmStudio. 

Ever onward!  

That seems to be the name of the game in software development.  Our customers need new features in their apps and we developers want new tools, and new techniques to build them.  We are all  just trying to keep up, stay current, keep that edge.  

Microsoft is happy to keep moving the target too.  .NET is arguably the fastest moving platform in the software tools market at the moment.  The major milestones of .NET development evolution are the major releases of Visual Studio tabulated below (source):   

Product nameCodenameInternal
version
Supported .NET
Framework versions
Release date
Visual StudioN/A4.0N/AApril 1995
Visual Studio 97Boston5.0N/AFebruary 1997
Visual Studio 6.0Aspen6.0N/AJune 1998
Visual Studio .NET (2002)Rainier7.01.0February 13, 2002
Visual Studio .NET 2003Everett7.11.1April 24, 2003
Visual Studio 2005Whidbey8.02.0, 3.0November 7, 2005
Visual Studio 2008Orcas9.02.0, 3.0, 3.5November 19, 2007
Visual Studio 2010Dev10/Rosario10.02.0, 3.0, 3.5, 4.0April 12, 2010
Visual Studio 2012Dev1111.02.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2September 12, 2012
Visual Studio 2013Dev1212.02.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2October 17, 2013



So ... onward we go!

We started work on gmStudio in 2004 with VS2003 and .NET 1.1.  Now we support rewriting VB6/ASP/COM code for VS2005, VS2008, and VS2010 although it has been a while since anyone showed interest in anything older than VS2008 and VS2010 is the default.  With the release of a major service pack  for VS2012, and VS2013 already in beta, its well past time to add support for VS2012.  I want to use this blog post to walk through the addition of VS2012 support to gmStudio.  I will describe some of the conventions and configuration features that allow gmStudio to target and integrate with different VS versions.  The tasks in this small maintenance effort are as follows:

  1. Prepare to do the work.
  2. Analyze the significant differences between VS2012 and other VS versions
  3. Implement the changes 

Preparation

Preparation is downloading and installing VS2012 and checking it out.  I downloaded the 1.5GB ISO for VS2012 Premium ran the install. All of that took a couple hours, but other than a couple restarts, it was smooth sailing.   Looking at the VS2012 UI and... hmm ... I think its called Metro right?   Functionally everything seems to be there, and more, but it reminds me of the character-based IDE turbo-Pascal that I first did PC programming on back in 1984...  very plain but now in high resolution.  (Hey at least I didn't compare it to DOS Basic).   No problem, it works; and I bet it will grow on me.  

I was able to rebuild the gmStudio projects (C#) in VS2012 with no issues.  Our gmStudio-as-a-VS-Extension project did not load or upgrade – no surprise there; it is VS2010-specific.  Also  our plug-in will not load in VS2012; no surprise there either.  Maybe I will do a separate blog post on bringing VSIX extension  up to date.

Analysis

 The first thing I notice is that VS2012 is backward compatible with the VS2010 project files (i.e. csproj, vbproj) we generate for DLLs and EXEs.  They open and work without asking to upgrade.  Web Application projects on the other hand, automatically upgrade to VS2012 format.  We will have to account for this minor matter when we translate web application projects.

Side-Bar: Multi-Version Environment

I installed VS2012 on a machine that also has VS2010 on it. I think this is typical for most people, but it does muddy the waters somewhat. In multi-version VS installations, opening a .NET project file (i.e., csproj, vbproj) can result in opening one of several VS versions. Microsoft decides which version by some means that involves looking for version specific solution file (.sln) in various locations and also looking at the application associated with .NET projects. Windows user's can also associate project files with a small utility called the Visual Studio Version Selector.    

The question is: what version of VS will be used to open the generated projects when we do a "shell open" operation from inside gmStudio?  The short story seems to be: if you have Visual Studio Version Selector associated with .NET project files and If there is a VS2010 sln file in the same folder as your csproj, then VS2010 is used, otherwise it's VS2012.

Updating gmStudio UI and Docs

Updating gmStudio to support VS2012 is a matter of changing the UI on the migration project setup form and the user default form.  

Updating the docs is also pretty mundane.  We use a Wiki for the gmStudio User Guide, so the update is quick and easy.  Gotta love a wiki...

Changing Build Tools

gmStudio has a .NET build operation that tries to compile the generated csproj/vbproj file.  This operation runs MSBuild as a shelled process.  Before we can run MSBuild executable, we execute SetEnv.cmd.  This is a command script distributed with gmStudio to setup the environment based on the desired VS version.  SetEnv.cmd  updated to support VS2012 is listed below.

@echo off
:: default to VS2010 if not specified.
if [%1]==[] set vssetup="%VS100COMNTOOLS%vsvars32.bat"
if [%1]==[VS2003] set vssetup="%VS71COMNTOOLS%vsvars32.bat"
if [%1]==[VS2005] set vssetup="%VS80COMNTOOLS%vsvars32.bat"
if [%1]==[VS2008] set vssetup="%VS90COMNTOOLS%vsvars32.bat"
if [%1]==[VS2010] set vssetup="%VS100COMNTOOLS%vsvars32.bat"
if [%1]==[VS2012] set vssetup="%VS110COMNTOOLS%vsvars32.bat"

:: If you do not have VisualStudio installed, and only the SDK, you will
:: need to use something like the following command depending on the target
:: framework SDK installation.
:: if [%1]==[VS2008] set vssetup="C:\Program Files\Microsoft.NET\SDK\v2.0\Bin\sdkvars.bat"
if not exist %vssetup% goto err
CALL %vssetup%
goto end

:err
echo %vssetup% NOT FOUND
echo Unable to setup .NET Framework SDK command line tools.
echo See %0.
exit /b 1
:end
If you need Interop Assemblies...

We rarely use interop for migrations, opting instead to configure the tool to replace COM dependencies with .NET classes. However, if you decide to use interop in your upgraded project, gmStudio can help you produce interop assemblies. The feature works as follows: First gmStudio generates a csproj file that references the COM binaries referenced in your VB6/ASP code. Then gmStudio runs a batch build of this csproj. The .NET SDK tools do the actual interop assembly generation. The csproj file is tool version and .NET framework version dependent and these should be consistent with the interop assemblies.

               VS2005: tool\framework Version = "2.0, v2.0"
               VS2008: tool\framework Version = "2.0, v3.5"
               VS2010: tool\framework Version = "4.0, v4.0"
               VS2012: tool\framework Version = "4.0, v4.5"

At present these defaults are hard coded in gmStudio. This logic was modified to support VS2012.

Changing Generated Project Files

For standard DLL and Exe projects, there are no required changes: you can open and build VS2010 files in VS2012 as-is.  However, when the user selects VS2012, I want to default to Framework 4.5.  This requires a small change to the a system configuration script called AuthorText.gmsl.    The change is made in a function called Project_Preamble.  A similar change is needed in function called StartNewcProject which is used when generating stub projects.

void Project_Preamble(string first)
{
	...
   if(Select.DevEnv == "VS2008")
   {
	...
   }
   else if(Select.DevEnv == "VS2010")
   {
	...
   }
   else if(Select.DevEnv == "VS2012")
   {
      #TextStart
      <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
         <PropertyGroup>
            <ProjectType>Local</ProjectType>
            <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
     #TextEnd
   }
...

As mentioned above, web application projects are different in VS2010 and VS2012.  

Opening a VS2010 web application project file in VS2012 will invoke a conversion process and display a conversion log:

Opening a VS2012 web project in VS2010 and will get you nothing but an error message about incompatibility.

I created new empty ASP.NET web application projects with both versions and compared them side-by-side; see the attachment for details.  Most of the differences are MSBuild tool and targets.  In any event, I made all differences conditional on DevEnv in AuthorText.gmsl.  I am doing all this on a Win7 64 machine.  There is chance it will not work on Windows versions.

Modifying Build and Run control files

Build and run control files, like csproj/vbproj, AssemblyInfo, and web.config, can direct some very powerful .NET features. When gmStudio upgrades your source code, it generates build and run control files for you. These generated files are simple, generic versions of these files. Their content is based on the templates and rules in AuthorText.gmsl.

If you want to take advantage of the advanced features you can simply use author/fix commands to modify the generated files. If you need to do something more sophisticated or something specific to your organizations standard build procedures , you can activate a project-specific AuthorText.gmsl file and change it for your purposes.

Looking at Results

There are two changes that result from setting DevEnv="VS2012" in your migration project.  First, the TargetFrameworkVersion=4.5.  Second, there are some changes in the CSC command line string used by MSBiuld.  Recall we modified SetEnv.cmd to call "%VS110COMNTOOLS%vsvars32.bat" which sets the environment to use the .NET build configuration installed with VS2012.  There were a few changes in the build configuration.  Most of the changes were Framework v4.0 to v4.5 related as expected.  The other two changes relate to the highentropy flag and the subsystem flag.

  • highentropy relates to the randomizing the layout of memory and relates to security.  Security is good.
  • subsystem:6.00  means the application requires Windows Vista or higher.  That is probably a valid assumption since we are also requiring Framework v4.5

These compiler settings are defaults chosen by Microsoft.

Left file: VS2010 build log 
Right file: VS2012 build log
 
Framework\v4.0.30319\Csc.exe 
/noconfig /unsafe- /checked- /nowarn:1701,1702 /nostdlib+
/errorreport:prompt /warn:1 /define:DEBUG
/highentropyva-
/reference:"... framework v4.0 assembly references ...
/debug+ /debug:full /filealign:4096 /optimize- 
/out:obj\Debug\code.dll

/target:library /warnaserror- /utf8output
...
"\.NETFramework,Version=v4.0.AssemblyAttributes.cs"
 
 
 
<>
<> 


<>
<>
Framework\v4.0.30319\Csc.exe 
/noconfig /unsafe- /checked- /nowarn:1701,1702 /nostdlib+
/errorreport:prompt /warn:1 /define:DEBUG
/highentropyva+
/reference: ... framework v4.5 assembly references ...
/debug+ /debug:full /filealign:4096 /optimize- 
/out:obj\Debug\code.dll
/subsystemversion:6.00
/target:library /warnaserror- /utf8output
...
"\.NETFramework,Version=v4.5.AssemblyAttributes.cs"
C# Migration Highlights

Software migration is a complex process.   During a transformation one must consider multiple aspects of the output code (Equivalence, Complexity, Readability, Maintainability, etc.)  In this blog, I wanted to highlight some of our VB6 to C# (.NET) transformations.  

 

File IO

BeforeAfter
If Dir(LogPath, vbDirectory) <> "" Then
if (System.IO.Directory.Exists(LogPath))
If Dir(FName) <> "" Then
if (System.IO.File.Exists(FName))

 

DateDiff Method

BeforeAfter
    i = DateDiff("YYYY", d2, d)
    i = DateDiff("M", d2, d)
    i = DateDiff("D", d2, d)
    i = DateDiff("H", d2, d)
    i = DateDiff("N", d2, d)
    i = DateDiff("S", d2, d)
         i = (d.Year - d2.Year);
         i = ((d.Month + (d.Year * 12)) - (d2.Month + (d2.Year * 12)));
         i = ((int)d.Date.Subtract(d2.Date).TotalDays);
         i = ((int)d.Subtract(d2).TotalHours);
         i = ((int)d.Subtract(d2).TotalMinutes);
         i = ((int)d.Subtract(d2).TotalSeconds);

 

 

MsgBox Method

BeforeAfter
        'MsgBox with message and title only
        i = MsgBox("a message box test", , "title")
        If MsgBox("a message box test", , "title") Then
        End If
            // MsgBox with message and title only
            i = MessageBox.Show("a message box test","title",MessageBoxButtons.OK);
            if (MessageBox.Show("a message box test","title",MessageBoxButtons.OK) == DialogResult.Yes)
            {
            }
i = MsgBox("Save File Before Closing ?", 51)
i = MessageBox.Show("Save File Before Closing ?","",MessageBoxButtons.YesNoCancel,MessageBoxIcon.Exclamation);
        Call MsgBox("a message box test", vbCritical Or _
            vbYesNoCancel Or _
            vbAbortRetryIgnore Or _
            vbApplicationModal Or _
            vbDefaultButton2 Or _
            vbQuestion, "title")
            MessageBox.Show("a message box test","title",MessageBoxButtons.YesNoCancel | 
                MessageBoxButtons.AbortRetryIgnore,
                MessageBoxIcon.Error | 
                MessageBoxIcon.Question,
                MessageBoxDefaultButton.Button2,
                MessageBoxOptions.ServiceNotification);

 

Like Statement

BeforeAfter
    'Tests copied from http://msdn.microsoft.com/en-us/library/swf8kaxw.aspx
    
    ' The following statement returns True (does "F" satisfy "F"?)
    wBA "Like", "'F' Like 'F'", "F" Like "F"
    '
    ' The following statement returns False for Option Compare Binary
    '    and True for Option Compare Text (does "F" satisfy "f"?)
    wBA "Like", "'F' Like 'f'", "F" Like "f"
    '
    ' The following statement returns False (does "F" satisfy "FFF"?)
    wBA "Like", "'F' Like 'FFF'", "F" Like "FFF"
    '
    ' The following statement returns True (does "aBBBa" have an "a" at the
    '    beginning, an "a" at the end, and any number of characters in
    '    between?)
    wBA "Like", "'aBBBa' Like 'a*a'", "aBBBa" Like "a*a"
    '
    ' The following statement returns True (does "F" occur in the set of
    '    characters from "A" through "Z"?)
    wBA "Like", "'F' Like '[A-Z]'", "F" Like "[A-Z]"
    '
    ' The following statement returns False (does "F" NOT occur in the
    '    set of characters from "A" through "Z"?)
    wBA "Like", "'F' Like '[!A-Z]'", "F" Like "[!A-Z]"
    '
    ' The following statement returns True (does "a2a" begin and end with
    '    an "a" and have any single-digit number in between?)
    wBA "Like", "'a2a' Like 'a#a'", "a2a" Like "a#a"
    '
    ' The following statement returns True (does "aM5b" begin with an "a",
    '    followed by any character from the set "L" through "P", followed
    '    by any single-digit number, and end with any character NOT in
    '    the character set "c" through "e"?)
    wBA "Like", "'aM5b' Like 'a[L-P]#[!c-e]'", "aM5b" Like "a[L-P]#[!c-e]"
    '
    ' The following statement returns True (does "BAT123khg" begin with a
    '    "B", followed by any single character, followed by a "T", and end
    '    with zero or more characters of any type?)
    wBA "Like", "'BAT123khg' Like 'B?T*'", "BAT123khg" Like "B?T*"
    '
    ' The following statement returns False (does "CAT123khg"?) begin with
    '    a "B", followed by any single character, followed by a "T", and
    '    end with zero or more characters of any type?)
    wBA "Like", "'CAT123khg' Like 'B?T*'", "CAT123khg" Like "B?T*"
         // Tests copied from http://msdn.microsoft.com/en-us/library/swf8kaxw.aspx
         // 
         //  The following statement returns True (does "F" satisfy "F"?)
         wBA("Like","'F' Like 'F'",Regex.IsMatch("F","F").ToString());
         //
         //  The following statement returns False for Option Compare Binary
         //     and True for Option Compare Text (does "F" satisfy "f"?)
         wBA("Like","'F' Like 'f'",Regex.IsMatch("F","f").ToString());
         //
         //  The following statement returns False (does "F" satisfy "FFF"?)
         wBA("Like","'F' Like 'FFF'",Regex.IsMatch("F","FFF").ToString());
         //
         //  The following statement returns True (does "aBBBa" have an "a" at the
         //     beginning, an "a" at the end, and any number of characters in
         //     between?)
         wBA("Like","'aBBBa' Like 'a*a'",Regex.IsMatch("aBBBa","a.*a").ToString());
         //
         //  The following statement returns True (does "F" occur in the set of
         //     characters from "A" through "Z"?)
         wBA("Like","'F' Like '[A-Z]'",Regex.IsMatch("F","[A-Z]").ToString());
         //
         //  The following statement returns False (does "F" NOT occur in the
         //     set of characters from "A" through "Z"?)
         wBA("Like","'F' Like '[!A-Z]'",Regex.IsMatch("F","[^A-Z]").ToString());
         //
         //  The following statement returns True (does "a2a" begin and end with
         //     an "a" and have any single-digit number in between?)
         wBA("Like","'a2a' Like 'a#a'",Regex.IsMatch("a2a","a\\da").ToString());
         //
         //  The following statement returns True (does "aM5b" begin with an "a",
         //     followed by any character from the set "L" through "P", followed
         //     by any single-digit number, and end with any character NOT in
         //     the character set "c" through "e"?)
         wBA("Like","'aM5b' Like 'a[L-P]#[!c-e]'",Regex.IsMatch("aM5b","a[L-P]\\d[^c-e]").ToString());
         //
         //  The following statement returns True (does "BAT123khg" begin with a
         //     "B", followed by any single character, followed by a "T", and end
         //     with zero or more characters of any type?)
         wBA("Like","'BAT123khg' Like 'B?T*'",Regex.IsMatch("BAT123khg","B.?T.*").ToString());
         //
         //  The following statement returns False (does "CAT123khg"?) begin with
         //     a "B", followed by any single character, followed by a "T", and
         //     end with zero or more characters of any type?)
         wBA("Like","'CAT123khg' Like 'B?T*'",Regex.IsMatch("CAT123khg","B.?T.*").ToString());

 

FormatDateTime Method

BeforeAfter
    str = FormatDateTime(d, vbGeneralDate)
    str = FormatDateTime(d, vbLongDate)
    str = FormatDateTime(d, vbShortDate)
    str = FormatDateTime(d, vbLongTime)
    str = FormatDateTime(d, vbShortTime)
         str = d.ToString();
         str = d.ToLongDateString();
         str = d.ToShortDateString();
         str = d.ToLongTimeString();
         str = d.ToString("HH:mm");
09/02/2013 public release
gmBasic 10.06B9
[+] Added support for translation subsystems. (select subSystem="id")
A subsystem is a named set of language translation rules that implement a custom migration.
For example producing WPF translations is done by activating the WPF subsystem.
[+] VB6 forms to WPF forms feature (supports most VB6 Intrinsic controls)
[+] Added ControlData API to gmSL. This also supports custom control migrations such as WPF.
[+] Additional migration events added to gmSL (AuthorProperties, CodeReference, AdjustProperties)
[+] Added Refactor-HasWeakSetter for accessors that take object
[+] Added Refactor-Declare to deal with missing declarations in ASP
[+] Added Refactor-RemoveResumeNext to deal with overly complex on error resume next functions
[+] Simplify FRX to RESX convention to avoid issues with special characters in resx filenames.
[+] Improved support for support for Graphics operations including Circle and Line command B and BF options
[+] Improved support for upgrading VB6 FileSystem listbox controls
[+] Improved support for source codes and COM components that use international character sets
[+] Support for '-' in ASP file names.

MetaLang
[Add] lang\WPFsubSystem.gmsl -- WPF Forms Authoring (beta)
[change] idf\Language.std.xml
[change] idf\MigrationSupport.dll.xml
[change] idf\ReferencesAudit.dll
[change] lang\netControls.xml
[change] lang\VB7Lang.xml
[change] lang\VB6IDL.XML
[change] lang\vbcontrols.xml
[change] lang\OPCODES.XML
[change] lang\TOOLLANG.XML
[change] lang\enumerations.xml
[change] lang\auditvbi.gmsl
[change] lang\VBASIC.XML
[change] lang\authortext.gmsl
[change] lang\GMSLANG.XML

gmStudio
[+] Improve UI responsiveness when running long processes
[+] Improve user control over scrolling session log to screen
[+] Update References/Definitions reports to use AuditVBI.gmsl
[+] Added Rules Samples management to Settings form
[+] Simplify view menu; removed items that are handled on Settings form
[!] Correct issue with report selector list not showing up in Trial Mode
[!] correct SrcFile path in NET Build Log report for ASP includes
[!] correct translation switches being cleared from the task in memory
[!] correct report type list being empty in trial mode

Samples
[+] Rework Scantool to filesystem listbox migration
[+] Rework FileExplorer sample to use new IDFs and gmSL for Common Controls replacements

Installation
[R] Retire GMNI DLLs that are now handled using gmSL
[+] Retire ReferenceAudit.dll
[+] Add ASPGlobalIncludes.dll to standard distribution (preparing for new Web Samples)
[+] Added a template GlobalImports script to settings folder (preparing for new Web Samples)
[+] Added a template GlobalIncludes script to settings folder (preparing for new Web Samples)
[+] Update the contents of extras\RefactorLibrary with more current samples and move to support\rules