Alias in Function Declaration overloaded? - vb.net

I have some VB6 code that I am converting to VB.net and came across this section
Declare Function TmSendByLen Lib "tmctl.dll" Alias "TmSendByLength"(ByVal id As Integer, ByRef msg As Any, ByVal blen As Integer) As Integer
'snip'
Function TmSendByLength(ByVal id As Integer, ByVal msg As String, ByVal blen As Integer) As Integer
TmSendByLength = TmSendByLen(id, msg, blen)
End Function
I have not come across the Alias term before but I can guess what it does. What I am unsure of is the reasoning behind overloading the alias. If that is what is happening.
I need to create overloads for the TmSendByLen function as the 'As Any' is not supported in VB.net so I am not sure if I should just remove the alias or if I should leave it in place.

The Alias doesn't specify that the function is overloaded exactly, but that the name specified is really named something else in the called dll.
Since your example is a bit confusing (because of the repeated names), I'll use a slightly modified version to explain:
Declare Function TmSendByLen Lib "tmctl.dll" Alias "TmSendByLength" (ByVal id As Integer, ByRef msg As Any, ByVal blen As Integer) As Integer)
Function InternalVersion(ByVal id As Integer, ByVal msg As String, ByVal blen As Integer) As Integer
InternalVersion = TmSendByLen(id, msg, blen)
End Function
So in this modified version, the TmSendByLength name is the one that the referenced function's entrypoint is really called in tmctl.dll. TmSendByLen is what we're referring to it as in our code, and InternalVersion is the name of the wrapper function.
I would imagine that this is so that InternalVersion can be called across modules/classes, while the TmSendByLen version was intended to be private.
To answer the second part of your question, Alias is still available in VB.NET, although As Any isn't. (You can find information about it here.) Whether you want to remove the Alias or not is completely up to you, but either way, I suspect you're going to need to use As IntPtr (or SafeHandle) instead of As Any.

The "Alias" keyword in VB6 is probably doing what you think it does, however, it's the function name in quotes after the keyword "alias" that is the actual function name in the DLL (i.e. TmSendByLength). The function name after the "Declare Function" part (i.e. TmSendByLen) is effectively the alias that the VB6 code will use.
As you correctly point out, VB6 will not allow the "As Any" parameter type, so from the original VB6 code you posted, the developer has declared a VB6 function which incidentally has the exact same name as the "real" function in the DLL, and altered the parameters to this function to accept only a string type for the "msg" parameter.
The VB6 code as-is isn't actually overloading any function, but rather it's wrapping the DLL function with a VB6 specific one that constrains the "msg" parameter type.
In VB.NET, since you can't specify "as any", I believe you can replace this with "as object", although that may not be very helpful since other VB.NET calling code could pass virtually anything to this parameter. What you're more likely going to want to do is to create real overloaded functions in VB.NET where the "msg" parameter differs by the type that you want to accept. This way, you can allow multiple different types, but still maintain some constraints on which types can be passed to the function.
Here's a couple of links that may well help:
VB6 "As Any" in VB.Net
PInvoke

Related

How are parameters passed to VB functions by default

Let's say I have the following function:
Function myFunction(j As Integer) As Double
myFunction = 3.87 * j
Exit Function
End Function
Is j passed as value ByVal or by reference ByRef?
Or does it depends of the data type? What if I have a complex object passed as the value?
Thanks in advance!
Parameters are passed ByVal unless explicitly specified. For details, see Passing Arguments by Value and by Reference, which states:
The default in Visual Basic is to pass arguments by value. You can make your code easier to read by using the ByVal keyword. It is good programming practice to include either the ByVal or ByRef keyword with every declared parameter.
As for:
What if I have a complex object passed as the value?
This is fine, provided the "complex object" is a class (Reference type), you're not going to be doing a lot of copying. This is because the reference to the object instance is passed by value (ByVal), which means you're only copying a single reference, even if the class is very large.
If, however, the complex object is a structure (value type), you will be causing the object to be copied when the method is called. This, btw, is why some frameworks like XNA provide alternative versions of many methods (like Matrix.Multiply) that have an option to pass ByRef - this avoids the expensive copies of the Matrix structures.
j in this case is passed ByVal. A parameter is always passed ByVal unless ByRef is explicitly stated. From section 9.2.5 of the VB.NET 10 Specification:
A parameter that does not specify ByRef or ByVal defaults to ByVal.

Using ByVal in vb.net methods, what's the common practice?

In vb.net the methods have their parameters using ByVal by default, it's better practice / common practice to make it explicit?
For example:
With ByVal:
Private Sub MySub(ByVal Q As String)
{
' ...
}
End Sub
Without ByVal:
Private Sub MySub(Q As String)
{
' ...
}
End Sub
According to Microsoft:
It is good programming practice to include either the ByVal or ByRef keyword with every declared parameter.
And if you use Visual Studio, it defaults to inserting ByVal if you don't explicitly specify it.
Starting with VS 2010 SP1, ByVal is no longer automatically inserted by the IDE.
I personally think it's better not to insert ByVal manually, because:
it's the default passing mechanism anyway, if neither ByVal nor ByRef are explicitly specified.
omitting ByVal from method signature makes ByRef stand out.
it adds 'noise' to the code. VB.Net is already very verbose, no need to clutter the code with unnecessary ByVals.
It is common practice that a method arguments can be specified at ByValue or ByReference. In VB.NET, the default argument type is ByVal. In many programming language, method arguments are by-value by default. If argument is not qualified with ByVal or ByRef then the argument type will be ByVal.

