5. Pragma Reference/プラグマリファレンス

  • 5.1 Project-level pragmas/プロジェクトレベルプラグマ

  • 5.2 Pragmas that affect classes/クラスに影響を与えるプラグマ

  • 5.3 Pragmas that affect fields and variables/フィールドと変数に影響を与えるプラグマ

  • 5.4 Pragmas that affect how code is converted/コード変換の仕方に影響を与えるプラグマ

  • 5.5 Pragmas that affect forms and controls/フォームとコントロールに影響を与えるプラグマ

  • 5.6 Pragmas that affect user controls/ユーザコントロールに影響を与えるプラグマ

  • 5.7 Pragmas that insert or modify code/コードを挿入または変更するプラグマ

  • 5.8 Pragmas that affect upgrade messages/アップグレードメッセージに影響を与えるプラグマ

  • 5.9 Miscellaneous pragmas/その他のプラグマ


5. Pragma Reference/プラグマリファレンス

This section illustrates the purpose and usage of all the pragmas that VB Migration Partner currently supports.

このセクションでは、VB Migration Partnerが現在サポートしているすべてのプラグマの目的と使用方法を例証します。


5.1 Project-level pragmas/プロジェクトレベルプラグマ

AddDataFile filespec

Copies a file into the output project’s main directory and includes the file in the VB.NET project, so that it is automatically copied to the output folder when the project is compiled. It is useful to copy images, Access MDB files, and other data files into the target project. The filespec argument is mandatory: it must be a path relative to the VB6 project’s folder (can’t be an absolute path), can contain wildcards, and must be enclosed in double quotes if it includes spaces:

    '## Rem Add the books.mdb database and all the files in the Images subfolder
    '## AddDataFile books.mdb
    '## AddDataFile Images\*.* 

AddDisposableType typename

Tells VB Migration Partner that a VB6 class is to be considered as a disposable type and be dealt with in a special way when a variable of this type is in the scope of an AutoDispose pragma. It is useful with COM objects that require finalization, for example objects that open a database connection. (Notice that VB Migration Partner recognizes as disposable ADODB objects such as Connection and Recordset.) The typename argument is mandatory and must include the type library name:

    '## AddDisposableType CALib.DatabaseManager

AddImports namespace [,explicit]

Imports a .NET namespace at the project- or file-level. It is useful together with an AddReference pragma, to make all types of the referenced library accessible from the current project. The namespace argument is mandatory and must be enclosed in double quotes if it includes spaces:

    '## AddReference "c:\code architects\appframework.dll" 
    '## AddImports CodeArchitects.AppFramework

If you specify True in the second argument, the namespace is imported at the file-level by means of an explicit Imports statement. For example the following pragma:

    '## AddImports ADODB, True

generates the following statement at the top of the file where the pragma resides:

    Imports ADODB

Even if it is rarely necessary or desirable, you can even generate explicit Imports statements in all the files in the projects by using an explicit project scope:

    '## project:AddImports ADODB, True

It’s worth noticing that the AddImports pragma has the added effect to drop all the imported namespace off type names, regardless of whether the namespace was imported at the project- or file-level. This feature helps producing more concise and readable code.

AddLibraryPath path, recurse, searchPattern

Specifies folder where VB Migration Partner can search DLLs and type libraries that have been already converted to VB.NET. The path argument is the absolute name of a directory; recurse is a Boolean that specifies whether the search must be extended to subfolders (if False or omitted, the search is limited to the directory specified in the first argument); searchPattern allows you to restrict the effect of this pragma to certain files.

    '## AddLibraryPath "c:\MyApps\Libraries"
    '## AddLibraryPath "c:\Projects\Net", True

The third argument is a regular expression that is applied against the base name of each file in the specified directory (or directory tree), that the file name without path and without extension  (the extension is assumed to be “.dll”). For example, the following pragma:

    '## AddLibraryPath "c:\Projects\Net", False, "^CodeArchitects\."

would include only the DLL files whose name starts with “CodeArchitects.”.

You can apply the AddLibraryPath pragma only by storing it in a *.pragmas file. We suggest that you use the special file named VBMigrationPartner.pragmas, which you can conveniently share among all the projects of a complex application.

An important note:
if you are migrating a VB6 project group, this pragma should be included in the *.pragmas file that accompanies each project, regardless of whether that specific project uses the classes defined in the DLLs the pragma points to. If the *.vbp files are all located in the same folder, you can use one single VBMigrationPartner.pragmas file in that directory.

AddSourceFile filename [, addaslink]

Adds a VB.NET source file to the project generated by VB Migration Partner. The filename argument is the absolute path of a *.vb source file; the second optional parameter is False (or omitted) if the file is copied to the output folder and included in the VB.NET project as a regular file, True if the file is added as a link an existing file. The pragma recognizes form and usercontrol source files and automatically imports the *.Designer.vb and *.resx files, if they exist.

    '## AddSourceFile "c:\code architects\AppFrameworkFormBase.vb"
    '## AddSourceFile "c:\code architects\AppMainForm.vb"
    '## AddSourceFile "c:\code architects\AppFrameworkCommon.vb", True

If the source file being imported requires a reference to an external DLL, you must provide an AddReference pragma; if the source file being imported assumes a project-level Imports, you must provide a suitable AddImports pragma. These pragma must be included in one of the original VB6 files:

    '## AddReference "c:\code architects\appframework.dll"
    '## AddImports CodeArchitects.AppFramework

AddReference asmPathOrName

Include a reference to a .NET assembly in the VB.NET project being created. It is useful when the code you inject by means of InsertStatement pragmas requires a .NET assembly that isn’t automatically referenced by default, for example System.Data.OracleClient. The argument is mandatory, must be either the assembly’s absolute file path or the assembly’s display name, and must be enclosed in double quotes if it includes spaces:

    '## AddReference C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Data.OracleClient.dll
    '## AddReference "System.EnterpriseServices, Version=2.0.0.0, Culture=neutral, 
        PublicKeyToken=b03f5f7f11d50a3a"

You typically specify the assembly’s display name for assemblies stored in the GAC.

ApplyRenameRules xmlfile

Specifies that VB Migration Partner should apply the rename rules contained in the specified XML file, or in the default RenameRules.xml file stored in the install folder:

    '## ApplyRenameRules c:\app\rules.xml

This pragma can be specified in both a *.pragmas file or in source code, however it affects all the projects in the solution being migrated.

For more information about renaming rules, see the Renaming program members section.

AssemblyKeyFile filename.snk, delaysign

Signs the VB.NET assembly that results from the conversion, using the specified .snk file. The filename.snk argument is the complete (absolute) path of the .snk file that contains the public/private key pair; delaysign is a Boolean that indicates whether the assembly must be delay-signed (default is False).

    '## AssemblyKeyFile "c:\codearchitects.snk"

Using this pragma is equivalent to tick the “Sign the assembly” option in the Signing tab of the My Project designer after the migration.

BinaryCompatibility force

Determines whether the migrated VB.NET project should preserve binary compatibility with the COM component written in VB6. If the optional argument is False or omitted, then compatibility is enforced only if the original VB6 project specified binary compatibility; if the argument is True, then compatibility is enforced in any case.

    '## project:BinaryCompatibility True

When this pragma is active, VB Migration Partner generates a ComClass attribute for each public class in the generated VB.NET project; this attribute specifies the GUIDs of the original coclass, class interface, and event interface of the original VB6 class. In addition, a project-level Guid attribute in AssemblyInfo.vb is generated so that the .NET assembly has same GUID as the original type library. Finally, the Register for COM Interop setting is enabled in the MyProject property page. The neat effect of all these operations is that the .NET DLL is fully compatible with the original COM DLL and all existing VB6/COM clients can continue to work as before but use the new .NET DLL instead. (No recompilation is needed.)

By default, VB Migration Partner uses the COM DLL specified as the binary-compatible DLL for the original VB6 project. (This is the DLL selected in the Component tab of the Project Properties dialog box in the VB6 IDE.) If the original VB6 project doesn’t specify binary compatibility (but the force argument is True) then VB Migration Partner uses the output DLL to extract all existing GUIDs.

This pragma is ignored and no warning message is emitted if the VB6 project type isn’t ActiveX DLL or if VB Migration Partner can’t find a COM DLL to be used to extract coclass and interface GUIDs.

As a side-effect of this pragma, all public fields in public classes are rendered as properties: this is necessary because public fields aren’t made visible to COM clients by the ComClass attribute. In addition, if the field was declared using As New, code is generated to preserve the auto-instancing semantics, regardless of whether the field is under the scope of an AutoNew pragma. The effect is therefore similar to the AutoProperty pragma, except that the BinaryCompatibility pragma affects only fields in public classes inside ActiveX DLL projects.

EnableAppFramework mainform, splashform, visualstyles, shutdownmode, singleinstance

Enables the VB.NET application framework feature. The parameter passed to this pragma correspond to the settings you can find in the Application tab of the My Project designer in Visual Studio. The mainform argument is the name of the startup form and is the only mandatory parameter for this pragma; splashform is the name of the splash form, if any; visualstyles is True if you want to enable Windows XP styles (the default is False); shutdownmode is 0 (the default) if the application exits when the main form closes or 1 if the application exits when all forms close; singleinstance is True if you want to prevent multiple instances of this application (the default is False).

For example, the following pragma sets frmMain as the main form, frmSplash as the splash screen form, enables XP visual styes and forces the application to close only when all loaded forms are closed:

    '## EnableAppFramework frmMain, frmSplash, true, 1

You should use this pragma only in standard EXE projects. When this pragma is specified, the Sub Main form is ignored (if the application has one).

ImportTypeLib typelibfilename, tlbimpcommand, assemblyname, copytoprojectfolder

Specify the command line to be passed to the TlbImp.exe tool when importing a type library. typelibfilename is the name of the .dll or .tlb file to be imported (can be just the file name or the complete file path); tlbimpcommand is the complete command that must be passed to the TlbImp.exe tool.

The third and fourth arguments are optional and are taken into account only if the tlbimpcommand argument starts with a “@” character (see later).

Notice that you need to specify the entire path in the first argument only if the current VB6 application uses two distinct type libraries with same file name:

    '## ImportTypeLib mytypelib.dll, "c:\myapp\mytypelib.dll /tlbreference:c:\myapp\support.dll
        /tlbreference:c:\myapp\interfaces.dll /keyfile:c:\mycompany.snk"

This pragma is necessary when VB Migration Partner fails to correctly locate the type library to be imported or any of the *.dll or *.tlb files such a type library depends on, or when you need to specify any additional option for the TlbImp.exe tool, such as when you want to sign the imported assembly with a strong name. Notice that VB Migration Partner uses this pragma only to correctly resolve a reference to a type library: the type library is actually imported in the current project only if it was referenced by the original VB6 project.

You can apply this pragma only by storing it in a *.pragmas file. We suggest that you use the special file named VBMigrationPartner.pragmas, which you can conveniently share among all the projects of a complex application. (As explained above, a type library is effectively imported only if it is referenced by the original VB6 project and this pragma only teaches VB Migration Partner how the type library must be imported.)

As a special case, if the second argument starts with a “@” character it is interpreted as the path of a .NET assembly that is equivalent to the original type library. This syntax variation is useful in two cases: First, if you have already (manually) converted the type library and have obtained the corresponding .NET assembly; second, if the author of the original type library has provided a Primary Interop Assembly for the type library and VB Migration Partner fails to correctly locate such a PIA. Here’s an example of this technique

    '## ImportTypeLib msword.olb, "@c:\assemblies\microsoft.office.interop.word.dll"

If the second argument begins with the “@” character, then the assemblyname optional argument should be specified and should be equal to the name of the assembly. This name is usually equal to the assembly’s root namespace, but it can also be a different string. Specifying this value allows VB Migration Partner to determine whether the .NET DLL should be added as a reference for the project being migrated, without having to actually load all the assemblies in all folders referenced by the project itself.

For example, assume that you have already migrated a VB6 DLL named “CAFramework” and created an assembly named “CodeArchitects.Framework.dll”. Here’s the pragma that does the trick:

    '## ImportTypeLib CAFramework.dll, "@c:\assemblies\CodeArchitects.Framework.dll", "CAFramework"

