1

I would like to use the tlbinf32.dll to read type info for a COM object. At the moment I have access to the pointer to the ITypeLib interface. I can use VTable offsets and DispCallFunc to manually call methods and navgate, however I was hoping to use the powerful builtin capabilities of that library.

I was thinking that since TLI.ClassInfoFromObject(Object As IUnknown) can be used to query the IDispatch::GetTypeInfo method, I could manually construct a dummy object that implements just this method to allow the TypeInfo to be read into memory. Similar to manually defining IEnumVariant where most of the methods just return E_NOTIMPL = &H80004001. Does this sound feasible? Is there a simpler way to access the TypeInfo from a pointer using VBA?


Update

To be clear, my problem is I can't find a way to declare the ITypeInfo interface and allow me to work with it directly - VBA accesses IUnknownfrom stole2.tlb so I can use that fine, but the only place I can find ITypeInfo declared is in mscorlib.dll, but it doesn't have the COMVisible attribute so there's no way to access it in VBA, AFAIK, and VBA doesn't have an equivalent to [ComImport] to let you define it with a GUID yourself. So I want to use tlbinf32.dll to save me having to use raw pointers.

Greedo
  • 4,967
  • 2
  • 30
  • 78
  • This needs details and/or clarity. ITypeLib (and associated interfaces) are the raw low-level interfaces that describe a type library, while tlbinf32 is an Automation-compatible library (created for VB/VBA) over the raw ones, they kinda do the same thing, but for different types of clients. I don't understand what you are trying to do? – Simon Mourier Jan 05 '21 at 13:43
  • @SimonMourier Exactly; I have accessed the raw interface through some COM hackery that lets me obtain more detailed versions than simply calling IDispatch::GetTypeInfo (which is what tlbinf32 does under the hood to get typeinfo from an automation object instance, I think). Now that I have the raw interface I'd like to somehow read that into tlbinf32.dll for slightly higher degree of abstraction. Hope that makes sense? – Greedo Jan 05 '21 at 16:09
  • @SimonMourier Also see update:) for clarification – Greedo Jan 05 '21 at 16:18
  • If you have an ITypeLib reference, then this type lib was loaded from somewhere. You should be able to get this type lib info and load it from scratch from tlbinf32 – Simon Mourier Jan 05 '21 at 16:49
  • @SimonMourier The typelib comes from some reverse engineering; I have an object for which I know a certain entry in the instance table (_not the vtable_, the actual object instance) points to a related ITypeLib instance (see [this project](https://github.com/rubberduck-vba/Rubberduck/blob/2d29c231796b9dbb784755ceecf0c7aaa753d0d2/Rubberduck.VBEEditor/ComManagement/TypeLibs/VBETypeLibsAccessor.cs#L16-L27) for an example of what I describe). And the object which holds those typelib ptr does not implement IDispatch. So in this case I can't easily find the parent typelib – Greedo Jan 05 '21 at 19:05
  • 1
    If you have an ITypeLib reference, ITypeLib::GetLibAttr should give you the type lib information (TLIBATTR) https://learn.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-tlibattr that you can use to load it from scratch with tlbinf32. – Simon Mourier Jan 05 '21 at 19:21

1 Answers1

2

Turns out tlbinf32.dll supports this out of the box but it's hidden. From the help file:

ITypeLib As IUnknown
TypeLibInfoFromITypeLib(ByVal ptlib As IUnknown) As TypeLibInfo

Inside every TypeLibInfo is a reference to an ITypeLib instance. In fact, the TypeLibInfo object can be viewed as a wrapper on the ITypeLib interface which is easier to program against than ITypeLib itself. To see if two TypeLibInfo objects actually refer to the same internal object, use VB's Is operator with the ITypeLib property of the two objects. The Is operator will usually return False for TypeLibInfo objects which actually correspond to the same underlying type, but not for the internal ITypeLib pointers. The ITypeLib property is settable, so you can put a TypeLibInfo object on top of an existing ITypeLib.

If you have an ITypeLib reference and want to use TLI objects, then you can call TLI.TypeLibInfoFromITypeLib to generate a fully functional TypeLibInfo object.

The ITypeLib property and TypeLibInfoFromITypeLib method are considered advanced features and are marked as hidden.

emphasis my own

... similar story for an ITypeInfo pointer

So how to use? Quite simple. First a way to get the IUnknown from a pointer. e.g:

Public Function ObjectFromObjPtr(ByVal Address As LongPtr) As IUnknown
    Dim result As IUnknown
    MemLongPtr(VarPtr(result)) = Address
    Set ObjectFromObjPtr = result
    MemLongPtr(VarPtr(result)) = 0
End Function

Private Property Let MemLongPtr(ByVal dest as LongPtr, ByVal value As LongPtr)
    CopyMemory ByVal dest, value, LenB(value)
End Property

Followed by the call

Dim ITypeLibPtr As LongPtr
ITypeLibPtr = ... 'get the raw pointer

Dim ITypeLibObj As IUnknown
Set ITypeLibObj = ObjectFromObjPtr(ITypeLibPtr)

Dim NiceTypeLib As tli.TypeLibInfo
Set NiceTypeLib = tli.TypeLibInfoFrom(ITypeLibITypeLibObj)

or words to that effect

Greedo
  • 4,967
  • 2
  • 30
  • 78
  • 1
    I can't edit a single character. If you do other edits then please change ```tli.TypeLibInfoFromITypeLibITypeLibObj)``` to ```tli.TypeLibInfoFromITypeLib(ITypeLibObj)```. Are you trying to get info about VBA classes or external libraries? I ask because I was under the impression that the ITypeLib that VBA uses at compile time is not available at runtime. I can get a pointer to the ITypeInfo interface (see [here](https://stackoverflow.com/questions/65507735/address-of-class-method-crash-on-x64)) via VBA but when I call ITypeInfo::GetContainingTypeLib I get a null pointer (HRESULT is S_OK) – Cristian Buse Jan 07 '21 at 11:54
  • @CristianBuse thanks for the correction, I just typed all that straight into the answer without ever actually running it:) Yeah I'm trying to inspect VBA classes, my approach is to mimic a method Rubber Duck uses to support its unit tests. NGL it's pretty involved and took me a long time to figure out, but [this](https://github.com/rubberduck-vba/Rubberduck/blob/2d29c231796b9dbb784755ceecf0c7aaa753d0d2/Rubberduck.VBEEditor/ComManagement/TypeLibs/TypeInfoVBEExtensions.cs#L141-L163) is where the trail of breadcrumbs starts... – Greedo Jan 07 '21 at 15:14
  • 1
    In fact [here](https://gist.github.com/Greedquest/1b9b0260408d1f7a2b3b175c9a2387de) is my current (WIP buggy) code. Basically, the VBE.References object has an instance table (not vtable, one level up) that lets you navigate some high level runtime TypeLibs. To get the tlbinf32 to work on 64 bits you need to follow the instructions in [this answer](https://stackoverflow.com/a/42581513/6609896) but tbh hacking a 32 bit dll to work in 64 bit env may well be the source of the bugs, so perhaps pointers and DispCallFunc are the way to go... Anyway this is a good start and lets you read some info – Greedo Jan 07 '21 at 15:20
  • Nice. Thanks for sharing. I will review and come back to you if I manage to think of anything useful. – Cristian Buse Jan 07 '21 at 15:29