Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Using InvokeHook instead of CallByName

Status
Not open for further replies.

josan

Programmer
Mar 25, 2002
11
ES
When I saw the possibilities that bring you the CallByName method, I start to work how to adapt its funcionality to my applications. But I found some problems with his four parameter, the arguments.

I tried to pass to this method the list of the parameters of the property or method that I wanted to invoke, but I needed to convert all the values of the Args(). I wanted to pass a list of variants to this parameter, but the method returned an error of types. For exemple, if I wanted to invoke the "Move" method of a form, I need to do:

CallByName Form1, "Move", vbMethod, 1000, 1000, 1000, 1000

and NOT

Dim vals As Variant

ReDim vals(3)
vals(0) = 1000
vals(1) = 1000
vals(2) = 1000
vals(3) = 1000

CallByName Form1, "Move", vbMethod, vals

Luckyly, I find a library that solved me this problem, the TypeLib Information Library. This is a library defined in the tlbinf32.dll file. You can use it making a reference to this library. Next I show a code that resolved many problems to me. I hope it can bring you some aid, too!!

'/ Include this code into a class module
'/ Call the class "CInvoke"
'/
'/ Note: This code need a reference to the
'/ TypeLib Information Library (TLBINF32.DLL)!!
'/

Private TLIApp As New TLIApplication
Private TLInfo As TLI.InterfaceInfo
'/
'/ GetMember
'/ =========
'/ Inputs
'/
'/ - MetProp: The method or property that we want to search in
'/ the Members collection of the object QueriedObject
'/
'/ Output
'/
'/ - Return the member that contain the information of the property/method
'/ we are looking for
'/

Private Property Get GetMember(ByVal MetProp As String) As MemberInfo
Dim i As Long
Set GetMember = Nothing
For i = 1 To TLInfo.Members.Count
If TLInfo.Members(i).Name = MetProp Then
Set GetMember = TLInfo.Members(i)
Exit Property
End If
Next i
End Property
'/
'/ ParamsTransform
'/ ===============
'/ Inputs
'/
'/ - vals: An array that that contains the parameters of the method or property
'/ - args: The array of the parameters that we need to make the invocation (passed by reference)
'/
'/ Output
'/
'/ - Return True if UBound(vals)>-1, or False if the vals array is empty
'/
'/ Note: This method pass a Variant type to a Variant() type, because this is the type
'/ that we need to pass to the method that makes the invocation (InvokeHook...)
'/

Private Function ParamsTransform(ByVal vals As Variant, ByRef args() As Variant) As Boolean
Dim i As Long

ParamsTransform = False
On Error GoTo fin

ReDim args(UBound(vals))
For i = 0 To UBound(vals)
args(i) = vals(i)
Next i

ParamsTransform = True
fin:
End Function
'/
'/ Execute
'/ =======
'/ Inputs
'/
'/ - QueriedObject: The object which we want to make the invocation
'/ - MetProp: The method or property that we want to invocate
'/ - vals: An array that that contains the parameters of the method or property
'/ - res: The value, if any, that returns the invocation (passed by reference)
'/
'/ Output
'/
'/ - Return True if everything has gone ok, or False if exists a problem
'/

Public Function Execute(ByVal QueriedObject As Object, _
ByVal MetProp As String, Optional ByRef vals As Variant, _
Optional ByRef res As Variant) As Boolean

Dim InvokeType As InvokeKinds
Dim Member As MemberInfo
Dim nParams As Long
Dim RetType As Long
Dim args() As Variant

Execute = False

Set TLInfo = TLIApp.InterfaceInfoFromObject(QueriedObject)
Set Member = GetMember(MetProp)
If TypeName(Member) = "Nothing" Then
MsgBox "Error: The name of the property or method doen't exists!"
Exit Function
End If
InvokeType = Member.InvokeKind
RetType = Member.ReturnType.VarType

nParams = -1

If ParamsTransform(vals, args) Then
nParams = UBound(args)
End If

On Error GoTo Handler
Select Case RetType
'/ If RetType = 24 the method don't return any value (void)
Case 24
If nParams = -1 Then
TLIApp.InvokeHookSub QueriedObject, MetProp, InvokeType
Else
TLIApp.InvokeHookArraySub QueriedObject, MetProp, InvokeType, args
End If
'/ If RetType = 0 Or 9, the method or property return an Object, so
'/ we need to use the "Set" sentencia to instance the res
'/ variable as an object

Case 0, 9
If nParams = -1 Then
Set res = TLIApp.InvokeHook(QueriedObject, MetProp, InvokeType)
Else
Set res = TLIApp.InvokeHookArray(QueriedObject, MetProp, InvokeType, args)
End If
'/ In other case, the method or property return a non object value
Case Else
If nParams = -1 Then
res = TLIApp.InvokeHook(QueriedObject, MetProp, InvokeType)
Else
res = TLIApp.InvokeHookArray(QueriedObject, MetProp, InvokeType, args)
End If
End Select
Execute = True
Exit Function
Handler:
'/ If there is an error...
MsgBox (Err.Number - vbObjectError) & vbCrLf & Err.Source & _
vbCrLf & Err.Description
End Function


'/ Now, you can use this class in your forms
'/ Add this code into a form with a CommandButton (Command1) and a TextBox (Text1)


Private oc As New CInvoke

Private Sub Command1_Click()
Dim vals As Variant
ReDim vals(0)

vals(0) = Text1.Text
oc.Execute Me, "Move", vals
End Sub

Private Sub Form_Load()
Me.Text1.Text = CStr(Me.Left)
End Sub

Cheers!!
[pipe][peace]
 
By Using InvokeHook and InvokeHookArray overcome all of the limitations of the CallByName procedure....with a little playing around

Using InvokeHookArray you don't get automatic support for passing parameters ByRef. InvokeHook does this automatically but it requires you konw the number of arguments at compile time. But using a bit of memory hacking of the variant array can over come this shortfall when used with InvokeHookArrary, basically you need to set the VariantArray Element with the VarPtr of your real variable then set the VT_BYREF bit in Variant's header. A little convoluted but well worth it in the end. Sadly this library is poorly documented.

I've written a generic COM test harness that uses a text script to make method calls with paramaters listed in the script and it displays parameters in and out of the method along with the result set and real error genereated by the COM object if one occurs using this type library.

It is also very useful for grabbing Type library information from a DLL like object browser does.

 
Well, I created a component who analizes my own code (with an structure established under my own criterion), and where I can invoke to the methods of my another libraries in run time. That's the reason because I wanted this method, because I have created an interpreter. Before I've been known this library, I wasn't be able to know the methods and properties of the objects that I was creating along the life of my application, neither the number and the type of each parameter of each method and property. That's truth that does not exist much documentation about this library (I needed a lot of time and a strike of luck to know how this library worked) I found this address: Now, I have been able to begin an interpreter that allows me to define the processes that are carried out in an application, in scripts, so I can modify these processes without modifying the libraries in run time, and in thanks to this library. That's because I was so happy when I knew of it!!

See you!
 
Yup CallByName returning the wrong error and not supporting the returning of ByRef parameters is why I use this library. I even tried having my test harness use this library to write VBScript code and execute it to try get everything working but though I could get the correct error back from a procedure the nature of VBScript prevented me from using objects directly with byref parameters unless those parameters where of variant types....and I'm sorry I don't code my base objects with variant datatypes unless I need to be able to pass any type of information to the method.

It would be good if they documented this library more but eventualy, via trial and error and a lot of hair pulling, I have a program that can call any method in any class dynamically, pass in parameters, read the changed values on the return and display the results of a function or error if one occurs.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top