If you omit the assemblyname argument VB Migration Partner attempts to locate the assembly by matching the assembly name with the filename. For example, in previous example we could omit the third argument if the .NET file were named CAFramework.dll.

If the second argument begins with the “@” character, then the copytoprojectfolder optional argument specifies whether the converted VB.NET project should include a reference to the specified .NET DLL (if the argument is True) or if VB Migration Partner should first copy the .NET DLL into the SupportDLLs subfolder and have the VB.NET project reference this copy. In most cases you can omit this argument and rely on the default behavior (the DLL isn’t copied into SupportDLLs folder); you should specify True only if you later want to deploy the VB.NET project on another computer where the specified .NET DLL isn’t present.

ProjectKind prjkind

Determines the type of the current project. It is useful to specify whether an ActiveX EXE project should be converted to an EXE or a DLL Visual Basic project. The prjkind argument is mandatory and can be equal to dll or exe:

    '## Rem convert the current ActiveX project as a class library
    '## ProjectKind dll

SetPragmaPrefix newprefix

Allows you to select a different prefix for pragmas inserted in VB6 code. The argument must not include the leading single quote used for remarks:

    '## SetPragmaPrefix %%

The argument is considered to be a regular expression, therefore it is necessary to escape the characters that have a special meaning inside a regex. For example, if you want to use a double dot as the pragma prefix, you need this pragma:

    '## SetPragmaPrefix \.\.

Using a regex instead of a simple string allows you to specify multiple pragma prefixes. For example, you can have VB Migration Partner recognize the double dot prefix in addition to the default prefix:

    '## SetPragmaPrefix (##|\.\.)

The prefix doesn’t need to be 2-char long.

You can apply this pragma only by storing it in a *.pragmas file. We suggest that you use the special file named VBMigrationPartner.pragmas, which you can conveniently share among all the projects of a complex application. Notice, however, that this pragma doesn’t affect the pragmas that are stored in *.pragmas files and applies only to pragmas inserted in VB6 source code files.

This pragma can be useful for two distinct and unrelated reasons:

  1.   You use another source code management tool that relies on remarks that start with the ‘## sequence. (For example, only later in the development cycle we realized that this sequence is used by Innovasys Document! Tool).
  2. You want to migrate the VB6 code using different sets of pragmas.

As an example of the second approach, let’s suppose that your VB6 code uses DAO to access an Access database. In the first migration attempt, you generate a VB.NET application that also uses DAO, but you can then improve the result by generating ADO.NET code, which surely requires a good amount of PostInclude, PostProcess, and InsertStatement pragmas. In this case it might make sense to use a different prefix for the pragmas that add just to support ADO.NET, so that you can quickly switch from the DAO to the ADO.NET version by just editing one SetPragmaPrefix pragma.


5.2 Pragmas that affect classes/クラスに影響を与えるプラグマ

ClassRenderMode mode

Specifies how a class must be rendered during the migration process. The mode argument can be Class, Interface, ClassAndInterface, and Module. This pragma can’t be specified at the project-level:

    '## ClassRenderMode Interface

By default, all VB6 classes are rendered as VB.NET classes; however, if the class name appears in one or more Implements statements, the class is also rendered as an interface. This pragma allows developers to generate the interface even if the class doesn’t appear in any Implements statement (which may be necessary when converting an ActiveX DLL or ActiveX EXE project without also converting a client application) as well as generate only the interface and not the original class. This pragma can also be useful to convert a GlobalMultiuse or GlobalSingleUse class into a VB.NET module.

ExcludeCurrentFile boolean

Specifies whether the current file must be ignored by VB Migration Partner. It is useful for files containing modules and classes that have a VB.NET counterpart – for example, the methods in the VBMigrationPartner_Support module. If the argument is True or omitted, the current file is ignored by VB Migration Partner:

    '## ExcludeCurrentFile

This pragma can’t be specified at the project-level.

GenerateEventDispatchers boolean

Specifies how event definitions in user controls should be rendered. By default, VB Migration Partner generate an event dispatcher class for each event exposed by the user control, and then uses the dispatcher’s Raise method instead of the standard RaiseEvent keyword. If the argument is False then the standard .NET event mechanism is used instead:

    '## Rem don’t use event dispatchers in this user control
    '## ExcludeCurrentFile

VB Migration Partner’s default implementation of events inside user controls ensures that events are handled correctly even if the control belongs to a control array or is instantiated dynamically by means of a Controls.Add method. You can disable this feature and produce more compact and efficient code if you are sure that neither condition is met.

ReuseResxFiles resxpath

Allows VB Migration Partner to reuse existing *.resx files, either created manually or generated by a previous migration (possibly with the Upgrade Wizard). The resxpath argument is the path of the folder that contains the existing *.resx files.

    '## project:ReuseResxFiles c:\MigratedApps\TestApp

The argument can be either an absolute or a relative path; in the latter case, it is considered to be relative to folder where the VB6 project being migrated resides. In addition, the ${ProjectPath} placeholder is replaced by the name of the folder where the VB6 project is stored. This placeholder and the ability to use relative path allows you to store this pragma in the global VBMigrationPartner.pragmas file, provided that you have used a consistent naming schema for your migrated apps. For example, if all your migrated projects are stored in the c:\MigratedApps directory tree, you might use the following pragma

    '## project:ReuseResxFiles c:\MigratedApps\${ProjectPath}

This pragma is especially useful when converting forms that contain one or more ActiveX controls. In some (rare) cases, in fact, VB Migration Partner fails to correctly generate the OcxState property for these ActiveX controls. If you see that an ActiveX control isn’t migrated correctly, you might try to convert the project using Microsoft Upgrade Wizard, and then use this pragma so that VB Migration Partner can reuse the generated *.resx files.

Notice that you can specify this pragma at the project-, file, or component-level. When used at the file or component level, you can omit the argument to disable this feature for a specific form or control.

VariantConversionSupport bool

Indicates that the current class should be extended with two CType Operator methods that provide support for implicit conversion from/to the VB6Variant type. The argument should be True (or omitted) to enable this feature, or False to disable it. (The feature is disabled by default, therefore you typically use the False value only to override the setting at the project-level.)

    '## project:VariantConversionSupport

Starting with release 1.11, all the classes defined in the VBLibrary support implicit conversion from/to the VB6Variant type. In general it is a good idea to extend this feature to all the forms, classes, and usercontrols of the projects you migrate.


5.3 Pragmas that affect fields and variables/フィールドと変数に影響を与えるプラグマ

AddAttribute text

Associates a custom attribute to the current project, class, method or a specific variable. The text argument must be a valid VB.NET attribute. Surrounding < and > delimiters are optional:

    '## project:AddAttribute Description("this is an assembly")

    Sub SetSize(w As Integer)
        ' attributes associated with a method can be inserted inside the method
        '## AddAttribute MyCustomAttribute(true)
        ' attributes associated with parameters require a prefix
        '## x.AddAttribute Description("the object’s width")
        …
    End Sub

This pragma may not work as intended with fields that are converted into separate properties, e.g. public variables declared with As New that fall under the scope of an AutoNew pragma.

ArrayBounds mode

Specifies how the declaration of arrays with a nonzero lower index must be converted to VB.NET. The valid values for the mode argument are Unchanged (arrays are migrated verbatim, the default behavior), ForceZero (the lower index is forced to be zero), Shift (both the lower and upper indexes are shifted so that the number of elements in the array doesn’t change), VB6Array (convert the array into a VB6Array object), or ForceVB6Array (convert the array into the VB6Array even if the lower index is zero):

    '## ArrayBounds VB6Array

Notice that this pragma, like all pragmas that can reference arrays, should be inserted immediately before the Dim statement that declares the array, rather than before the ReDim statement that actually creates the array. Pragmas inserted inside the method where the ReDim statement appears are ignored.

Also notice that this pragma only affects the declaration (DIM) of an array, not the value of indexes used in code to reference individual array items. For that purpose you should use a ShiftIndexes pragma.

ArrayRank rank

Specifies the rank of an array. It is useful when VB Migration Partner isn’t able to determine the correct rank of a multi-dimensional array taken as an argument, returned by a property or function, or declared at the class level but initialized elsewhere. Consider the following VB6 example:

    '## arr.ArrayRank 2 
    '## GetArray.ArrayRank 2
    Dim arr() As Integer
    
    Function GetArray(initialize As Boolean) As Integer()
        If initialize Then ReDim arr(10, 10)
        GetArray = arr
    End Function

If it weren’t for the ArrayRank pragma, the field and the method would return a vector instead of a two-dimensional array:

    Dim arr(,) As Short 
    
    Function GetArray(initialize As Boolean) As Integer(,) 
        If initialize Then ReDim arr(10, 10) 
        Return arr.Clone() 
    End Function 

Notice that this pragma must have a nonempty scope.

Also notice that this pragma, like all pragmas that can reference arrays, should be inserted immediately before the Dim statement that declares the array, rather than before the ReDim statement that actually creates the array. Pragmas inserted inside the method where the ReDim statement appears are ignored.

AssumeType type

Informs VB Migration Partner that a given Object, Variant, or Control variable must be translated as if it were of a specific VB6 type. It is useful to correctly solve default properties even in late-bound references. For example, consider the following VB6 code:

    '## ctrl.AssumeType TextBox 
    Dim ctrl As Control 
    
    For Each ctrl In Me.Controls 
        If TypeOf ctrl Is TextBox Then ctrl = "" 
    Next

If it weren’t for the AssumeType pragma, VB Migration Partner wouldn’t know how to convert the reference to the default property:

    Dim ctrl As Object
    
    For Each ctrl In Me.Controls
        If TypeOf ctrl Is VB6TextBox Then ctrl.Text = ""
    Next

Notice that this pragma must have a nonempty scope.

AutoDispose mode

Specifies how fields pointing to disposable objects must be converted. The mode argument can be No, Yes, or Force. If equal to Yes or omitted, all Set x = Nothing statements are converted into calls to the SetNothing6 method; if equal to Force, classes that contain disposable field is marked as IDisposable and all such fields are disposed of in the Dispose method; if equal to No, disposable objects aren’t handled in any special way (this setting represents the default behavior and can be useful to override a pragma with a broader scope). The AutoDispose pragma can be applied to the project, file, class, or individual field or variable level.

    '## Rem force disposal of all disposable objects in current class
    '## Rem except those of the Test method
    '## AutoDispose Force
    '## Test.AutoDispose No

AutoNew boolean

Specifies how auto-instancing object – that is, fields and variables declared with the As New clause – must be converted. By default, such declarations are converted verbatim to VB.NET, even though the VB.NET semantics differs from VB6. If the mode argument is True or omitted, then VB Migration Partner generates code that ensures that the VB.NET is identical to VB6.

    '## Rem ensure that Connection and Recordset objects have auto-instancing semantics 
    '## Connection.AutoNew 
    '## Recordset.AutoNew
    Public Recordset As New ADODB.Recordset
    Public Connection As New ADODB.Recordset

The actual code being generated is different for local variables and fields: if the object is declared as a class-level field, VB Migration Partner converts it into a property whose Get block contains code that implements the auto-instancing behavior; if the object is declared as a local variable, all occurrences are wrapper by AutoNew6 method calls, that ensure that the object is instantiated if necessary.

ChangeType vb6type, nettype

Specifies that all members of a given VB6 type in the pragma’s scope must be converted to a given .NET type. It is useful to convert Variant variables to VB6Variant objects and Control variables to System.Windows.Forms.Control variables (without this pragma, such variables would be migrated as Object variables):

    '## ChangeType Variant, VB6Variant
    '## ChangeType Control, Control

AutoProperty boolean

Specifies whether public fields should be rendered as properties. If the argument is True (or omitted) then all public fields are replaced by a read-write property with same name. For example, the following VB6 code:

    '## AutoProperty
    
    Public Name As String
    Public Widget As New Widget

is rendered as follows:

    Public Property Name() as String
        Get
            Return Name_InnerField
        End Get
        Set(ByVal value As String)
            Name_InnerField = value
        End Set
    End Property

    Private Name_InnerField As String = ""

    Public Property Widget() As Widget
        Get
            If Widget_InnerField Is Nothing Then Widget_InnerField = New Widget()
            Return Widget_InnerField
        End Get
        Set(ByVal value As Widget)
            Widget_InnerField = value
        End Set
    End Property

    Private Widget_InnerField As Widget

