Note: this article only applies to conversions to VB.NET, because the LateBoundProperties and LateBoundMethods pragmas aren’t supported when converting to C#.
VB Migration Partner uses a quite sophisticated algorithm to handle late-bound calls. Understanding how the mechanism works will help you generate better code and avoid some common migration issues.
1. Passing late-bound members to methods
In this case you are passing an late-bound field or property to a method invoked through early-binding. Consider the following VB6 code:
Sub Test(ByVal obj As Object, ByVal wi As Widget)
wi.DoSomething obj.Value
End Sub
If no pragmas have been used, the code is converted to VB.NET with no significant changes:
Sub Test(ByVal obj As Object, ByVal wi As Widget)
wi.DoSomething(obj.Value)
End Sub
Here’s the problem. Under VB6, the obj.Value member will be never changed inside the DoSomething method, regardless of how the property or the method is defined. In short, under VB6 fields and properties are always passed to a method using by-value semantics. Conversely, under VB.NET the Value member might be changed, if it is a writable property and if the called method takes a parameter defined by means of an implicit or explicit ByRef keyword. Another way to explain this fact is that VB Migration Partner considers all late-bound members as method names (or readonly property names, if you prefer).
This difference might introduce subtle bugs in the migrated application. You can change VB Migration Partner’s default behavior by specifying that the Value property should be dealt with as a writable property that must be protected from “hidden” assignments. You do this by means of a LateBoundProperties pragma at the project level:
Alternatively, you can be more specific about which properties should be considered as writable:
When a proper LateBoundProperties pragma is used, VB Migration Partner generates code that forces the by-value semantics:
wi.DoSomething(ByVal6(obj.Value))
2. Passing values to late-bound methods
In this case you are passing an early-bound field or property to a method invoked through late binding. Consider the following VB6 code:
Sub Test(ByVal obj As Object, ByVal wi As Widget)
obj.DoSomething wi.Value
End Sub
If no pragmas have been used, the code is converted to VB.NET with no significant changes:
Sub Test(ByVal obj As Object, ByVal wi As Widget)
obj.DoSomething(wi.Value)
End Sub
Here’s the problem. Under VB6, the wi.Value property will be never changed inside the DoSomething method, regardless of the property or the method is defined. As explained in previous case, under VB6 fields and properties are always passed to a method using by-value semantics. Conversely, under VB.NET the Value member might be changed, if it is a field or a writable property and if the called method takes a parameter defined by means of an implicit or explicit ByRef keyword. Another way to explain this fact is that VB Migration Partner considers all the parameters of late-bound methods as if they use by-value semantics.
As for previous case, this difference might introduce subtle bugs in the migrated application. You can change VB Migration Partner’s default behavior by specifying that the DoSomething method takes a parameter with by-reference semantics and, therefore, that values passed to this parameter must be protected from “hidden” assignments. You do this by means of a LateBoundMethods pragma at the project level:
Alternatively, you can be more specific about which properties should be considered as writable:
When a proper LateBoundMethod pragma is used, VB Migration Partner generates code that forces the by-value semantics:
obj.DoSomething(ByVal6(wi.Value))
3. Passing late-bound members to late-bound methods
In this case you are passing an late-bound field or property to a method invoked through late binding. Consider the following VB6 code:
Sub Test(ByVal obj As Object, ByVal obj2 As Object)
obj.DoSomething obj2.Value
End Sub
If no pragmas have been used, the code is converted to VB.NET with no significant changes:
Sub Test(ByVal obj As Object, ByVal wi As Widget)
obj.DoSomething(obj2.Value)
End Sub
The same considerations seen for cases 1 and 2 apply here. The above code might mistakenly cause the Value member to be modified inside the DoSomething method. To avoid this problem, you must include both a LateBoundProperties pragma that specifies that Value is a writable property and a LateBoundMethods pragma that specifies that DoSomething takes a ByRef parameter:
4. UseByVal pragma’s behavior with late-bound calls
The last case to discuss is when the current method is under the scope of a UseByVal pragma and VB Migration Partner must determine whether the parameter is modified by a call to a late-bound method. Consider the following VB6 code:
Sub Test(value As Integer, obj As Object)
obj.DoSomething value
End Sub
Notice that the value parameter isn’t explicitly modified anywhere in the method, therefore VB Migration Partner must determine whether it can be modified inside the DoSomething method: if the answer is no, then the parameter can be rendered with the ByVal keyword.
As explained above, by default VB Migration Partner assumes that late-bound methods don’t modify their argument. Consequently, the UseByVal pragma causes the value parameter to be rendered with the ByVal keyword.
As for case #2, this difference might introduce subtle bugs in the migrated application. You can change VB Migration Partner’s default behavior by specifying that the DoSomething method takes a parameter with by-reference semantics and, therefore, that values passed to this parameter must be protected from “hidden” assignments. You do this by means of a LateBoundMethods pragma at the project level:
If this pragma is specified, VB Migration Partner will assume that the value parameter can be modified inside the DoSomething method and won’t use the ByVal keyword for the parameter.