Solved

CallByName - Array Parameters Of An Unknown Type

Posted on 2001-07-20
11
1,115 Views
Last Modified: 2009-12-16
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.
0
Comment
Question by:ygibbs
  • 3
  • 3
  • 2
  • +2
11 Comments
 
LVL 3

Expert Comment

by:nigelrowe
ID: 6301860
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
 
LVL 22

Expert Comment

by:CJ_S
ID: 6301869
I think he wants to determine the type of parameters at run-time...

regards,
CJ
0
 
LVL 4

Expert Comment

by:VincentLawlor
ID: 6301870
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
 
LVL 3

Expert Comment

by:nigelrowe
ID: 6301871
Please forget that, I see what you are getting at now. I will look more closely.
0
 
LVL 4

Expert Comment

by:VincentLawlor
ID: 6301886
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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 

Author Comment

by:ygibbs
ID: 6301901
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
 
LVL 15

Accepted Solution

by:
ameba earned 200 total points
ID: 6301988
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
 
LVL 4

Expert Comment

by:VincentLawlor
ID: 6301992
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
 

Author Comment

by:ygibbs
ID: 6302004
Superb - thank you so much.  That's it working perfectly now.
0
 
LVL 15

Expert Comment

by:ameba
ID: 6302005
My code was version 0.1  :-)
Do not redim arrays:
    "0 To maxEl"
but use "minEl To maxEl", where  minEl = LBound(arr)
0
 
LVL 15

Expert Comment

by:ameba
ID: 6302018
Thanks!
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Article by: Martin
Here are a few simple, working, games that you can use as-is or as the basis for your own games. Tic-Tac-Toe This is one of the simplest of all games.   The game allows for a choice of who goes first and keeps track of the number of wins for…
Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…

932 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now