Notice that the AutoProperty pragma automatically enforces the auto-instancing (As New) semantics if possible, regardless of whether the variable is under the scope of an AutoNew pragma.

ContainsVariantArray bool

Specifies how arrays contained inside a VB6Variant member should be processed. If the argument is True (or omitted), the array contained inside all the VB6Variant variables under the scope of the pragma is considered to be a Variant array (which has been translated as a VB6Variant array). If False, the contained array is considered as an array of regular objects.

    '## project:ContainsVariantArray

By default, when VB Migration Partner parses a Variant member that is followed by an index and a dot, it assumes that the member contains an array of regular objects. To see why this pragma can be useful, consider the following VB6 code:

    '## ChangeType Variant, VB6Variant
    Sub Test(ByVal arrObj() As Object, ByVal arrVar() As Variant)
        Dim v1 As Variant, v2 As Variant
        V1 = arrObj
        v2 = arrVar
        v1(0).DoSomething
        v2(0).DoSomething
    End Sub

This is how the code is converted to VB.NET if no other pragma is used:

    Sub Test(ByVal arrObj() As Object, ByVal arrVar() As VB6Variant)
        Dim v1 As VB6Variant, v2 As VB6Variant
        V1 = arrObj
        v2 = arrVar
        v1(0).DoSomething    ' << correct
        v2(0).DoSomething    ' << wrong!
    End Sub

The problem in previous code is that the v2 variable contains an array of VB6Variant objects, therefore the reference to v2(0) returns a VB6Variant element which does not expose the DoSomething method. You solve the problem by adding the following pragma inside the Test method:

    '## v2.ContainsVariantArray

which causes the following code to be generated

    v2(0).Value.DoSomething    ' << correct

IMPORTANT:
This pragma has been obsoleted in release 1.11.01. In this and all subsequent releases, the indexing operation on a simple VB6Variant variable always returns a VB6Variant object, therefore VB Migration Partner always appends the “.Value” suffix when the expression is followed by a dot. The ContainsVariantArray pragma is therefore useless and is ignored during the migration process (but no warning is issued).

DeclareImplicitVariables boolean

Specifies whether VB Migration Partner should generate one Dim statement for each local variable that isn’t declared explicitly. If the argument is True or omitted, all local variables in the converted VB.NET methods under the pragma’s scope are declared explicitly.

    '## Rem generate code for implicitly-declared variables in current file
    '## InsertStatement Option Explicit On
    '## DeclareImplicitVariables

FixParamArray maxargs

Specifies whether VB Migration Partner should generate a method overload for methods that take a ParamArray argument and that modify an element of the array argument inside the method. The method overload uses Optional ByRef parameters instead of one single ParamArray parameter, and the maxargs value specifies the maximum number of arguments that you expect. For example, assume that you have the following VB6 code:

    '## FixParamArray 3
    Sub Increment(ParamArray arr() As Variant)
        Dim i As Integer
        For i = 0 To UBound(arr)
            arr(i) = arr(i) + 1
        Next
    End Sub

Notice that the elements of the arr ParamArray array are modified inside the method and these changes are propagated back to callers under VB6 but not under VB.NET. However, the FixParamArray pragma causes the following code to be generated:

    Public Sub Increment(Optional ByRef arr0 As Object = Nothing, _
        Optional ByRef arr1 As Object = Nothing, _
        Optional ByRef arr2 As Object = Nothing)
        
        Dim arr() As Object = GetParamArray6(arr0, arr1, arr2)
        Try
            Increment(arr)
        Finally
            SetParamArray6(arr, arr0, arr1, arr2)
        End Try
    End Sub
    
    Public Sub Increment(ByVal ParamArray arr() As Object)
        Dim i As Short
        For i = 0 To UBound6(arr)
            arr(i) += 1
        Next
    End Sub

The neat effect is that any call to the Increment method that takes 3 arguments or fewer will use the first overload, which ensures that changes to any argument are correctly propagated back to callers even in VB.NET.

If the maxargs argument is 0 or omitted, no overloaded method is generated. (This behavior is useful to override another FixParamArray pragma with broader scope.) Values higher than 20 are rounded down to 20.

InferType mode, includeParams

Specifies whether VB Migration Partner should try to infer the type of the local variables, class fields, functions, and properties that are under the scope of this pragma. The mode argument can be one of the following: No if type inference is disabled; Yes if type inference is enabled only for members that lacks an explicit As Variant clause and for local variables that are implicitly declared; Force if type inference is enabled for all Variant members. The second argument is True if type inference is extended to method parameters.

VB Migration Partner is capable, in most cases, to correctly deduce a less generic data type for Variant local variables, parameters, class fields, functions and properties. This applies both to members that were explicitly declared as Variant and to members that lacked an explicit As clause. To see how this feature works, consider the following VB6 code:

    '## DeclareImplicitVariables True 
    '## InferType Force, True
    
    Private m_Width As Single
    
    Property Get Width () 
        Width = m_Width
    End Property
    
    Property Let Width (value)
        m_Width = value
    End Property
    
    Sub Test(x As Integer, frm)
        Dim v1 As Variant, v2
        v1 = x * 10
        v2 = Width + x
        Set frm = New frmMain
        res = frm.Caption
    End Sub

Here’s the migrated VB.NET code:

    Private m_Width As Single
    
    Public Property Width() As Single
        Get
            Return m_Width
        End Get
        Set(ByVal value As Single)
            m_Width = value
        End Set
    End Property
    
    Public Sub Test(ByRef x As Short, ByRef frm As Form1)
        ' UPGRADE_INFO (#0561): The 'frm' symbol was defined without an explicit "As" clause. 
        ' UPGRADE_INFO (#05B1): The 'res' variable wasn't declared explicitly.
        Dim res As String = Nothing
        Dim v1 As Integer
        ' UPGRADE_INFO (#0561): The 'v2' symbol was defined without an explicit "As" clause.
        Dim v2 As Single
        v1 = x * 10
        v2 = Width + x
        frm = New Form1()
        res = frm.Caption
    End Sub

Extending the pragma scope to method parameters isn’t always a good idea, because the current version of VB Migration Partner infers the type of parameters by looking at assignments inside the method and doesn’t account for implicit assignments that result from method calls. For this reason, the type inferred during the migration process might not be correct in some cases.

Important note:
Type inference isn’t an exact science and you should always double-check that the data type inferred by VB Migration Partner is correct. Even better, we recommend that you use the InferType pragma only during in early migration attempts and then you later assign a specific type to members by editing the original VB6 code or by means of the SetType pragma.

LateBoundMethods methodregex, indexregex, varregex

Specifies which late-bound members should be considered as methods with one or more ByRef arguments. The first methodregex argument is a regular expression that specifies which member names are to be considered as the names of methods with ByRef arguments (use “.+” to indicate “all members”). The second indexregex argument is a regex that identifies all (0-based) numeric indexes of ByRef parameters of indicated methods (if omitted, it defaults to “\d+”, which means “all parameters”). The third parameter is optional and is considered as a regular expression that specifies which Variant and Object fields and variables the pragma applies to (if omitted, it defaults to “.+” and therefore all the fields and variables in the pragma’s scope are affected).

    ' all the late-bound members in current project are to be considered as 
    ' methods that take ByRef arguments
    '## project:LateBoundMethods ".+"

This pragma becomes important in applications that use late-binding quite extensively and accounts for a subtle but important difference between VB6 and VB.NET. Under VB6, passing a writable property to a ByRef parameter of a method does not affect the property (because behind the scenes VB6 is actually passing the return value from the Property Get block). Vice versa, passing a writable property to a ByRef parameter does modify the property value on exiting the method under VB.NET.

Consider the following VB6 code:

    Sub Test(ByRef lbl As Label, ByVal txt As TextBox, ByVal wi As Widget, ByVal obj As Object)
        Set obj = wi
        wi.ModifyValues lbl.Caption, txt.Text
        obj.ModifyValues lbl.Caption, txt.Text
    End Sub

If the ModifyValue in the Widget class takes one ByRef argument, this is how VB Migration Partner translates the code to VB.NET:

    Sub Test(ByRef lbl As VB6Label, ByVal wi As Widget, ByVal obj As Object)
        Set obj = wi
        wi.ModifyValue(ByVal6(lbl.Caption), ByVal6(txt.Text))
        obj.ModifyValue(lbl.Caption, txt.Text)
    End Sub

The ModifyValue method can modify the lbl.Caption and txt.Text writable properties under VB. NET and that this modification would break functional equivalence with the original VB6 code. VB Migration Partner knows how to work around this difference and correctly wraps the two property references inside a ByVal6 method when calling the wi.ModifyValue method.

VB Migration Partner can carry out this correctly because the ModifyValue is referenced using early-binding (i.e. the wi member has a definite type) and it is possible to detect that the lbl.Caption and txt.Text values are being passed to a ByRef parameter. Conversely, the obj.ModifyValue call uses late binding and VB Migration Partner can’t decide whether the called method takes one or more ByRef parameters.

In this scenario you can use the LateBoundProperties pragma to let VB Migration Partner know which late-bound members are to be considered as methods that take one or more ByRef parameters. Here’s how the pragma might be used in this specific example:

    Sub Test(ByRef lbl As Label, ByVal txt As TextBox, ByVal wi As Widget, ByVal obj As Object)
        '## obj.LateBoundMethods "ModifyValues"
        Set obj = wi
        wi.ModifyValues lbl.Caption, txt.Text
        obj.ModifyValues lbl.Caption, txt.Text
    End Sub

which produces the following code:

    Sub Test(ByRef lbl As VB6Label, ByVal wi As Widget, ByVal obj As Object)
        Set obj = wi
        wi.ModifyValue(ByVal6(lbl.Caption), ByVal6(txt.Text))
        obj.ModifyValue(ByVal6(lbl.Caption), ByVal6(txt.Text))
    End Sub

Consider that the pragma’s first argument is actually a regular expression, which allows you to specify multiple methods in just one pragma. (This is necessary because you can associate only one LateBoundMethods pragma to a given variable.) Therefore you might write something like

    '## obj.LateBoundMethods "^(ModifyValues|ProcessInfo)$"

or just assume that all exposed members are to be considered as methods that can modify their arguments:

    '## obj.LateBoundMethods ".+"

The second optional argument of the LateBoundMethods pragma is a regular expression that is applied to the 0-based numeric index of the argument being analyzed. If omitted, this regex defaults to “\d+”, therefore all parameters are considered to be defined with ByRef. For example, if you knew that only the second argument of the Widget.ModifyValues method is defined with ByRef, you can avoid useless ByVal6 insertions using this pragma:

    '## obj.LateBoundMethods "ModifyValues", "^1$"

If just the 2nd and 3rd parameters are defined with ByRef you need this pragma:

    '## obj.LateBoundMethods "ModifyValues", "^(1|2)$"

and so on.
The third argument of the LateBoundMethods pragma allows you to apply the pragma to multiple variables and fields under the pragma’s scope, without having to specify a different pragma for each one of them. For example, consider the following VB6 code:

    Sub Test(ByVal obj As Object, ByVal obj2 As Object, ByVal obj3 As Object)
        Set obj = New Widget
        Set obj2 = New Widget
        Set obj3 = New Person
        obj.ModifyValues lbl.Caption, txt.Text
        obj2.ModifyValues lbl.Caption, txt.Text
        obj3.ModifyValues lbl.Caption, txt.Text
    End Sub

If both the Widget and Person classes expose a ModifyValues method that takes ByRef arguments, you might use the following pragma to affect all of them:

    Sub Test(ByVal obj As Object, ByVal obj2 As  Object, ByVal obj3 As Object)
        '## LateBoundMethods "ModifyValues"
        Set obj = New Widget
        Set obj2 = New Widget
        Set obj3 = New Person
        obj.ModifyValues lbl.Caption, txt.Text
        obj2.ModifyValues lbl.Caption, txt.Text
        obj3.ModifyValues lbl.Caption, txt.Text
    End Sub

