core.sys.windows.com.ComObject apparently has wrongly laid out Vtable

Carl Sturtivant sturtivant at gmail.com
Tue Mar 19 23:36:39 UTC 2024


On Tuesday, 19 March 2024 at 18:35:38 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
> It's worth noting that for every class and interface in a given 
> class hierarchy, each have different vtables for a given object.

Nevertheless, a given virtual method may occur with the same 
index in the Vtable of a class and in the Vtable of a class that 
inherits from it and overrides that method, so dynamic lookup 
finds a given method in a given position in a Vtable irrespective 
of the exact class in the hierarchy it occurs in: statically 
determined code can then look it up in the Vtable by its fixed 
index at the point in source that a method call occurs. And the 
case of COM this position is determined by the COM interface 
being implemented, where AddRef is always in position 1 after 
QueryInterface for example.

> This is why you must cast the D object to IUnknown first before 
> inspecting its reference.

I do not think this follows, either for a regular D object or a 
COM object. For the first the class hierarchy can determine the 
order of the virtual methods and overriding doesn't change the 
index of a method with a given signature. For a COM object the 
order of the methods in the Vtable is determined by the COM 
interface that the object is implementing. In the case of this 
thread, it's determined by the definition of IUnknown in COM.

Specifically, the ComObject class in D inherits from D's IUnknown 
interface and this is modeling implementing the COM interface 
IUnknown with an object with methods in positions 0,1,2 in the 
Vtable implementing QueryInterface, AddRef and Release.

It should be possible to cast a ComObject which by definition 
implements the COM interface IUnknown into a pointer to its first 
word, which external COM expects to contain a pointer to its 
Vtable, which external COM expects to contain pointers to those 
three methods in positions 0,1,2.

However this casting doesn't produce a pointer to the COM object 
needed in any external COM context. It produces a pointer 16 
bytes short of that object, which makes no sense semantically. 
What is it a pointer to? Something hidden by the implementation 
that does not function as a COM object externally.

Casting to a pointer is producing an implementation dependent 
pointer to an object NOT defined in source that happens to seem 
to contain offset down two words the actual object that we have 
defined in source, and the object pointed to seems to have a 
bogus Vtable for COM purposes that doesn't work. We have no 
reason whatsoever to be given access to this outer object. D does 
not define what it is! And D is not producing a pointer to the 
COM object that we defined.

This is a semantic bug: it defines casting to a pointer to have 
silly undefined semantics.

Perhaps the reference to a COM object defined by a class that 
inherits IUnknown is secretly represented by a pointer to this 
outer object. That's no reason to have casting such a reference 
to a pointer not be to compute a pointer to the COM object inside 
that outer object, which is the only cast that has any meaning.










More information about the Digitalmars-d mailing list