Is there a VB.NET equivalent of C# out parameters?

Does VB.NET have a direct equivalent to C# out function parameters, where the variable passed into a function does not need to be initialised?
No, there is no equivalent of the out keyword in VB.
However, VB does automatically initialise all local variables in a method, so you can use ByRef without needing to explicitly initialise the variable first.
Example:
Sub Main()
Dim y As Integer
Test(y)
End Sub
Sub Test(ByRef x As Integer)
x = 42
End Sub
(If you examine code in the framework (for example Double.TryParse), you may see the <OutAttribute> added to parameters, but that only makes a difference when the call is marshalled for COM interop or platform invoke.)
No, there is no equivalent construct that allows a non-initialised variable to be passed to a method without a warning, but, as mentioned in my question and answer specifying an <Out()> attribute on a ByRef parameter definition, although VB ignores it, is treated by C# as an out parameter.
So, I would pre-initialise reference variables to Nothing and specify <Out()> ByRef to signify the intention (that will work if C# users ever access your methods).
If you feel you know when you intend to access the default Nothing in otherwise unassigned reference variables you can set the "Warning configuration" "Use of variable prior to assignment" to "None" at the Project level (Project Properties > Compile, and you probably want to set Configuration to "All Configurations" before changing this setting), or, in VS2015 (VB.NET 14), you can use #Disable Warning BC42030.
C# version
void TestFunc(int x, ref int y, out int z) {
x++;
y++;
z = 5;
}
Vb.net version
Sub TestFunc(ByVal x As Integer, ByRef y As Integer, ByRef z As Integer)
x += 1
y += 1
z = 5
End Sub
Found the answer here
Update
As stated in the comment do not forget to initialze your parameter that will be used in the out slot
I had the problem in VB.NET that I called a function "by ref" that passed an array back.
Even though the compiler flagged it as a warning it was fine. The fix is super simple and probably good programming practice.
I changed
Dim m_arr_values() as Integer
fnRetArray(m_arr_values)
to
' Even though 'Nothing' is the default value, setting it
' stops the compiler complaining.
Dim m_arr_values() as Integer = Nothing
fnRetArray(m_arr_values)
It also helps when coding if variable names are descriptive...
Sub fnCreatePalette(ByRef arr_in_pal() As color, ByRef arr_out_pal() as uinteger)
...
End Sub
VB has the attribute which should be the same as C# out but today you still get a warning even if you use it. There are details about fixing it in vblang area of github. https://github.com/dotnet/vblang/issues/67.
You can use the pass by reference method in VB.NET.
You need the Out parameter mechanism in C#, because it doesn't let you use any variable without initializing it.
VB.NET doesn't need a special keyword as it automatically does it by itself.
Just use ByRef.
Use keyword ByRef before variable.

Receive a Jagged Array in VBA (VB6)

I currently have a VB.NET dll that returns a jagged array of double. This is the declaration:
Public Function CalcMatching(ByRef dataArray1 As Object,
ByRef dataLen1 As Integer, ByRef dataArray2 As Object,
ByRef dataLen2 As Integer, ByRef matchingType As String) As Double()()
It works well inside VB.NET, but when I insert it into a VBA project, I noticed that after the execution of the function, while retrieving the data, the "Type mismatch' exception is raised inside VBA.
I searched over the internet, but I could not find a declaration of a jagged array inside VBA. is that possible? If yes, how can I do it?
Just a guess without seeing the calling VBA code, but I believe this is being caused by having ByRef arguments instead of ByVal. There is stronger type checking when using ByRef arguments which you can read about here.

Byref New Object. Is it okay top pass New Object as "byref"

Below I tried to do an Example:
Public Function UserData(ByVal UserDN As String) As DataTable
Dim myTable As DataTable = UserData_Table()
Dim dr As DataRow
dr = myTable.NewRow()
SplitOU2(UserDN, dr("OUDN"), dr("Organisation"), New Object)
dr("UserDN") = UserDN
myTable.Rows.Add(dr)
Return myTable
End Function
Below is the called method:
Friend Sub SplitOU2(ByVal inDN As String, ByRef OUDN As Object, ByRef Organisation As Object, ByRef VerksamhetTyp As Object)
By doing this I can skip to declare the in this example "useless" variable
Dim VerksamhetTyp as Object = "".
Perhaps it looks a little ugly but to have to declare unused variables can also be confusing.
Summary: Check whether or not the method really needs those parameters to be ByRef. Also check that you really don't care about anything it does to the parameters. After scrupulous checking, it's okay to do this - nothing "bad" will happen in terms of the CLR, because it's just a compiler trick under the hood.
Well, VB (unlike C#) will let you do this. Behind the scenes it's effectively creating a new variable and passing it by reference - after all, it has to for the method to be called properly. However, I'd say this is usually a bad idea. The point of ByRef is that you use the value after it's been set within the method.
Do you really need all those parameters to be ByRef in the first place? If you find yourself doing this a lot for a particular method, you could always write a wrapper method which called the original one, but didn't have the ByRef parameters itself.
(I usually find that methods with a lot of ByRef parameters indicate either a lack of understanding of reference types in .NET, or that the parameters should be encapsulated in their own type.)
Having said all of this, it's not always incorrect to ignore the value of a ByRef argument after calling the method. For example, if you just want to know whether or not some text can be parsed as an integer, then using Int32.TryParse is reasonable - but only the return value is useful to you.
The reason that I consider to use this has to do with that the method has even more parameters and that different operation overloads gets the same signature ….
The fact that it works is quite fun and somthing I became awarae óff by chance ...