However, if you don’t want to apply the pragma to obj3, you would be forced to specify a distinct pragma for obj and obj2. The pragma’s third argument allows you to write more concise code:

    '## LateBoundMethods "ModifyValues", "\d+", "^(obj|obj2)$"

Notice that VB Migration Partner applies the two regular expressions using the Regex.IsMatch method, therefore the following pragma wouldn’t achieve the intended effect:

    '## LateBoundMethods "ModifyValues", "\d+", "(obj|obj2)"

because it would also match the obj3 member name.

If the VB6 code consistently uses a naming convention for its late-bound members, the pragma’s second argument can be quite useful. For example, if all the Variant and Object variables that are meant to store a reference to an ADODB.Connection have a leading “conn” in their name, you might use the following pragma:

    '## project:LateBoundMethods "Execute", "^1$", "^conn"

to indicate that the second argument (i.e. the RecordsAffected argument) of the Execute method can be modified on return from the call.

Finally, you can also change VB Migration Partner’s default behavior by considering all late-bound names as references to methods with ByRef arguments:

    '## project:LateBoundMethods ".+", ".+"

or more simply with

    '## project:LateBoundMethods ".+"

Notice that a LateBoundMethods pragma with a narrow scope shadows all the LateBoundMethods  pragmas at a broader scope. For example, the above project-level pragma doesn’t apply to methods where another LateBoundMethods pragma is defined.

LateBoundProperties propregex, varregex

Specifies which late-bound members should be considered as writable properties. The first propregex argument is a regular expression that specifies which member names are to be considered as the names of writable properties (use “.+” to indicate “all members”). The second parameter is optional and is considered as a regular expression that specifies which Variant and Object fields and variables the pragma applies to (if omitted, it defaults to “.+” and therefore all the fields and variables in the pragma’s scope are affected). This pragma can be applied to the project, file, method, and variable level:

    ' all the late-bound members in current project are to be considered as writable properties
    '## project:LateBoundProperties ".+"

This pragma becomes important in applications that use late-binding quite extensively and accounts for a subtle but important difference between VB6 and VB.NET. Under VB6, passing a writable property to a ByRef parameter of a method does not affect the property (because behind the scenes VB6 is actually passing the return value from the Property Get block). Vice versa, passing a writable property to a ByRef parameter does modify the property value on exiting the method under VB.NET.

Consider the following VB6 code:

    Sub Test(ByVal lbl As Label, ByVal obj As Object)
        DoSomething lbl.Caption, obj.Caption
    End Sub
	
    Sub DoSomething(ByRef str As String)
        str = UCase(str): str2 = UCase(str2)
    End Sub

If no pragma is added, this is how VB Migration Partner translates the code to VB.NET:

    Sub Test(ByVal lbl As VB6Label, ByVal obj  As Object)
        DoSomething(ByVal6(lbl.Caption), obj.Caption)
    End Sub
	
    Sub DoSomething(ByRef str As String, ByRef str2 As String)
        str = UCase(str): str2 = UCase(str2)
    End Sub

As you see, VB Migration Partner knows how to work around this difference and correctly wraps the lbl.Caption property reference inside a ByVal6 method when calling the method. This is possible because the property is referenced using early-binding (i.e. the lbl member has a definite type) VB Migration Partner can detect that a writable property is being passed. Conversely, the obj.Caption member uses late binding and VB Migration Partner can’t decide whether Caption is a reference to a writable property and omits the necessary ByVal6 code.

In this scenario you can use the LateBoundProperties pragma to let VB Migration Partner know which late-bound members are writable properties. In this specific case you might use this pragma

    Sub Test(ByVal lbl As Label, ByVal obj As Object)
        '## obj.LateBoundProperties "Caption"
        DoSomething lbl.Caption, obj.Caption
    End Sub

However, consider that the pragma’s first argument is actually a regular expression, which allows you to specify multiple properties in just one pragma. (This is necessary because you can associate only one LateBoundProperties pragma to a given variable.) Therefore you might write something like

    '## obj.LateBoundProperties "^(Caption|Left|Top|Width|Height)$"

or just assume that all exposed members are to be considered as writable properties:

    '## obj.LateBoundProperties ".+"

The second optional argument of the LateBoundProperties pragma allows you to apply the pragma to multiple members under the pragma’s scope, without having to specify a different pragma for each one of them. For example, consider the following VB6 code:

    Sub Test(ByVal obj As Object, ByVal obj2 As Object, ByVal obj3 As Object)
        DoSomething obj.Caption, obj2.Caption, obj3.Caption
    End Sub

If you can assume that all three parameters represent a control you might use the following pragma to affect all of them:

    Sub Test(ByVal obj As Object, ByVal obj2 As Object, ByVal obj3 As Object)
        '## LateBoundProperties "Caption"
        DoSomething obj.Caption, obj2.Caption, obj3.Caption
    End Sub

However, if you don’t want to apply the pragma to obj3, you would be forced to specify a distinct pragma for obj and obj2. The pragma’s second argument allows you to write more concise code:

    '## LateBoundProperties "Caption", "^(obj|obj2)$"

Notice that VB Migration Partner applies the two regular expressions using the Regex.IsMatch method, therefore the following pragma wouldn’t achieve the intended effect:

    '## LateBoundProperties "Caption", "(obj|obj2)"
because it would also match the obj3 member name.

 

If the VB6 code consistently uses a naming convention for its late-bound members, the pragma’s second argument can be quite useful. For example, if all the Variant and Object variables that are meant to store a reference to an ADODB.Connection have a leading “conn” in their name, you might use the following pragma:

    '## project:LateBoundProperties "(ConnectionString|CursorLocation)", "^conn"

Finally, you can also change VB Migration Partner’s default behavior by having all references to all late-bound members wrapped in ByVal6 method, as follows:

    '## project:LateBoundProperties ".+", ".+"

or more simply with

    '## project:LateBoundProperties ".+"

Notice that a LateBoundProperties pragma with a narrow scope shadows all the LateBoundProperties pragmas at a broader scope. For example, the above project-level pragma doesn’t apply to methods where another LateBoundProperties pragma is defined.

LateBoundVariantMembers propregex, varregex, canReturnEmpty

Specifies which late-bound members should be considered as properties or methods that return a Variant value. The first propregex argument is a regular expression that specifies which member late-bound names can return a Variant value (use “.+” to indicate “all members”). The second parameter is optional and is considered as a regular expression that specifies which Variant and Object fields and variables the pragma applies to (if omitted, it defaults to “.+” and therefore all the fields and variables in the pragma’s scope are affected). The third Boolean parameter is also optional and should be set to True if the Variant being returned can be the special Empty value.

        ' all the late-bound members in current project are to be considered as properties
        ' or methods that can return a Variant value
        '## project:LateBoundProperties ".+"

This pragma can be necessary to prevent a few runtime exceptions when working with VB6Variant values and therefore is always used together with a ChangeType pragma like this one:

        '## project:ChangeType Variant, VB6Variant

If the LateBoundVariantMembers pragma is used, all methods and properties (within the scope of the pragma) invoked in late-bound mode – that is, through an Object or VB6Variant variable – are assumed to return a VB6Variant value. In practice, this pragma causes the invocation to be wrapper inside a CVar6 method in the following cases:

  • The member appears to the left or right of a comparison operator (e.g. = or <> operators)
  • The member appears to the left or right of a math operator, and the other operand isn’t a VB6Variant value
  • The return value from the member is being assigned to an array or an object variable
  • The return value from the member is being assigned to a scalar value (only if pragma’s 3rd argument is True)

MergeInitialization mode

Specifies whether a specific local variable (or all local variables in a method) must be merged with the first statement that assigns it a value. By default, VB Migration Partner merges a variable declaration with its first assignments only if the value being assigned is constant and if the variable isn’t used in any statement after the declaration and before the assignment. You can use this pragma to inform VB Migration Partner that it is safe to do the merge even if the value being assigned isn’t constant. For example, consider this VB6 code:

    Sub Test(value As Integer)
        '## MergeInitialization Force
        Dim x As Integer, y As Integer
        x = value * 2
        y = x * value * 3
        ' ...
    End Sub

The values being assigned aren’t constant, therefore by default VB Migration Partner wouldn’t attempt to merge the declaration and the assignment statements. Thanks to the MergeInitialization pragma, the code generator produces the following code:

    Sub Test(value As Short)
        Dim x As Short = value * 2
        Dim y As Short = x * value * 3
        ' ...
    End Sub

Other possible values for this pragma are No (always disable the merging) or Yes (apply the merging if it is safe to do so). The Yes value represents the default behavior, but this setting can be necessary to override the effect of another MergeInitialization pragma with a broader scope:

    ' Disable initialization merging for all variables except n1
    '## MergeInitialization No
    '## n1.MergeInitialization Yes

Note:
in a method that contains one or more Gosub statements that are converted to separate methods because of a ConvertGosubs pragma, this pragma is ignored and the variable initialization merging feature is disabled.

SetName membername

Specifies whether the current project, class, method, property or variable must have a different name in the converted VB.NET application. It can be useful to avoid name clashes with reserved VB.NET keywords or names of .NET Framework classes and methods. Consider the following VB6 code:

    ' ... (inside the Console VB6 class) 
    '## SetName ConsoleNET 
    '## Id.SetName Identifier 
    Public Id As String 
    
    Sub AddHandler() 
        '## SetName AddEventHandler 
        ' 
    End Sub 
    
    Sub Test() 
        Dim c As New Console 
        c.Id = "abc" 
        c.AddHandler
    End Sub

Here’s how the code inside the Test method is converted to VB.NET:

    Sub Test() 
        Dim c As New ConsoleNET 
        c.Identifier = "abc" 
        c.AddEventHandler() 
    End Sub

ShiftIndexes applytovariables, delta1 [, delta2, delta3]

Specifies whether the indexes of the element of an array should be adjusted by a given value. The applytovariables argument is False if only constant indexes should be adjusted, True if all indexes should be adjusted; delta1 is the value that must be subtracted from the first index; delta2 and delta3 are the values that must be subtracted from the second and third index, respectively.

This pragma is typically used together with the ArrayBounds pragma. Consider the following VB6 code:

    Sub Test()
        '## ArrayBounds Shift 
        '## primes.ShiftIndexes False, 1
        Dim primes(1 To 10) As Integer
        primes(1) = 1: primes(2) = 2: primes(3) = 3: primes(4) = 5: primes(5) = 7
    
        '## powers.ShiftIndexes False, 1
        Dim powers(1 To 10) As Double
        powers(1) = 1
        Dim i As Integer
        For i = LBounds(powers) + 1 To UBound(powers)
            powers(i) = powers(i - 1) * 2
        Next
    End Sub

The ShiftIndexes pragmas ensure that the array elements whose index is constants are scaled by 1 when this code is converted to VB.NET:

    Sub Test()
        Dim primes(9) As Short
        primes(0) = 1: primes(1) = 2: primes(2) = 3: primes(3) = 5: primes(4) = 7
        
        Dim powers(9) As Double
        powers(0) = 1
        Dim i As Short
        For i = LBounds6(powers) + 1 To UBound6(powers)
            powers(i) = powers(i - 1) * 2
        Next
    End Sub

In most cases, the first argument of the ShiftIndexes pragma is False, which prevents this pragma from affecting array elements whose index is a variable or an expressions, as it usually happens inside a loop. However, this isn’t a fixed rule and the value for the applytovariables argument actually depends on how the loop is defined. For example, consider a variations of the above code:

    '## powers.ShiftIndexes True, 1
    Dim powers(1 To 10) As Double
    powers(1) = 1
    Dim i As Integer
    For i = 2 To 10
        powers(i) = powers(i - 1) * 2
    Next

In this case the lower and upper bounds of the loop are constants and aren’t expressed in terms of LBound and UBound functions, therefore you need to pass True in the first argument of the ShiftIndexes pragma to adjust the indexes inside the loop. This is the generated VB.NET code:

    Dim powers(9) As Double
    powers(0) = 1
    Dim i As Short
    For i = 2 To 10
        powers(i - 1) = powers(i - 1 - 1) * 2
    Next

