Gaining Visual Basic OLE super-powers

Visual Basic in its various incarnations and off-springs has super-powers when it comes to OLE Automation, aka late-bound COM through IDispatch.

Where do they come from?

Super Powers?

For instance, when doing MS Word OLE automation, you can in VBS and VBA write things like

WordApp.Documents[1].Name

which in Delphi (and many others) has to be written as

WordApp.Documents.Item(1).Name

and it can also call some methods like

set v1 = WordApp.CentimetersToPoints(2.5)
set v2 = WordApp.InchesToPoints(2.5)

which Delphi, FreePascal, PowerBasic, Python, C++’s CComPtr and others are unable to call, and which instead result in an “unspecified error” without further description.

While trying to solve the above riddle, I found posts about it for various languages and frameworks, dating back to the beginning of the millennium with no solutions, just specific workarounds.

Until today that is, bit thanks to David Heffernan and Hans Passant, two StackOverflow super-stars.

The reason is that some “methods” like CentimetersToPoints aren’t methods, they’re really indexed properties that you can’t call as indexed properties (ie.  WordApp.CentimetersToPoints[2.5] will fail in Delphi as well).

The Magic Potion

If you want to get the same super-power, the fix is basically to not follow the spec when calling IDispatch.Invoke, and instead of using DISPATCH_METHOD, use DISPATCH_METHOD or DISPATCH_PROPERTYGET.

In Delphi’s ComObjDispatchInvoke function that means the

end else
  if (InvKind = DISPATCH_METHOD) and (ArgCount = 0) and (Result <> nil) then
    InvKind := DISPATCH_METHOD or DISPATCH_PROPERTYGET;

should be changed to just

end else
  if (InvKind = DISPATCH_METHOD) then
    InvKind := DISPATCH_METHOD or DISPATCH_PROPERTYGET;

And the call will now go through. So all the previously mentioned languages and environment that follow the spec are doomed to fail.

Similarly, investigations have showed that for some OLE automation properties “get” to pass, you need to use DISPATCH_METHOD or DISPATCH_PROPERTYGET, and using just DISPATCH_PROPERTYGET will fail.

Speculations

There is a suspicious bit in the MSDN documentation for Getting and Setting properties:

 Properties are accessed in the same way as methods, except you specify DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT instead of DISPATCH_METHOD. Some languages cannot distinguish between retrieving a property and calling a method. In this case, you should set the flags DISPATCH_PROPERTYGET or DISPATCH_METHOD.

Do you know a language that can’t distinguish between properties and methods? Visual Basic.

Given that Visual Basic was a primary user of OLE Automation, it’s likely using DISPATCH_PROPERTYGET or DISPATCH_METHOD all the time indiscriminately, so I’ll speculate that at some point, using both dispatch flags became the effective spec. I suppose Raymond Chen might be able to provide some further insight?

Bottom Line

DWScript COM Connector now has the same OLE Automation super-powers, and it’ll work without modifying the ComObj unit.

The COM connector uses its own IDispatch.Invoke wrapper, distinct from Delphi, which is incidentally also capable of working with Single precision floats (requires a workaround in Delphi).