Sunday, August 23, 2015

Pointer to a pointer to a pointer

I never thought I'd ever use the datatype void**** in a real project. Yet I did. That's the datatype of a pointer to a smart pointer to a COM object, which contains a pointer to the virtual function table, which is an array of function pointers.

Are you lost yet? Let's recap. The virtual function table is an array of pointers, function pointers to be precise. The pointer to it, which by convention constitutes the first data element in a COM object, is a pointer to an array of pointers, type void**. The interface pointer to a COM object points at the object itself, which is to say, points at the first data element, so it's void***. A smart pointer object holds the interface pointer as its first and only data element (no virtual functions there), so a pointer to a smart pointer object is a pointer to its first data element, so it's void****.

Friday, August 14, 2015

Lack of a typelib is not a security fault

Amazing discovery of the day: Microsoft Word pops up a security prompt for a perfectly good macro if a reference to a typelib can't be resolved.

Here's the scenario. I've built a managed DLL with a COM-visible component to be called from a MS Word macro. When managed DLLs are built in the usual way, they don't have a type library resource in them. Dynamic type discovery for created Automation objects is supported by the framework, but the regular typelib-in-file discovery would fail - for DLLs, it's looking for a custom resource of type "TYPELIB" with ID 1. That's why you can't open a managed DLL in OLEView and see the types.

You can, however, export a .TLB file from a managed DLL either with the "tlbexp" utility, or with "regasm". Both come with the .NET framework. Google it up.

Enter MS Word and Visual Basic for Applications aka VBA, it's tried and true macro language. In order to reference a component library during macro development, one needs the typelib registered; the "References" window of the VBA editor presents a list of typelibs. So on the dev machine, I have the typelib registered anyway.

The runtime environment is not the same as the dev environment, one would think. On the runtime machine, do you need the typelib registered, too? Trick question. In theory, no. Once CLSIDs/IIDs of all relevant objects are stored in the project, and enums are resolved to integers, it should be possible to call methods without a typelib. In fact, JavaScript has no problem with creating and invoking a component without a registered typelib. But not VBA.

When invoked on a machine where the managed coclass is registered, but the respective typelib is not, you get the following message:

"The macro cannot be found or has been disabled because of your Macro security settings."

It's really neither. It's a dependency to the macro that can't be found.

The remedy is obvious: use tlbexp to generate a typelib, ship it along with the DLL, register when installing. A TLB file can't register itself, so some manual registry fiddling would be in order.