When dealing with a multi-dimensional array you need to pass more than two elements to the ShiftIndexes pragma, as in the following code:

    '## mat.ArrayBounds Shift 
    '## mat.ShiftIndexes False, 1, 2
    Dim mat(1 To 10, 2 To 20) As Double
    mat(1, 2) = 1: mat(2, 3) = 2

which is converted to VB.NET as follows:

    Dim mat(9, 18) As Double
    mat(0, 0) = 1: mat(1, 1) = 2

Finally, notice that the delta values don’t have to be constants, as in this example:

    Sub Test(arr() As Double, firstEl As Integer, lastEl As Integer)
        '## arr.ArrayBounds Shift 
        '## arr.ShiftIndexes True, firstEl
        ReDim arr(firstEl To lastEl) As Double
        arr(firstEl) = 1
    End Sub

which is converted as follows:

    Sub Test(ByRef arr() As Double, ByRef firstEl As Short, ByRef lastEl As Short)
        ReDim arr(lastEl - (firstEl)) As Double
        arr(firstEl - firstEl) = 1
    End Sub

Notice that this pragma, like all pragmas that can reference arrays, should be inserted immediately before the Dim statement that declares the array, rather than before the ReDim statement that actually creates the array. Pragmas inserted inside the method where the ReDim statement appears are ignored.

SetStringSize nnn

Specifies that a fixed-length string must be converted as a VB6FixedString_NNN type instead of the VB6FixedString type. For example, the following VB6 code:

    '## name.SetStringSize 128
    Dim id As String * 20, name * As String * 128

is converted to VB.NET as follows:

    Dim id As New VB6FixedString(20)
    Dim id As New VB6FixedString_128

where the VB6FixedString_128 class is defined in the VisualBasic6.Support.vb file under the My Project folder.

SetType nettype

Specifies that the specified variable, field, property or method must be rendered with a different .NET type. It is useful to specify a type other than Object for Variant and Control variables. For example, the following VB6 code:

    '## m_Name.SetType String 
    '## Name.SetType String
    Private m_Name As Variant
    Property Get Name() As Variant
        Name = m_Name
    End Property

is translated to VB.NET as follows:

    Private m_Name As String
    Public ReadOnly Property Name() As String
        Get
            Return m_Name
        End Get
    End Property

Notice that this pragma must have a nonempty scope.

ThreadSafe Boolean

Specifies whether variables defined in modules must be decorated with the ThreadStatic attribute. This attribute is only useful when migrating VB6 DLLs that are meant to be used by free-threaded .NET clients, for example ASP.NET pages or COM+ server components. It serves to reduce the gap between the Single-Thread Apartment (STA) model used by VB6 and the free-thread model used by .NET:

    '## ThreadSafe
    Public UserName As String

If previous code is inside a BAS module, then VB Migration Partner generates what follows:

    <ThreadStatic()> _
    Public UserName As String

The ThreadStatic attribute forces the VB.NET compiler to allocate the UserName variable in the Thread-Local Storage (TLS) area, so that each thread sees and works with a different instance of the variable. This approach makes free-threading more akin to the STA model and avoid many subtle runtime errors due to concurrency and race conditions between threads.

UseByVal mode

Specifies how to convert by-reference parameters that might be rendered using by-value semantics. The mode argument can be Yes (the ByVal keyword is used for the parameter unless an explicit ByRef keyword is present), Force (the ByVal keyword is used for the parameter, regardless of whether an explicit ByRef keyword is present), No (the parameter is translated as is):

    '## project:UseByVal Yes

If the parameter is omitted, the Yes value is assumed.

UseSystemString boolean

Specifies whether fixed-length strings inside Type…End Type blocks must be converted to VB.NET. If the argument is True or omitted, fixed-length strings inside the pragma’s scope are converted as properties that take or return System.String values.

    '## testudt.UseSystemString

5.4 Pragmas that affect how code is converted/コード変換の仕方に影響を与えるプラグマ

ConvertGosubs boolean, optimize

Specifies whether VB Migration Partner should attempt to convert old-styled Gosubs into calls to separate methods. The first boolean argument is True (or omitted) to enable this conversion; the second Boolean argument is True if you want to optimize the generated code so that parameters of the separate method are declared with ByVal if possible. This pragma can have project-, file-, or method-level scope. For example, consider the following VB6 code:

    Function GetValue(x As Integer) As Integer
        '## ConvertGosubs True
        On Error Resume Next
        
        Dim s As String, name As String
        s = "ABC"
        name = "Code Architects"
        GoSub BuildResult
        Exit Function
    BuildResult:
        GetValue = x + Len(s) + Len(name)
        Return
    End Function

VB Migration Partner detects that the code that begins at the BuildResult label (a.k.a. the target label) can be safely refactored to a separate method, that receives four arguments. The result of the conversion is therefore:

    Public Function GetValue(ByRef x As Short) As Short
        Dim s As String
        Dim name As String
        On Error Resume Next
    	    
        s = "ABC"
        name = "Code Architects"
        Gosub_GetValue_BuildResult(x, GetValue, s, name)
        Exit Function
    End Function
    
    Private Sub Gosub_GetValue_BuildResult(ByRef x As Short, ByRef GetValue As Short, _
        ByRef s As String, ByRef name As String)
        On Error Resume Next
        GetValue = x + Len6(s) + Len6(name)
    End Sub

Notice that the external method contains an On Error Resume Next statement, because the original GetValue method also contains this statement.

All arguments to the new Gosub_GetValue_BuildResult method are passed by reference, so that the caller can receive any value that has been modified inside the method (as is the case with the GetValue parameter in previous example.) You can have VB Migration Partner optimize this passing mechanism and use ByVal if possible by passing True as the second argument to the ConvertGosubs pragma:

    '## ConvertGosubs True, True

If this optimization is used in the above code, the separate method is rendered as follows:

    Private Sub Gosub_GetValue_BuildResult(ByVal x As Short, ByRef GetValue As Short, _
        ByVal s As String, ByVal name As String)
        On Error Resume Next
        GetValue = x + Len6(s) + Len6(name)
    End Sub

If you don’t like the name that VB Migration Partner assigns to the automatically-generated method, you can easily change it by means of a PostProcess pragma:

    '## PostProcess "Gosub_GetValue_BuildResult", "AssignValueResult"

It is important to keep in mind that the conversion of a Gosub block of code into a separate method isn’t always possible. More precisely, VB Migration Partner can perform this conversions only if all the following conditions are met:

    1. The method doesn’t contain any Resume statement. (On Error Resume Next is OK, though).


    1. The target label isn’t located inside a If, Select, For, Do, or Loop block.


    1. The target label isn’t referenced by a Goto, On Goto/Gosub, or On Error statement.


    1. The target label must be preceded by a Goto, Return, End, Or Exit Sub/Function/Property statement.


    1. The code block must terminate with an inconditional Return.


    1. (Blocks that terminate with End Sub/Function/Property or Exit Sub/Function/Property statements aren’t converted.)


    1. The block of code between the target label and the closing Return/End statement doesn’t contain another label.

If a method contains one or more labels that can’t be converted to a separate method, VB Migration Partner still manages to convert the remaining labels. In general, a label can be converted to a separate method if it neither references nor is referenced by a label that can’t be converted (for example, a label that is defined inside an If block or a label that doesn’t end with an unconditional Return statement.)

Note:
in a method that contains one or more Gosub statements that are converted to separate methods, the variable initialization merging feature is disabled.

DefaultMemberSupport boolean

Specifies whether VB Migration Partner must wrap references to default members inside calls to the special GetDefaultMember6 and SetDefaultMember6 methods defined in the language support library:

    '## Rem enable default member support for this class, except for the Test member
    '## DefaultMemberSupport
    '## Test.DefaultMemberSupport False

FixRemarks boolean

Specifies how VB Migration Partner must convert VB6 remarks that start with three consecutive apostrophes. By default they are prefixed by an additional apostrophe+space, so that the VB.NET compiler doesn’t mistakenly interpret them as XML remarks. You can use False for the argument to disable such automatic fix, which can be useful if you decide to insert VB.NET XML remarks right in the VB6 code:

    '## project:FixRemarks False

LogicalOps boolean

Specifies whether And and Or VB6 keywords must be translated to AndAlso and OrElse VB.NET keywords. For example, the following code:

    Sub Test(ByVal x As Integer) 
        '## LogicalOps True 
        If x < 0 And x > 100 Then Err.Raise 9 
        ' ... 
    End Sub

The pragma can have project, class, and method scope, and can issued multiple times inside the same method, to selectively enable and disable this feature. For example, this VB6 code:

    '## LogicalOps True 
    If x > 0 Or (x = 0 And y < 0) Then … 
    '## LogicalOps False 
    If x1 > 0 Or (x1 = 0 And y1 < 0) Then …

translates to:

    If x > 0 OrElse (x = 0 AndAlso y < 0) Then … 
    If x1 > 0 Or (x1 = 0 And y1 < 0) Then …

MergeIfs boolean, includeParens

Specifies whether two or more nested Ifs are automatically merged into a single statement by means of an AndAlso operator. This pragma can have project, class, and method scope. The first argument can be True (default if omitted) or False, where the latter value can be used to override another pragma with broader scope. The includeParens optional argument is True (default if omitted) if you want to enclose individual expressions within parenthesis, or False to drop these parenthesis.

For example, consider the following code

    Sub Test(ByVal obj As Object, ByVal obj2 As Object)
        '## MergeIfs True
        If Not obj Is Nothing Then
            If obj.Text = "" Then Debug.Print "Empty Text"
        End If
    
        If Not obj Is Nothing Then 
            If Not obj2 Is Nothing Then
                If obj.Text = obj2.Text Then Debug.Print "Same text"
            End If
        End If
    End Sub

This is how VB Migration Partner translates it to VB.NET

    Sub Test(ByVal obj As Object, ByVal obj2 As Object)
        ' UPGRADE_INFO (#0581): Two nested If...End If blocks have been merged.
        If (Not obj Is Nothing) AndAlso (obj.Text = "") Then
            Debug.WriteLine("Empty Text")
        End If
        
        ' UPGRADE_INFO (#0581): Three nested If...End If blocks have been merged.
        If (Not obj Is Nothing) AndAlso (Not obj2 Is Nothing) AndAlso (obj.Text = obj2.Text) Then
            Debug.WriteLine("Same text")
        End If
    End Sub

You can further simplify the expression by dropping the parenthesis around each subexpressions, by using the following pragma:

    '## MergeIfs True, False

Notice that this optimization is disabled if there are one or more special pragmas between the two IF statements, including InsertStatement, ReplaceStatement, PreInclude and PostInclude.

NullSupport boolean

Specifies whether VB Migration Partner must generate code that provides better support for null propagation in expressions. For example, consider the following VB6 code:

    '## NullSupport
    Sub Test(name As Variant, city As Variant)
        name = UCase(name) + Trim(city)
    End Sub

and its VB.NET translation

    Sub Test(ByRef name As Object, ByRef city As Object)
        name = UCase6(name) + Trim6(city)
    End Sub

Methods affected by this pragma are: Chr, CurDir, Environ, Error, Hex, LCase, LTrim, Mid, Oct, Right, RTrim, Space, and UCase. The corresponding method in the language support library has same name plus a “6” suffix.

PreInclude includefile

Includes a text file before the parsing process begins. The argument is the path to the text file that contains the text to be included. (It can be an absolute path or a path relative to the folder that contains the .vbp project file.). The argument never needs to be included in double quotes:

    '## PreInclude c:\includes\copyright.txt

If the includefile argument points to a non-existing file, no text is included and no migration warning is generated. The PreInclude pragma supports recursion, in the sense that the file being included can contain additional PreInclude pragmas, up to any nesting level. VB Migration Partner doesn’t allow circular references among include files.

Keep in mind that you typically can’t use this pragma to include a standard CLS or BAS file, because such VB6 files contains hidden text and attributes that would be included in the wrong position and might deliver unexpected results or even crash VB Migration Partner. You use this pragma at your own risk.

A good use for this pragma is as a simple way for multiple project to share the same set of project-level pragmas. For example, let’s assume that you have to migrate ten VB6 projects that require the same set of PostProcess pragmas. Instead of copying the pragma text in each and every project, you can gather them in a text file and reference the text from inside any source file in each project:

    '## PreInclude c:\code\pragmas.txt

