• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 420
  • Last Modified:

Passing Variable ByRef

I have written a generic application to test MTS objects. The application has no pre-knowledge of the object's interface and as such does not know what the parameter types will be.
I have a variant array which holds all the values to be passed as parameters.
The problem is that the MTS object may be expecting a parameter as a String, Integer, Long, etc, so I can CStr, CInt, CLng the variant array's element to pass it to the function. But what if the function expects the parameter to be passed ByRef so it can modify the contents of the parameter. Eg, a function returns the records from an SQL call and has an "Error As String" parameter to indicate whether there was an error or not.

Any ideas on how to do this?
  • 6
  • 5
  • 3
1 Solution
How about passing it by ref as a variant, then using the VarType command to determine its type in the function.

Changing a variant of any type to a string eg

varMy = "Error"

is then no problem, and the value drops back to your calling routine.
Returns a value indicating the subtype of a variable.



The varname argument can be any variable except a variable of a user-defined type.

Return Values

Constant      Value      Variable type description

vbEmpty      0      Empty (uninitialized).
vbNull      1      Null (no valid data).
vbInteger      2      Integer.
vbLong      3      Long integer.
vbSingle      4      Single-precision floating-point number.
vbDouble      5      Double-precision floating-point number.
vbCurrency      6      Currency.
vbDate      7      Date.
vbString      8      String.
vbObject      9      OLE Automation object.
vbError      10      Error.
vbBoolean      11      Boolean.
vbVariant      12      Variant (used only with arrays of Variants).
vbDataObject      13      Non-OLE Automation object.

vbByte      17      Byte
vbArray      8192      Array.

Note   These constants are specified by Visual Basic for applications.  As a result, the names can be used anywhere in your code in place of the actual values.


The VarType function never returns the value for vbArray by itself.  It is always added to some other value to indicate an array of a particular type.  The constant vbVariant is only returned in conjunction with vbArray to indicate that the argument to the VarType function is an array of type Variant.  For example, the value returned for an array of integers is calculated as vbInteger + vbArray, or 8194.  If an object has a default property, VarType (object) returns the type of its default property.
garymatherAuthor Commented:
This does not help as I cannot control how the function is declared. Also, if the function is expecting a String, passing a variant causes a type mismatch.

Here's the code I'm using to make the call:

varReturn = CallByName(objMTS, lstMembers.Text, VbMethod, Cnv(0), Cnv(1))

Private Function Cnv(ByRef Variable As Long)

    Select Case lstParameters.ItemData(Variable)
        Case 2  ' VT_I2
            Cnv = CInt(varParameters(Variable))
        Case 3  ' VT_I4
            Cnv = CLng(varParameters(Variable))
        Case 8  ' VT_BSTR
            Cnv = CStr(varParameters(Variable))
        Case 11 ' VT_BOOL
            Cnv = CBool(varParameters(Variable))
        Case Else
            Cnv = varParameters(Variable)
    End Select

End Function

This works fine as long as the called function does not try to manipulate any of the parameters.
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

how bout passing it like this:

Private Function Cnv(Variable As Any)
garymatherAuthor Commented:
VB does not allow you to declare a function as "Any". This is only used for API declarations. Anyway, the only reason the Cnv function is there, is to convert the Variant to the correct type. But this still only returns the Value and not a Reference.
why not declare it as a variant then?
You can't change the declaration of the function, but it is called by ref and wants a string?

Surely its easy, you load the variant into a string variable (or whatever type it is), then call the function over the string variable and be able to look at its changed value.

Then put the string back into the variant.  Might not be totally elegant but it solves the problem.

garymatherAuthor Commented:
Uh, I think we're going off on a tangent now. The CNV function has nothing to do with the problem. I would like a way to modify the CallByName call so that the variable is passed ByRef not ByVal.

If you're suggesting changing the function declaration within the MTS object, then the answer would be that this is a generic tester app and I cannot dictate to other developers how to define their objects.
garymatherAuthor Commented:
sorry, deighton, i missed your comment.

The problem is that I don't want to have to write thousands of lines of code for each possible combination of variable types in the CallByName call. It's bad enough that I have to have 10 lines to cater for the possibility of 10 parameters. It's enough that I restrict the app to allow a maximum of 10 parameters.

Currently I have for :
1 parm:
CallByName(......, Cnv(0))
2 parms:
CallByName(......, Cnv(0), Cnv(1))
what harm comes from declaring the call as byref initially?  declaring it to expect a variable of variant data type should provide all the functionality it needs.
garymatherAuthor Commented:
Once again. I cannot dictate to other developers how to implement their interfaces. This is to be a generic app that should be able to work with any MTS object, regardless of who or how it was written.
how about using the VarPtr() function then to pass a pointer instead of the actual value instead
garymatherAuthor Commented:
This looks like it will do the trick. Just FYI, what i did was this to test the idea.

Declare a module level variable:
Public s1 As String
I will have to declare s0 thru s9 for strings, i0 thru i9 for integers etc.

Then, before the callbyname, declare another variable to hold the name of the module level variable:

Dim strVarName As String

strVarName = "s1"
' Now change the CallByName call to this:
Call CallByName(objMts, lstMembers.Text, VbMethod, Cnv(0), VarPtr(CallByName(Me, strVarName, VbGet)))

Worked like a charm. I knew coming to this forum would pay off!!
i had just woken up and my head was a bit foggy...should have suggested this from the beginning...glad its working for you now

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 6
  • 5
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now