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:
Sub SetSize(w As Integer)
…
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 .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):
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:
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:
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.
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.
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):
The ChangeType pragma can’t be used to convert to VB6Variant when converting to C#.
NOTE: starting with version 1.52, the VB6Variant class is not officially supported.
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:
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.
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:
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
v2(0).DoSomething
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:
which causes the following code to be generated
v2(0).Value.DoSomething
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 .NET methods under the pragma’s
scope are declared explicitly.
When converting to C#, VB Migration Partner ignores the DeclareImplicitVariables pragma and
always generate all implicitly-declared local variables.
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:
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
.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 .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.
The FixParamArray pragma is ignored when converting to C#.
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:
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)
Dim res As String = Nothing
Dim v1 As Integer
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).
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 .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)
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
or just assume that all exposed members are to be considered as methods that can
modify their arguments:
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:
If just the 2nd and 3rd parameters are defined with ByRef
you need this pragma:
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)
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:
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:
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:
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:
or more simply with
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.
The LateBoundMethods pragma is ignored when converting to C#.
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:
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)
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
or just assume that all exposed members are to be considered as writable properties:
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)
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:
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:
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:
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:
or more simply with
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.
The LateBoundProperties pragma is ignored when converting to C#.
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.
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:
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)
The LateBoundVariantMembers pragma is ignored when converting to C#.
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)
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:
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 .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:
Public Id As String
Sub AddHandler()
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()
Dim primes(1 To 10) As Integer
primes(1) = 1: primes(2) = 2: primes(3) = 3: primes(4) = 5: primes(5) = 7
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:
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:
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)
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:
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:
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:
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):
If the parameter is omitted, the Yes value is assumed.
The UseByval Force pragma is always implicitly assumed when converting to C#.
You can use a UseByval No pragma at the project level to disable this feature.
UseSystemString boolean
Specifies whether fixed-length strings inside Type…End Type blocks must be
converted to .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.
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
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:
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:
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:
- The method doesn't contain any Resume statement. (On Error Resume Next is OK, though).
- The target label isn't located inside a If, Select, For, Do, or Loop block.
- The target label isn't referenced by a Goto, On Goto/Gosub, or On Error statement.
- The target label must be preceded by a Goto, Return, End, Or Exit Sub/Function/Property
statement.
- The code block must terminate with an inconditional Return.
(Blocks that terminate with End Sub/Function/Property or Exit Sub/Function/Property
statements aren't converted.)
- 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:
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:
The FixRemarks pragma is ignored when converting to C#.
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)
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:
If x > 0 Or (x = 0 And y < 0) Then …
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 …
The LogicalOps pragma is ignored when converting to C#.
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)
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)
If (Not obj Is Nothing) AndAlso (obj.Text = "") Then
Debug.WriteLine("Empty Text")
End If
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:
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:
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.
The NullSupport pragma is ignored when converting to C#.
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:
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:
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:
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
The following example uses the optional regionpattern argument to restrict
the action of the PreProcess pragma to Sub methods only:
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:
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
.NET code.
PostProcess searchpattern, replacepattern, ignorecase, applytohiddenfiles, regionpattern
Applies a replace regular expression to the .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:
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:
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:
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.
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
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
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
Return m_MyData
End Get
Set(ByVal newValue As Object)
If Not IsObject6(newValue) Then
m_MyData = newValue
ProcessDataValue(newValue)
Else
m_MyData = newValue
End If
End Set
End Property
Sub Main()
Dim rs As New ADODB.Recordset
MyData = par.Value
MyData = par
MyData = rs.Fields
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:
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
Return m_MyData
End Get
Set(ByVal newValue As Object)
If _assignmentMode = PropertyAssignmentKind.Let Then
m_MyData = newValue
ProcessDataValue(newValue)
Else
m_MyData = newValue
End If
End Set
End Property
Sub Main()
Dim rs As New ADODB.Recordset
MyData = par
MyData(PropertyAssignmentKind.Set) = par
MyData = rs
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.
(This option is ignored when converting to C#.)
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:
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:
When applied at the project level, the SetOption ExcludeMethodBody pragma must be
included in a *.pragmas file.
DisableInitializeOptimization:
by default, VB Migration Partner extracts assignments to class variables inside
Class_Initialize methods and merges them with the variable's declaration. However,
in some cases you might want to disable this optimization. This is especially
important when converting to C#, because C# doesn't support class variable
initializers that are expressed in terms of another class-level variables, but can
be useful when converting to VB.NET if the order of assignments is important.
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()
On Error Goto ErrorHandler
ErrorHandler:
End Sub
This is how the code is translated to VB.NET:
Sub Test()
Try
Catch _ex As Exception
End Try
End Sub
The Try…Catch block can be inserted only if the following conditions are
all true:
- The method contains only a single On Error GoTo <label> method.
- 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.
- The method doesn’t contain GoSub, Resume, or Resume Next statements. (Resume
<label> statements are acceptable, though)
- 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.)
- 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.
- 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.
- 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()
On Error Goto ErrorHandler
If x > 0 Then GoTo ErrorHandler2
ErrorHandler:
ErrorHandler2:
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
On Error Resume Next
Reciprocal = 1 / x
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
Catch
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:
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.
The UseTryCatch pragma is always assumed by default when converting to C#.
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:
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:
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.
The name of controls that belong to a control array include the index between parenthesis:
You can also perform math operations on the current property value, by prefixing
the newvalue argument with the +, -, *, /, \ symbols:
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:
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:
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 .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 .NET project:
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):
.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):
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:
WriteProperty propertyname, value
Assigns a design-time property to the current form or to a specific control:
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
.NET applications.
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:
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:
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:
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.
DesignTimeSerialization boolean
Specifies whether the property should be decorated with the Browsable and
DesignerSerializationVisibility attributes (to suppress serialization) or with the DefaultValue
attribute (if serialization is not suppressed).
This pragma works in two different ways, depending on whether it is specified at the project/file-level
or at the property level.
If specified at the project/file-level, VB Migration Partner uses the code inside the WriteProperties
method to derive the names and the default values of the properties that must be serialized.
Note: This group of pragmas allow you to control how VB Migration
Partner parses VB6 statements or outputs .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 or C# statement (or statements):
Note text
Inserts an UPGRADE_NOTE remark in the converted .NET:
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 .NET statements
affected by this pragma; if zero or omitted, the effect extends to the next OutputMode
pragma:
PrintReport "Products”, 1, 10
Private Sub TestReport()
End Sub
The Uncomment setting is especially useful for including a portion of VB.NET
or C# code
that doesn’t exist in the original VB6 project:
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:
PrintReport "Products”, 1, 10
Private Sub TestReport()
End Sub
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 .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:
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 .NET.
This pragma is useful to explain what other pragmas do:
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 .NET code, the default behavior), On or omitted (unreachable
code is removed from the generated .NET code), Remarks (unreachable code
is remarked out.) Consider the following VB6 code:
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
End Sub
If the VB6 code had included the followed pragma:
then the result would have been as follows:
Sub Test(ByRef x As Integer, ByRef y As Integer)
x = 123
Exit Sub
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.
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
.NET code, the default behavior), On or omitted (unused members are removed
from the generated .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:
Const UnusedValue As Integer = 1
If you use a RemoveUnusedMembers pragma, the message is different. For example:
Const UnusedValue As Integer = 1
generates this VB.NET code:
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:
then VB Migration Partner generates (remarked out) nonoptimized .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 or C# statement (or statements):
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.
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 .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:
DisableMessages category
Disables message generation for a specific language category. The argument can be:
Info, ToDo, Warning, Issue, Syntax, Language, CodeAnalysis, Library, All:
EnableMessage messageid
Enables generation for a specific message. The messageid argument is the
hex numeric value of the message:
EnableMessages category
Enables message generation for a specific language category. The argument can be:
Info, ToDo, Warning, Issue, Syntax, Language, CodeAnalysis, Library, All:
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:
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:
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:
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:
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:
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 .NET source files to a backup folder immediately after saving them
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:
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”
CSharpOption optionname [,bool]
Affects the way VB6 code is converted to C#. The optionname argument is mandatory
and is the name of the option to be set (see below); bool is optional and can be
True (or omitted) to enable the option, or False to disable it. Except where noted,
this pragma can have project-, file-, and method-level scope.
A “+” operator under the scope of this pragma is assumed to be string concatenations, if either of its operands is an Object variable.
A comparison operator (e.g. == or >=) under the scope of this pragma
is assumed to be a comparison between strings, if either of its operands is an Object variable.
Forces the conversion of an On Error Goto statement into
a try-catch block, even if the resulting C# code isn’t perfectly equivalent to the original VB6 code.
Converts On Error Resume Next statements into anonymous methods.
Force VB Migration Partner to emit calls to conversion helper methods when a dynamic variable
appears as an operand to a math operator. This pragma can be useful if one or more statement in
a method rely on implicit conversions from incompatible types, e.g. between strings and numbers.
- ExplicitInterfaceImplementation
Generates an implicit implementation for one or more members of an interface.
Use it inside a method to have VB Migration Partner implement that interface method explicitly, as in:
Sub MyInterface_DoSomething()
…
End Sub
Attempts to optimize For Each loops by avoiding the declaration of a separate variable for controlling the loop.
Generates all the necessary overloads for a method so that VB Migration Partner doesn’t
have to generate temporary variables when passing an expression to a ref/out parameter.
Generates all the necessary overloads for a method so that VB Migration Partner doesn’t
have to use optional parameters in the method definition.
Specifies that a Variant or Object variable should be rendered using the standard C# Object
type rather than the special C# type, and that late-bound calls should be rendered using the
VB6Helpers.Invoke helper methods.
Replaces C# data types (e.g. int or float) with standard .NET types (e.g. Int32 or Single).
Uses the “out” keyword for parameters that are assigned inside methods before their value is used.
UseDynamic value, forceconversion
Specifies that a Variant or Object variable should be rendered using the special dynamic C# type.
Both arguments are optional: value argument can be True (or omitted) to enable this option, or False
to disable it; forceconversion can be True to force the generation of code that converts dynamic
variables to a more definite data type inside expressions. This pragma can be applied at the project,
file, method, and variable level.
Dim var As Variant
UseNetMethods pattern, replaceall
Attempts to replace calls to methods in VB Migration Partner’s support library with calls to native
.NET methods and classes. Both arguments are optional: pattern is a regular expression that is used
to decide which library methods should be converted to .NET methods (defaults to “.+”, which means
“all methods”), whereas replaceall can be True to perform “aggressive” substitution, in which case
the replacement occurs even if it delivers redundant and less-than-optimal code.
Only a small number of library methods can be safely replaced by calls to native .NET methods without
losing functional equivalence with the original VB6 code. Examples of such methods are Space, Left,
and Upper. By default VB Migration Partner will replace all occurrences of the methods that can be
safely converted to .NET methods, but you can use the pattern argument to decide which library methods
must be converted, as in:
Sub Test()
'## UseNetMethods "Left|Space"
…
End Sub
In some cases – for example the Right method - the replacement causes the generation of a C# expression
with repeated sub-expressions. To avoid generating bloated and inefficient code, in such cases VB Migration
Partner do not apply the substitution, but you can force it anyway by passing True as the second argument
to this pragma.