Notice, however, that in this specific case, the pragma.txt file can’t contain the special pragmas that must be parsed before the project itself and that are necessarily to be stored in the VBMigrationPartner.pragmas file. However, quite conveniently PreInclude pragmas are honored even inside *.pragmas files, therefore each folder might contain a VBMigrationPartner.pragmas file that contains only one line containing the PreInclude pragma pointing to the text file that contains the actual pragmas that are shared among multiple projects.

PreProcess searchpattern, replacepattern, ignorecase, applytohiddencode, regionpattern

Applies a replace regular expression to the VB6 code before it is parsed. The first argument is the search regex pattern string. The second argument is the replace regex pattern and can reference match groups defined in the search pattern; it abides to the same syntax rules as the Regex.Replace method but it also recognizes character sequences such as \n (newline), \r (carriage return) and \t (tab). Backslash characters in the replace regex must be doubled (as in \\). The third argument is a Boolean value that specifies whether searches are case insensitive (if omitted, it defaults to True). The fourth argument is True if this pragma applies also to the .vbp file and to the hidden portion of an .frm or .ctl file, False (or omitted) if it applies only to the VB6 code that you see inside the code editor. The fifth argument is an optional regex pattern that can be used to precisely indicate the code regions to which the search pattern must be applied.

For example, the following pragma pre-processes the VB6 code and converts all OLE_COLOR variables into plain Long variables:

    '## PreProcess "As OLE_COLOR\b", "As Long"

The following pragma renames a button named “AddHandler” into “btnAddHandler”, to avoid the problem caused by AddHandler being a reserved VB.NET keyword. In this case it is necessary to apply the pragma to the hidden portion of the file and to account for event names, where the control’s name is followed by an underscore

    '## PreProcess "(\bAddHandler\b|(? < =\bSub\s+)AddHandler(?=_))", "btnAddHandler", True, True

The following example uses the optional regionpattern argument to restrict the action of the PreProcess pragma to Sub methods only:

    '## PreProcess "Dim ctrl As Control", "Dim ctrl As Object", False, _
            False, "\bSub\b.+?\bEnd Sub\b"

Notice that the last argument uses the .+? pattern to ensure that the search region doesn’t extend to more than one method at a time.

You can apply this pragma at the project-level only by storing it in a *.pragmas file – for example, in the Widgets.vbp.pragmas file for all the files in the Widgets.vbp project. An important note: this pragma can’t have a project: prefix: if the pragma appears in a source file it is implicitly scoped at the file level; if it appears in a *.pragmas file, it is implicitly scoped at the project level.

PostInclude includefile

Includes a text file after the conversion process has been completed. The argument is the path to the text file that contains the text to be included. (It can be an absolute path or a path relative to the folder that contains the .vbp project file.). The argument never needs to be included in double quotes:

    '## PreInclude c:\includes\copyright.txt

If the includefile argument points to a non-existing file, no text is included and no migration warning is generated. The PostInclude pragma supports recursion, in the sense that the file being included can contain additional PostInclude pragmas, up to any nesting level. VB Migration Partner doesn’t allow circular references among include files.

A good use for this pragma is to add one or more methods or classes to the resulting VB.NET code.

PostProcess searchpattern, replacepattern, ignorecase, applytohiddenfiles, regionpattern

Applies a replace regular expression to the VB.NET code generated by the migration process. The first argument is the search regex pattern string. The second argument is the replace regex pattern and can reference match groups defined in the search pattern; it abides to the same syntax rules as the Regex.Replace method but it also recognizes character sequences such as \n (newline), \r (carriage return) and \t (tab). Backslash characters in the replace regex must be doubled (as in \\). The third argument is a Boolean value that specifies whether searches are case insensitive (if omitted, it defaults to True). The fourth argument specifies whether the PostProcess pragma applies only to “hidden” files such as AssemblyInfo.vb and *.vbproj files (if omitted, it defaults to False and the pragma applies only to standard *.vb files, including *.Designer.vb files). The fifth argument is an optional regex pattern that can be used to precisely indicate the code regions to which the search pattern must be applied.

For example, the following pragma changes the base form for the converted application:

    '## project:PostProcess "Inherits CodeArchitects.VB6Library.VB6Form", _
        "Inherits AppFramework.FormBase", False, True

The search pattern can include match groups and you can reference these search groups in the replacement pattern. For example, the following pragma moves the declaration of the controlling variable into a For Each loop, if the variable is defined immediately before the loop:

    '## PostProcess "Dim (?< name > \w+) As (?< type> \w+)( = .+)?\s+For Each \k< name > In", _
        "For Each ${name} As ${type} In"

The following example is similar to previous one, except it uses the optional regionpattern argument to restrict the action of the PostProcess pragma only to Function methods named GetArray and GetString:

    '## PostProcess  "Dim (?< name> \w+) As (?< type > \w+)( = .+)?\s+For Each \k < name > In", _
                     "For Each ${name} As ${type} In", False, False, _
                     "\bFunction (GetArray|GetString)\b.+?\bEnd Function\b"

Notice that the last argument uses the .+? pattern to ensure that the search region doesn’t extend to more than one function at a time.

PreservePropertyAssignmentKind mode

Specifies whether VB Migration Partner must take additional cure when converting custom properties. If Yes (or omitted) the pragma applies only to properties whose definition contains both a Property Let and a Property Set; if Force it applies to all properties that have a Property Let block, even if the Property Set block is missing. In all cases, the pragma applies only to properties whose Let block specifies a non-scalar data type.

        '## DataResult.PreservePropertyAssignmentKind Yes 

To understand when this pragma can be necessary, let’s consider the following VB6 code:

        Private m_MyData As Variant

        Property Get MyData() As Variant
            If Not IsObject(m_MyData) Then
                MyData = m_MyData
            Else
                Set MyData = m_MyData
            End If
        End Property
		
        Property Let MyData(ByVal newValue As Variant)
            m_MyData = newValue
            ProcessDataValue newValue   ' (ProcessDataValue is defined elsewhere)
        End Property

        Property Set MyData(ByVal newValue As Variant)
            Set m_MyData = newValue
        End Property

        Sub Main()
            Dim rs As New  ADODB.Recordset, par As New ADODB.Parameter 
            ' ... init the recordset here 
            MyData = par
            Set MyData = par
            ' ... 
            MyData = rs
            Set MyData = rs 
        End Sub 

This is how VB Migration Partner usually converts the above code:

        Private m_MyData As Object

        Property MyData() As Object
            Get
                ' *** VB Migration Partner has simplified this code 
                Return m_MyData 
            End Get		
            Set(ByVal newValue As Object)
                If Not IsObject6(newValue) Then
                    m_MyData = newValue
                    ProcessDataValue(newValue)      ' (ProcessDataValue is defined elsewhere)
                Else
                    m_MyData = newValue
                End If
            End Set
        End Property
  
        Sub Main()
            Dim rs As New ADODB.Recordset
            ' ... init the recordset here
            MyData = par.Value   ' ** resolution of default property
            MyData = par
            ' ...
            MyData = rs.Fields   ' ** resolution of default property
            MyData = rs
        End Sub

Notice that VB Migration Partner expands par into par.Value and rs into rs.Fields when the assignment to the MyData property lacks the Set keyword. While the two cases seem similar, they aren’t. The key different is that the ADODB.Parameter’s default property (Value) is a scalar value (a string, a number, a date, etc.) whereas the ADODB.Recordset’s default property (Fields) is an object.

When par.Value is assigned to the MyData property, the following statement

        If Not IsObject6(newValue) Then

recognizes that it’s a scalar and executes the code block that was originally in the Property Let procedure (and therefore the ProcessDataValue method is correctly invoked). However, when rs.Fields is assigned to the MyData property, the test in the If statement finds that it’s not a scalar and mistakenly executes the code block that was originally in the Property Set procedure. As a result, the ProcessDataValue method isn’t invoked as it should have been.

(You can also omit the argument, because Yes is the default). You can solve this problem by applying the PreservePropertyAssignmentKind pragma to the MyData property, as follows:

        '## MyData.PreservePropertyAssignmentKind Yes

In this case VB Migration Partner generates the following VB.NET code:

        Private m_MyData As Object
        Property MyData(ByVal Optional _assignmentKind As PropertyAssignmentKind _
                     = PropertyAssignmentKind.Let) As Object
            Get
                ' *** VB Migration Partner has simplified this code
                Return m_MyData
            End Get
            Set(ByVal newValue As Object)
                If _assignmentMode = PropertyAssignmentKind.Let Then
                    m_MyData = newValue
                    ProcessDataValue(newValue)    ' (ProcessDataValue is defined elsewhere)
                Else
                    m_MyData = newValue
                End If
            End Set
        End Property
		
        Sub Main()
            Dim rs As New ADODB.Recordset
            ' ... init the recordset here
            MyData = par        ' ** no resolution of default property
            MyData(PropertyAssignmentKind.Set) = par
            ' ...
            MyData = rs         ' ** no resolution of default property
            MyData(PropertyAssignmentKind.Set) = rs
        End Sub

In this new version the task of determining whether the original assignment was performed by means of a Let or a Set is carried out by means of the _assignmentMode parameter. Being optional, the parameter is omitted when assigning using a “let” and is used only in “set” assignments, which helps generating less cluttered code.

Notice that when this pragma is used, the default property isn’t expanded any longer and the newValue parameter receives the actual object being assigned, not its default property. This is exactly what the happens in VB6.

By default, the pragma applies only to properties that have both a Property Let and a Property Set pragma. However, if you use Force as an argument, the pragma applies also to properties that have only the Property Let block (provided that the parameter for such block is Variant or a non-scalar type). In this case the PropertyAssignmentKind argument is generated but never used, and the pragma only has the effect of preventing VB Migration Partner from generating.

SetOption optionname, boolean

Specifies a code generation option, depending on the argument passed in the first argument. Supported options are:

VariantContainsArray:
VB Migration Partner assumes that VB6Variant variables under the scope of this pragma may contain an array; as a result, when passing a VB6Variant variable to a ByVal VB6Variant parameter, the variable is wrapped in a CVar6 method, to ensure that the inner array is correctly cloned.

FixedStringsAsStructures:
VB Migration Partner generates one member named “VB6FixedString_NNN” (where NNN is a number) for each fixed-length string that is used inside an array. By default such members are generated as classes, but if this parameter is True or omitted then the member is rendered as a strictire. (This option has been introduced in version 1.23 to preserve compatibility with older versions, which rendered those members as classes.) This option is always applied to the entire project, regardless of the specified scope.

RemarkMethodBody:
VB Migration Partner remarks out all the statements inside all properties and methods under the scope of this pragma, so that you can correctly resolve property/method references without having to fix individual statements that cause a compilation error. This pragma is especially useful to incrementally migrate large VB6 projects, one file at a time.  You can specify this pragma at the project, file, and method level. (If applied at the variable level, this pragma is ignored.)

For example, the following pragmas force VB Migration Partner to generate fixed-length strings as structures and to remark all statements in all methods in the current project. Notice that you can omit the second argument if it is True:

        '## project:SetOption FixedStringsAsStructures, True
        '## project:SetOption RemarkMethodBody

ExcludeMethodBody:
VB Migration Partner excludes all statements inside methods and property procedures when parting the VB6 source code, but not method and property signatures (so that it can correctly resolve all references). This pragma is especially useful to incrementally migrate very large VB6 projects, one file at a time, to speed up the migration process of large files, and to avoid out-of-memory errors during the migration process.  You can specify this pragma at the project, file, and method level. (If applied at the variable level, this pragma is ignored.)

For example, the following pragmas force VB Migration Partner to exclude statements in all methods in the current project. Notice that you can omit the second argument if it is True:

        '## project:SetOption ExcludeMethodBody

When applied at the project level, the SetOption ExcludeMethodBody pragma must be included in a *.pragmas file.


UseTryCatch boolean, maxExecLines

