CallByName - Array Parameters Of An Unknown Type

When using CallByName to run a method of a COM component, if a parameter expected is of a certain type, when calling it, you can actually pass in a variant, as long as the variant contains a variable of the right type.

However, if the parameter expected is an array of a certain type (say Long), then when calling it you must pass an array dimensioned as that type, rather than an array dimensioned as a variant, or a variant storing an array.

So, say your COM component has a function as follows:
Public Function Blah(x as long, y() as long)

When calling it, you should do this:
Dim x As Long
Dim y() As Long
CallByName MyObj, "Blah", VbMethod, x, y

Our problem is that we don't know at compile time what the COM object is expecting, so we have to do this:
Dim x As Variant
Dim y() As Variant

'Now convert the array to the relevant type - in this instance assume Long is the data type
x=CLng(0)
Redim y(0)
y(0)=CLng(0)
CallByName MyObj, "Blah", VbMethod, x, y

This is causing a Type Mismatch error.  The x parameter works fine, but the y parameter (the array) isn't.

Any ideas would be greatly appreciated.
ygibbsAsked:
Who is Participating?
 
amebaConnect With a Mentor Commented:
This will make your callbyname work, but you should know that if you don't pass right variable type, ByRef won't work - you will be passing argument ByVal.

Option Explicit

Private Sub Form_Load()
    Dim x As Variant
    ReDim y(0) As Variant
    x = 1
    y(0) = 1
   
    Dim vntY As Variant  ' this variable will hold our array
    vntY = ConvertArray(y, vbLong)
   
    ' don't pass vntY variable directly - gives "Type mismatch" error
    '    pass Expression (vntY)
    CallByName Me, "Blah", VbMethod, CLng(x), (vntY)

End Sub

Public Sub Blah(px As Long, py() As Long)
    px = 2
    py(0) = 2
End Sub

' converts variant array to
'     variant variable which holds 'right' type of array
' I modified code from: http://www.vb2themax.com/Item.asp?PageID=CodeBank&ID=72
Public Function ConvertArray(arr() As Variant, NewType As VBA.VbVarType) As Variant
    Dim i As Long
    Dim maxEl As Long
    Dim res As Variant
   
    maxEl = UBound(arr)
   
    ' create different arrays, depending on the
    ' type of the first argument
    Select Case NewType
    Case vbInteger
        ReDim arrInt(0 To maxEl) As Integer
        res = arrInt()
    Case vbLong
        ReDim arrLng(0 To maxEl) As Long
        res = arrLng()
    Case vbSingle
        ReDim arrSng(0 To maxEl) As Single
        res = arrSng()
    Case vbDouble
        ReDim arrDbl(0 To maxEl) As Double
        res = arrDbl()
    Case vbCurrency
        ReDim arrCur(0 To maxEl) As Currency
        res = arrCur()
    Case vbString
        ReDim arrStr(0 To maxEl) As String
        res = arrStr()
    Case vbDate
        ReDim arrDat(0 To maxEl) As Date
        res = arrDat()
    Case vbBoolean
        ReDim arrBol(0 To maxEl) As Boolean
        res = arrBol()
    Case vbObject
        ' special case
        ReDim arrObj(0 To maxEl) As Object
        For i = 0 To maxEl
            Set arrObj(i) = arr(i)
        Next
        ConvertArray = arrObj()
        Exit Function
    Case Else
        ' unsupported data type
        ' (might be a UDT or an array)
        Err.Raise 5
    End Select
           
    ' now we can copy all values into the array
    For i = 0 To maxEl
        res(i) = arr(i)
    Next
    ConvertArray = res
End Function
0
 
nigelroweCommented:
There doesn't seem to be a one line solution, so..
Dim y As variant
    y = Array("1", "2", 3)
    For i = 0 To UBound(y)
        y(i) = CLng(y(i))
    Next
0
 
CJ_SCommented:
I think he wants to determine the type of parameters at run-time...

regards,
CJ
0
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.

 
VincentLawlorCommented:
That's because your COM object is probably expecting a array of longs not a variant.

The IDL for the file probably declares it as a specific type. i.e. long

To get this to work the COM object must be able to accept either Variant or Variant array data types.

Check the types it is expection using object browser.

What language were the COM object written in.

Vin.
0
 
nigelroweCommented:
Please forget that, I see what you are getting at now. I will look more closely.
0
 
VincentLawlorCommented:
If you wrote them in VB then you will have to change your data types in the COM objects to Variants and do the Conversions internally.

If the were written in C++ then the data types will have to be changed to VARIANT and the appropriate conversions done on the values passed to it internally in the com object.

Vin.
0
 
ygibbsAuthor Commented:
Yeah, the only easy solution is to change the COM component to receive variants (generally our clients' COM components will be written in VB, but we allow them to define which components they want to use, so it could theoretically be anything).  However I would like to try and avoid that if at all possible.

The other thing we're investigating is using the Type Library Information DLL and its InvokeHook method.  Has anyone had any experience of this?

I'll post a solution if we manage to get one ourselves, but thanks for the input anyway.
0
 
VincentLawlorCommented:
Have you checked out MSDN.

There is an article in there about it.

http://support.microsoft.com/support/kb/articles/Q194/4/18.ASP

This might help.

Tried it it works.

Vin.
0
 
ygibbsAuthor Commented:
Superb - thank you so much.  That's it working perfectly now.
0
 
amebaCommented:
My code was version 0.1  :-)
Do not redim arrays:
    "0 To maxEl"
but use "minEl To maxEl", where  minEl = LBound(arr)
0
 
amebaCommented:
Thanks!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.