Double Return in VB6?

This is part 2 or a follow up blog of the previous VB6 blog regarding ByVal and ByRef which explores a use case that I often use when defining functions where I return a boolean and pass the value through parameter(s).

If you haven’t read that blog, here’s the link (cause this expects you to know what I discussed on that one):

I first used this technique several years ago when I was trying to find a way to get the return value and at the same time also allow me to know if there was an error and thereby allow the calling routine to change behavior depending on success or failure. If there was no error, the caller would consume the value but show the error when the call didn’t succeed.

I thought of using dictionary as the return value since it would allow me to pack many values in it, values and error.

I thought of using a class as a return value which would have properties like error and value.

And both of those worked, until I was trying to evaluate the return value to figure out if the call succeeded or not.

Long story short, I didn’t like it — so I tried something else and this is what I came up with and ended up using, as the better version among the versions I tried. Here’s the template (or function signature):

function function_name(byval input_values, ByRef outvalue, ByRef outerror As String) As Boolean

First set of parameters are those needed by the function and they’re passed by value.

The last two (2) are for containing the result of function execution and the error it produced/encountered respectively, and that both of these are passed by reference.

Lastly, the function returns True when there’s no error and False when it does. Additionally, the function sets the value of outerror to a blank string if successful and the error (via Err.Description) otherwise.

Here’s a trivial example when implementing this function signature for computing the vehicles fuel efficiency:

Function compute_km_per_liter_hybrid(ByVal km As Single, ByVal liters As Single, _
ByRef outvalue As Single, ByRef outerror As String) As Boolean
    '
    ' computes fuel efficiency and returns the computed value.
    ' returns True if no error, False otherwise.
    ' additionally, "outerror" contains the error if returning False
    '
    Dim value_was_computed              As Boolean
    
Try:
    On Error GoTo Catch
    
    
    outvalue = km / liters
    outerror = ""
    value_was_computed = True
    
    GoTo Finally
    
Catch:
    outvalue = -1
    outerror = Err.Description
    value_was_computed = False
    
Finally:
    compute_km_per_liter_hybrid = value_was_computed
    
End Function

And here’s how this would be used:

Private Sub TestHybrid(ByVal liters_consumed As Integer)
    Dim error_text                      As String
    
    If compute_km_per_liter_hybrid(km_travelled, liters_consumed, fuel_economy, error_text) Then
        StandardSummary "Using Hybrid"
    Else
        StandardSummary "Using Hybrid", "Unable to compute fuel efficiency: " & error_text
    End If
End Sub

The function is called and evaluated (for success or failure) on the same line which makes it look like a simple IF..THEN..ELSE code and that it is more “obvious” where the values will be and what we’re trying to do, versus Dictionary or Class. Plus, this signature doesn’t require you to reference external libraries (like Scripting Runtime) or force you to create a Class just to make it work.

When you need to return multiple values, you can combine function and byref…or do the other options I mentioned.

And there’s one more…

That’s not the only reason why you need to understand this concept (of passing values via a arguments). Most Windows API are passing the return value via the argument, and you’d have a hard time using Windows APIs if you have not tried passing value back through an argument.

Here’s one of the many Windows API that uses a parameter to store the value (instead of returning it):

Private Declare Function GetComputerName Lib "kernel32" Alias _
"GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long

To use this, you have to define a buffer string that will contain the value of computer-name. Here’s what you’ll see from Microsofts web site:

https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcomputernamea

In VB6, here’s how the code would look like:

Private Sub Form_Load()
    Dim return_value            As Long
    Dim hostname                As String
    
    hostname = Space(100)
    return_value = GetComputerName(hostname, Len(hostname))
    Debug.Print return_value, hostname
End Sub

Here’s the GitHub link for the source codes used in this blog (in case you want to test and explore it):

https://github.com/vegitz/codes/tree/master/0021%20ByVal%20vs%20ByRef%20in%20VB6

Leave a Comment