Specifies whether VB Migration Partner should attempt to convert error-handling code inside a method by means of structured error handling based on the Try…Catch block. The first optional argument can be True (or omitted) if you want to use structured exception handling, or False to suppress this feature (can be useful to override a UseTryCatch pragma with a broader scope. The second optional argument maxExecLines is the max number of executable statements in a method that contains an On Error Resume Next statement (default value is 2).

Here’s an example of this pragma:

    Sub Test()
        '## UseTryCatch
        On Error Goto ErrorHandler
        ' method body
     ErrorHandler:
        ' error handler
     End Sub

This is how the code is translated to VB.NET:

    Sub Test()
        Try
            ' IGNORED: On Error Goto ErrorHandler 
            ' method body
        Catch _ex As Exception
            ' IGNORED: ErrorHandler: 
            ' error handler
        End Try
    End Sub

The Try…Catch block can be inserted only if the following conditions are all true:

    1. The method contains only a single On Error GoTo < label > method.


    1. The On Error GoTo < label > statement doesn’t appear inside a conditional block such as If, For, Select Case, and isn’t preceded by a GoTo statement.


    1. The method doesn’t contain GoSub, Resume, or Resume Next statements. (Resume < label > statements are acceptable, though)


    1. There is no Goto statement in the method body that points to a label that is defined in the error handler. (Notice that it is ok if a GoTo in the error handler points to a label defined in the method body.)


    1. If the method contains one or more On Error Goto 0 statements, such statements must immediately precede a statement that causes exiting from the current method, e.g. Exit Sub or End Function.


    1. If the current method is a Property Let procedure, there must not be a Property Set procedure for the same property. Likewise, If the current method is a Property Set procedure, there must not be a Property Let procedure for the same property.


    1. The execution flow is such that it can enter the error handler only when an error occurs, which means that the label the precedes the error handler must not be the target of a GoTo statement in method body and the statement that precedes the error handler must be an Exit Sub/Function keyword or a Goto statement, so that execution cannot “flow” into the error handler from the method body.

For example, the following VB6 code:

    Sub Test()
        '## UseTryCatch
        On Error Goto ErrorHandler
        ' method body
        If x > 0 Then GoTo ErrorHandler2
    
    ErrorHandler:
        ' error handler
    ErrorHandler2:
        ' do something here
    End Sub

can’t be converted to VB.NET using a Try-Catch block because a GoTo statement in the method body points to a label that is defined in the error handler.

By default, VB Migration Partner inserts a Try-Catch also if the method contains the On Error Resume Next statement plus another executable statement. For example, the following VB6 code:

    Function Reciprocal(ByVal x As Double) As Double
        '## UseTryCatch True
        On Error Resume Next
        Reciprocal = 1 / x
        ' returns zero if an error occurs (e.g. X is zero)
    End Function

contains only two executable statements (including On Error Resume Next) and is converted to:

    Function Reciprocal(ByVal x As Double) As Double
        Try
            Return 1 / x
            ' returns zero if an error occurs (e.g. X is zero)
        Catch
            ' Do nothing if an error occurs
        End Try
    End Function

Methods with three or more executable statements can be converted using Try Catch if you specify a value higher than 2 in the second argument for the UseTryCatch pragma. For example, all methods with up to 5 executable statements under the scope of the following pragma:

    '## UseTryCatch True, 5

are converted using a Try-Catch block.

Important Note:
the UseTryCatch pragma can be used together with the AutoDispose Force pragma, in which case VB Migration Partner generates a complete Try-Catch-Finally block. However, for the VB.NET code to be perfectly equivalent to the original VB6 code it is essential that the On Error Goto statement be located at the very top of the method body.

WrapDeclareWithCallbacks boolean

Specifies whether VB Migration Partner must generate additional code to ensure that delegate objects passed to Declare statements aren’t orphaned during garbage collections:

    '## project:WrapDeclareWithCallbacks True

5.5 Pragmas that affect forms and controls/フォームとコントロールに影響を与えるプラグマ

BringToFront

Changes the z-order of a control and brings it in front of all other controls. This pragma can be only scoped at the control level. When using this pragma for two or more controls on the same form, the last control becomes the topmost control:

    '## Rem bring the ListView1 in front of all other controls, except Text1
    '## ListView1.BringToFront
    '## Text1.BringToFront

ChangeProperty propertyname, newvalue [, controltype] [, controlname]

Modifies the value of a given property for all occurrences of a control of given name or type. The propertyname argument is the name of the property to be affected, newvalue is the new property value.  The controltype argument is a regex that identifies the type of the controls to be affected and must match the complete name of the control’s type (e.g. “VB.TextBox”); if omitted, controls are affected regardless of their type. The controlname argument is a regex that identifies the name of the controls to be affected by the pragma; if omitted, all controls are affected regardless of their name. The propertyname, controltype, and controlname arguments are case-insensitive.

The pragma can have project or form project, therefore a single pragma can affect controls that are hosted in different forms; because the first two arguments are regexes, a single pragma can affect multiple controls of same or different type.

    '## Rem all command buttons in current form  whose name begins with "cmd" must be 400 twips high
    '## ChangeProperty Height, 400, "VB\.CommandButton", "cmd.+"

    '## Rem reset the Text property of all TextBox controls in all forms
    '## project:ChangeProperty Text, "", "VB\.TextBox"

The name of controls that belong to a control array include the index between parenthesis:

    '## Rem reset the Text property for all the elements of the "txtFields" control array
    '## ChangeProperty Text, "", "VB\.TextBox", "txtFields\(\d+\)"

You can also perform math operations on the current property value, by prefixing the newvalue argument with the +, -, *, /, \ symbols:

    '## Rem expand the width of all command buttons in current form by 200 twips
    '## ChangeProperty Width, +200, "VB\.CommandButton"
	
    '## Rem ensure that all textboxes on current form are multilined and double their height
    '## ChangeProperty Height, *2, "VB\.TextBox"

The newvalue argument can be preceded by the “=” symbol, which allows you to set a negative value for a numeric property or to assign a string property that begins with a math symbol:

    '## Rem set the ListIndex property to -1 for all ListBox controls
    '## ChangeProperty ListIndex, =-1, "VB\.ListBox"
	
    '## Rem set the Caption property to "+1" for controls named "lblIncr" or "cmdIncr"
    '## project:ChangeProperty Caption, "=+1", , "(lblIncr|cmdIncr)"

FormFont fontname [,fontsize]

Set the default font for a specific form or (if the pragma has project scope) all the forms in the application. The fontname argument is the name of the form (embedded in double quotes if contains spaces), the optional fontsize argument is the size of the font:

    '## Rem set the default font for forms that don’t define a custom font
    '## project:FormFont Arial, 10

This pragma allows you to specify a different default font for forms; it affects only fonts that use the default font and don’t specify a specific font. If the fontsize argument is omitted, the original font size is retained.

KeepObsoleteProperties boolean

Specifies whether VB Migration Partner should discard assign design-time assignments to properties that aren’t supported under VB.NET. Such properties are marked as obsolete in the control language library and, by default, they aren’t included in the converted project. If the argument is True or omitted, assignments to these properties are preserved in the converted VB.NET project:

    '##  KeepObsoleteProperties True

You can scope this pragma at the project, file, and individual control level. This pragma can be useful to browse all the properties that are usually discarded during the migration process.

ReplaceFont oldfontname, newfontname

Replace all occurrences of a font with another font, for all controls in current form or in all forms in current project (depending on the pragma’s scope):

    '## Rem replace all occurrences of MS Sans Serif with Helvetica font
    '## project:ReplaceFont "MS Sans Serif", "Helvetica"

VB.NET doesn’t support system fonts, a group which includes the following fonts: Courier, Fixedsys, Modern, MS Sans Serif, MS Serif, Roman, Script, Small Fonts, System, and Terminal. Because of this limitation, VB Migration Partner converts Courier and Fixedsys fonts to Courier New and all other fonts to Arial, while preserving the font size. You can use this pragma to enforce a different substitution schema.

ReplaceFontSize oldfontname, oldfontsize, newfontname, newfontsize

Replaces all occurrences of a font/size combination with a different font/size combination, for all controls in current form or in all forms in current project (depending on the pragma’s scope):

    '## Rem replace all occurrences of MS Sans Serif 12 with Helvetica 10 font
    '## project:ReplaceFont "MS Sans Serif", 12, "Helvetica", 10

See the ReplaceFont pragma for more information on the automatic font replacement mechanism that VB Migration adopts.

SendToBack

Changes the z-order of a control and sends it behind all other controls. This pragma can be only scoped at the control level. When using this pragma for two or more controls on the same form, the first control becomes the bottommost control:

    '## Rem send the ListView1 behind all other controls, except Text1
    '## Text1.BringToFront
    '## ListView1.BringToFront

WriteProperty propertyname, value

Assigns a design-time property to the current form or to a specific control:

    '## Rem change the caption of current form
    '## WriteProperty Text, ".NET Framework options"
    '## Rem set the  DTPicker1.Format property equal to 2
    '## DTPicker1.WriteProperty Format, 2

This pragma is useful in many cases, for example to manually assign a control property that VB Migration Partner can’t migrate correctly (as is the case of the DTPicker’s Format property) or to purposely introduce minor differences between the VB6 and VB.NET applications.


5.6 Pragmas that affect user controls/ユーザコントロールに影響を与えるプラグマ

TranslateProperties propertylist

Specifies a list of properties that have a different name in the .frm file. The propertylist argument is a comma-delimited list of oldname=newname pairs, as in this example:

    '## TranslateProperties "FC=ForeColor,BC=BackColor"

When storing properties in a .frm file, VB6 doesn’t necessarily use the property name; more precisely, the actual name used in the .frm file is equal to the name specified when saving the value in the WriteProperties event handler. If the name specified in the event handler is different from the property name, you should use this pragma to tell VB Migration Partner which name is used in .frm files.

This pragma can’t have a scope prefix and is implicitly scoped at the file level. It is ignored if it appears in a VB6 file other than a .ctl (user control ) class.

TranslateEvents eventlist

Specifies a list of events that must be renamed when migrating a UserControl class. The eventlist argument is a comma-delimited list of oldname=newname pairs, as in this example:

    '## TranslateEvents "KeyPress=KeyPress6,KeyDown=KeyDown6,KeyUp=KeyUp6"

When this pragma is used, VB Migration Partner marks the converted UserControl class with a TranslateEvents attribute. In turn, this attribute is taken into account when VB Migration Partner converts any VB6 form that contains one or more instances of the user control. Renaming an event is sometimes necessary because the original name used under VB6 conflicts with events exposed by the .NET UserControl class.

This pragma can’t have a scope prefix and is implicitly scoped at the file level. It is ignored if it appears in a VB6 file other than a .ctl (user control ) class.

IgnoreMembers memberlist

Specifies a list of properties and methods that should be ignored when translating a VB6 user control. The memberlist argument is a pipe-delimited list of member names:

    '## IgnoreMembers "Appearance|Bindings|CompanyName"

This pragma can’t have a scope prefix and is implicitly scoped at the file level. It is ignored if it appears in a VB6 file other than a .ctl (user control ) class.


5.7 Pragmas that insert or modify code/コードを挿入または変更するプラグマ

Note:
This group of pragmas allow you to control how VB Migration Partner parses VB6 statements or outputs VB.NET code. None of these pragmas can have a scope, because they have an immediate effect on the code that follows.

InsertStatement code

Inserts a statement in the converted application. The code argument is an (unquoted) string that represents a valid VB.NET statement (or statements):

    '## InsertStatement MsgBox6("End of  processing"): Exit Sub

Note text

Inserts an UPGRADE_NOTE remark in the converted VB.NET:

    '## Note Double-check following statement
    x =  Abs(y) Mod y

OutputMode mode [,count]

Sets VB Migration Partner’s output mode. The mode argument can be one of the following: On (enables code generation), Off (disable code generation), Remarks (generate remarked out code)), Uncomment (removes a leading apostrophe). The count argument is the number of VB.NET statements affected by this pragma; if zero or omitted, the effect extends to the next OutputMode pragma:

    '## Rem don’t output the next line (two statements, counting the remark) 
    '## OutputMode Off, 2 
    PrintReport  "Products", 1, 10    ' print pages 1-10 of the Products Report 
    
    '## Rem don’t output the next method 
    '## OutputMode Off
    Private Sub TestReport() 
        ' ... (any number of lines here) ' ... 
    End Sub  
    '## OutputMode On

