Using TLBINF32's InvokeHookArray?

Posted on 2000-05-05
Last Modified: 2008-02-20
I have a generic MTS Object Tester app (yes, this relates to a question I asked a couple of days ago) which needs to be able to call any method of an object without having preknowledge of the object's interface.

I am successfuly using the InvokeHookArray method from TLBINF32 with simple variable types, passed ByRef, like strings, integers, longs, etc. What I am having trouble with is passing a Variant array ByRef.

Some code I found from the TlbInf32 help files looks something like this:

Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
  (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" _
  (Ptr() As Any) As Long

Dim obj As Object
Dim args() As Variant
Dim i As Integer
Dim iArr() As Integer
Dim vt As Integer
Dim InvokeID As Long
  'Call Foo(i As Integer, iArr() As Integer)
  ReDim args(1)
  'Use this code only with variable sized arrays.
  args(0) = VarPtrArray(iArr)
  CopyMemory args(0), vt, 2
  args(1) = VarPtr(i)
  vt = VT_BYREF Or VT_I2
  CopyMemory args(1), vt, 2
  TLI.InvokeHookArray obj, "Foo", INVOKE_FUNC, args

Like I said, this works fine for simple types, anybody have any ideas on how to use this to pass a variant array?
Question by:garymather
  • 7
  • 6
LVL 28

Expert Comment

ID: 2781051

Author Comment

ID: 2781103

Nope, the way they are using the InvokeHookArray here passes the variables ByVal, not ByRef. According to the TlbInf32 documentation, you have to manipulate the variable using RtlMoveMemory to add the VT_BYREF bit to the variables declaration, or words to that effect. The documentation states that if you fill the "reverse" array with simple VB code, the variables are passed ByVal. I want to pass them ByRef.
LVL 28

Expert Comment

ID: 2781129
what is happening when you apply the code sample provided from the tlbinf32 documentation?
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

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.


Author Comment

ID: 2781209
I get an Automation Error.

Here's the code that I am using:

ReDim varReverse(UBound(varParameters)) As Variant

ReDim aryString(UBound(varParameters)) As String
ReDim aryVariant(UBound(varParameters)) As Variant

lm = UBound(varParameters)
ln = 0
For Each objParameter In objMember.Parameters

   Select Case objParameter.VarTypeInfo.VarType
      Case VT_BSTR
         aryString(ln) = varParameters(ln)
         lngByteLen = Len(aryString(ln))
         varReverse(lm) = VarPtr(aryString(ln))
      Case VT_VARIANT
         aryVariant(ln) = varParameters(ln)
         lngByteLen = GetLengthInBytes(aryVariant(ln))
         varReverse(lm) = VarPtr(aryVariant(ln))
   End Select

   intVarType = VT_BYREF Or objParameter.VarTypeInfo.VarType
   If IsArray(varParameters(ln) Then
      intVarType = intVarType Or VT_ARRAY
   End If
   Call CopyMemory(varReverse(lm), intVarType, lngByteLen)

   lm = lm - 1
   ln = ln + 1

varReturn = TLI.InvokeHookArray(objMTS, objItem.MemberId, INVOKE_FUNC, varReverse)

The GetLengthInBytes simple get the length of each of the elements in the array.

LVL 28

Expert Comment

ID: 2781245
what sort of debugging have you tried?  perhaps place a msgbox after each call to CopyMemory to see if, in fact, the proper values are being copied to it

Author Comment

ID: 2781290
I've single stepped it and checked all the vars. When I check the varReverse(lm) for the Variant array after the CopyMemory, I get :
"VB6.EXE Application Error
The instruction at "0x0fc03042" referenced memory at "0x0e0001d". The memory could not be "read".
LVL 28

Expert Comment

ID: 2781391
try foregoing the VarPtr step and leave the element of that array empty and then call copymemory.  see if the data is transferred.  if that makes no difference, try passing the second parameter ByVal

CopyMemory varReverse(lm), ByVal intVarType, lngByteLen


Author Comment

ID: 2781420
Nope, both of these generate the same VB6.EXE Application error....
LVL 28

Expert Comment

ID: 2781522
i apologize for not being more than just another debugging tool...i have been unable to find a direct answer to this problem anywhere.

this array is declared as variant and is then filled with pointer values of another array yes?  we then determine the number of bytes in this array.  as a string it is the length of the string since characters are 1 byte values.  however when we perform copymemory we are telling it to copy lngByteLen bytes from the source to our destination. our source is just an integer though.  i think perhaps this could be part of the problem.


Author Comment

ID: 2781638
This was my initial thought. It looked confusing that the pSrc was an integer and not a pointer. But the fact remains that this method works perfectly when you are working with simple data types such as String, Integer etc. I wrote a simple MTS object that had a number of functions that took only one parameter, eg. TestFunc(aString As String) etc, In these functions I was able to manipulate the variable that was passed ByRef and the results of this manipulation were visible from the client.

I have searched numerous sites on the web but to no avail. This is my last resort. I even tried passing the variant array ByVal and other simple variables that I wanted to manipulate ByRef, but this fails. It seems it wants them all passed ByRef or all passed ByVal, no mixture of the two.
LVL 28

Accepted Solution

AzraSound earned 200 total points
ID: 2781736
have you tried ByVal VarPtr(varReverse(lm)) and ByVal VarPtr(intVarType)??

possibly declare the varReverse array explicitly as a byte array and change it back later if you need to

maybe just pass 2& as the length to ensure its only reading 2 bytes


Author Comment

ID: 2781825
It never ceases to amaze me how stupid  one person can be! After reading your post it suddenly dawned on me that I was passing the number of bytes occupied by the parameter being passed, AND NOT THE NUMBER OF BYTES OCCUPIED BY AN INTEGER (intVarType) WHICH IS 2!!!!!!!!

So the final call is Call CopyMemory(varReverse(lm), intVarType, 2) and it works perfectly!

Thanks, you deserve the points if for nothing other than highlighting the error of my ways!
LVL 28

Expert Comment

ID: 2781840
i cant tell you how many times i've stared at code where the error was the most ridiculous thing.  we both missed this one, it must be contagious. regardless, i'm glad its working for you now.  take care.

Featured Post

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

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.

Question has a verified solution.

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

Suggested Solutions

Have you ever wanted to restrict the users input in a textbox to numbers, and while doing that make sure that they can't 'cheat' by pasting in non-numeric text? Of course you can do that with code you write yourself but it's tedious and error-prone …
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 Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…

828 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