The Uncomment setting is especially useful for including a portion of VB.NET code that doesn’t exist in the original VB6 project:

   	'## OutputMode Uncomment
   	'' This is a piece of VB.NET code
   	'Debug.Print("x={0}", x)
   	' ...
   	' ...
   	'## OutputMode On
   	

ParseMode mode [,count]

Sets VB Migration Partner’s parsing mode. The mode argument can be one of the following: On (enables parsing), Off (disable parsing), Remarks (consider next statements as remarks). The count argument is the number of VB6 statements affected by this pragma; if zero or omitted, the effect extends to the next ParseMode pragma:

    '## Rem don’t parse the next line (two statements, counting the remark) 
    '## ParseMode Off, 2 
    PrintReport  "Products", 1, 10    ' print pages 1-10 of the Products Report 
    '## Rem don’t parse the next method 
    '## ParseMode Off
    
    Private Sub TestReport() 
        ' ... (any number of lines here) ' ... 
    End Sub  
    '## ParseMode On

Notice the subtle difference between OutputMode and ParseMode pragmas. If parsing is enabled when a variable or method is parsed, VB Migration Partner creates a symbol for that method and correctly solves all references to it; if parsing is disabled, no symbol can be created, which prevents VB Migration Partner from correctly resolving references to that symbol.

If you don’t want to include a VB6 member in the VB.NET program, in most cases it is preferable to have VB Migration Partner parse the symbol and then use an OutputMode pragma to omit it during the code generation phase.

ParseReplace vb6code

Replace the following line of VB6 code with a different line. The replacement is performed before the parsing takes place, therefore you can use this pragma to change the way a method is declared, the scope of a variable, and so forth:

    '## ParseReplace Sub Test(Optional Byval arg As Integer = -1)
    Sub Test()

Notice that this pragma replaces an entire line of code, therefore it can replace multiple statements if the next line contains multiple statements. It can even replace a portion of a statement if the next line has a trailing underscore.

Rem text

Inserts a remark in the VB6 source code that won’t be translated to VB.NET. This pragma is useful to explain what other pragmas do:

    '## Rem we use the Shift option to preserve number of array elements
    '## arr.ArrayBounds Shift
    Dim arr(1 To 10) As Integer

RemoveUnreachableCode mode

Determines how unreachable code blocks are processed. The mode argument can be one of the following three values: Off (unreachable code is left in the generated VB.NET code, the default behavior), On or omitted (unreachable code is removed from the generated VB.NET code), Remarks (unreachable code is remarked out.) Consider the following VB6 code:

    '## RemoveUnreachableCode Remarks
    Sub Test(x As Long, y As Long)
        x = 123
        Exit Sub
        x = 456
        y = 789
    End Sub

This is the VB.NET code that VB Migration Partner generates:

    Sub Test(ByRef x As Integer, ByRef y As Integer)
        x = 123
        Exit Sub
        '## UPGRADE INFO (#06F1): Unreachable code removed 
        ' EXCLUDED: x = 456 
        ' EXCLUDED: y = 789
    End Sub

If the VB6 code had included the followed pragma:

    '## RemoveUnreachableCode On

then the result would have been as follows:

    Sub Test(ByRef x As Integer, ByRef y As Integer)
        x = 123
        Exit Sub
        '## UPGRADE INFO (#06F1): Unreachable code removed
    End Sub

Notice that current version of VB Migration Partner might, under some conditions, fail to recognize a piece of code as unreachable. This happens, for example, when a label is referenced by a piece of code that is unreachable. Consider the following code snippet

    Sub Test(ByRef x As Integer, ByRef y As Integer)
        x = 123
        Exit Sub
    Restart:
        ' ...
        If x = 10 Then Goto Restart
    End Sub

The block of code between Exit Sub and End Sub is unreachable and should be removed. However, the Restart label is referenced by the GoTo statement in the unreachable portion of the method, and this detail cheats VB Migration Partner into believing that the label is indeed reachable. We are aware of this limitation and hope to work around it in a future release of the tool.

RemoveUnusedMembers removeMode, safeMode

Determines how unused members blocks are processed. The first argument can be one of the following three values: Off (unused members are left in the generated VB.NET code, the default behavior), On or omitted (unused members are removed from the generated VB.NET code), Remarks (unused members are remarked out.) The second argument is True if the pragma must affect only members that can’t be reached via late binding. Consider the following VB6 code:

    Const UnusedValue As Integer = 1

If the constant is never referenced, VB Migration Partner generates the following message:

    ' UPGRADE_INFO (#0501): The 'UnusedValue' member isn’t used anywhere in current application
    Const UnusedValue As Integer = 1

If you use a RemoveUnusedMembers pragma, the message is different. For example:

    '## RemoveUnusedMembers Remarks
    Const UnusedValue As Integer = 1

generates this VB.NET code:

    ' UPGRADE_INFO (#0701): The 'UnusedValue' member has been remobed because 
    ' isn't used anywhere in current application
    ' EXCLUDED: Const UnusedValue As Integer = 1

If the On option is used, the warning message is emitted but the member itself is removed. You need a DisableMessage pragma to drop the warning.

When applied to methods, the RemoveUnusedMembers pragma used with the Remarks disables a few other refactoring features, for example the ConvertGosubs pragma. In other words, if the following pragmas are active:

    '## RemoveUnusedMembers Remarks
    '## ConvertGosubs
    '## UseTryCatch

then VB Migration Partner generates (remarked out) nonoptimized VB.NET code, where Gosub keywords are not rendered as separate methods and On Error statements are not converted into Try-Catch blocks.

Important note:
the RemoveUnusedMembers pragma deletes or remarks all members that haven’t found to be referenced by any other member in the current project or other projects in the current solution. However, this mechanism can lead to unwanted removal if the member is part of a public class that is accessed by another project (not in the solution) or if the member is accessed via late-binding. You can use the MarkAsReferenced or MarkPublicAsReferenced pragmas to account for the first case.

However, there is no simple way to detect whether a member is accessed via late-binding. For this reason the RemoveUnusedMembers pragma supports a second safeMode parameter. If this parameter is True then the pragma affects only members that can’t be reached via late-binding, e.g. constants, Declare statements, and members with a scope other than public.

ReplaceStatement code

Replaces the next statement with a piece of code. The code argument is an (unquoted) string that represents a valid VB.NET statement (or statements):

    '## ReplaceStatement Dim obj As Widget = Widget.Create(12)
    Dim  obj As New Widget

Keep in mind that this pragma replaces only the VB6 statement (not the line) that follows immediately the pragma. If the following line includes two statements separated by a semicolon, only the first statement is replaced by this pragma.


5.8 Pragmas that affect upgrade messages/アップグレードメッセージに影響を与えるプラグマ

Note:
This group of pragmas allow you to select which upgrade messages are generated during the migration process. VB Migration Partner can generate issue, warning, info, and to-do messages and, by default, all of them are included as remarks in the converted VB.NET application. You can selectively disable and enable messeges by their ID, by their severity (Issue, Warning, Info, ToDo), and type (Syntax, Language, CodeAnalysis, Library)

DisableMessage messageid

Disables generation for a specific message. The messageid argument is the hex numeric value of the message:

    '## Rem disable the message “Controls of type XYZ aren’t supported…” 
    '## DisableMessage 02C8

DisableMessages category

Disables message generation for a specific language category. The argument can be: Info, ToDo, Warning, Issue, Syntax, Language, CodeAnalysis, Library, All:

    '## Rem disable all messages except issues and warnings
    '## DisableMessages All
    '## EnableMessages Issue
    '## EnableMessages Warning

EnableMessage messageid

Enables generation for a specific message. The messageid argument is the hex numeric value of the message:

    '## Rem disable all messages except “Controls of type XYZ aren’t supported…” 
    '## DisableMessages All 
    '## EnableMessage 02C8 

EnableMessages category

Enables message generation for a specific language category. The argument can be: Info, ToDo, Warning, Issue, Syntax, Language, CodeAnalysis, Library, All:

    '## Rem disable messages except those related to code analysis 
    '## DisableMessages All 
    '## EnableMessages CodeAnalysis

MarkAsReferenced

Specifies that a specific symbol should be considered as used even if VB Migration Partner can’t detected any reference to it. It is useful when the member is accessed through late binding or the CallByName method:

    '## Rem consider the PrintReport method as referenced 
    '## PrintReport.MarkAsReferenced

Notice that this pragma must have a scope prefix.

MarkPublicAsReferenced

Specifies that all public members of current user control or class should be considered as used even if VB Migration Partner can’t detected any reference to it. It is useful inside ActiveX DLL or EXE projects that aren’t migrated together with their clients:

    '## Rem mark all public members in all public classes as referenced 
    '## project:MarkPublicAsReferenced

5.9 Miscellaneous pragmas/その他のプラグマ

PreCommand cmdtext

Executes an external application or an operating system command before starting the conversion of current project; cmdtext is the name of the external application or O.S. command, including its path if the application can’t be found on system path. If the command is an internal O.S. command (e.g. Copy) or the name of a batch file, the command should be prefixed by cmd /C and be run through the command-line interpreter:

    '## PreCommand notepad.exe c:\docs\instructions.txt
    '## PreCommand cmd /C copy c:\vbproject\*.* c:\backup

cmdtext can include the following special placeholders (not case sensitive)

  • ${vb6projectfile} :
    the complete path+name of the VB6 .vbp project file
  • ${vb6projectpath} :
    the path of the folder containing the VB6 .vbp project file

It is a good idea to enclose these placeholders between double quote, in case the project name or path include spaces. For example, you can use the PreCommand pragma to restore all VB6 files from a backup folder before starting the migration:

    '## PreCommand cmd /c copy "${vb6projectpath}\backup\*.*" "${vb6projectpath}"

The PreCommand pragma can only have an (implicit or explicit) project scope. You can apply the PreCommand pragma only by storing it in a *.pragmas file. We suggest that you use the special file named VBMigrationPartner.pragmas, which you can conveniently share among all the projects of a complex application, and use project placeholders to differentiate between individual projects.

PostCommand cmdtext

Executes an external application or an operating system command after saving the migrated .NET version of current project; cmdtext is the name of the external application or O.S. command, including its path if the application can’t be found on system path. If the command is an internal O.S. command (e.g. Copy) or the name of a batch file, the command should be prefixed by cmd /C and be run through the command-line interpreter:

    '## PostCommand notepad.exe "c:\docs\after migration instructions.txt"
    '## PostCommand cmd /C copy c:\vbproject\*.* c:\backup\vbproject

cmdtext can include the following special placeholders (not case sensitive)

  • ${vb6projectfile} :
    the complete path+name of the VB6 .vbp project file
  • ${vb6projectpath} :
    the path of the folder containing the VB6 .vbp project file
  • ${ProjectName} :
    the .NET name of the project that has been converted
  • ${ProjectFile} :
    the path of the .NET project that has been converted
  • ${ProjectPath} :
    the path of the folder containing the converted .NET project

It is a good idea to enclose these placeholders between double quote, in case the project name or path include spaces. For example, you can use the PostCommand pragma to copy all VB.NET source files to a backup folder immediately after saving them

    '## PostCommand cmd /c copy "${projectpath}\*.*" "c:\backup\${vb6projectname}"

The PostCommand pragma can only have an (implicit or explicit) project scope.

The PostCommand pragma is very helpful to preserve one or more .NET “definitive” source files that have been accurately edited and refined and that you don’t want to be overwritten in subsequent migrations. VB Migration Partner always deletes all the files in the target .NET directory, therefore you can’t really prevent a file from being overwritten; however, you can store all these “definitive” files in a given folder and use a PostCommand pragma to ensure that these files are copied over the files produced by the migration that has just been completed:

    '## PostCommand cmd /c copy "c:\definitiveprj\${projectname}\*.*" "${projectpath}" /Y

This technique is especially useful to preserve *.designer.vb files containing the code-behind portions of converted .NET forms.

SetTag tagname, tagvalue

Creates a tag with a given name and value. This pragma can be only useful when a VB Migration Partner extender recognizes and uses it. The following example assumes that you have installed an extender that recognizes the pragma tag named “DatabaseName”

    '## SetTag DatabaseName, “SqlServer”