Tag Archives: ActiveX

When C++ Builder 6 fails to properly import COM Objects

In Borland C++ Builder 6, the code generated to import COM objects slightly differs from the one generated by previous versions of C++ Builder.
Specifically, the VARIANT date type is used instead of TVariant. Giving up its TVariant “smart wrapper” was a good move from Borland, but it broke backward compatibility with output parameters of some COM methods, which don’t receive a value anymore.

For example, below is the code generated by C++ Builer 4 for the FarPoint TfpSpread COM object (from file FPSpreadADO_TLB.h) :
[code lang=cpp]
VARIANT_BOOL __fastcall GetText(long Col, long Row, TVariant* Var)
{
_TDispID _dispid(/* GetText */ DISPID(252));
TAutoArgs<3> _args;
_args[1] = Col /*[VT_I4:0]*/;
_args[2] = Row /*[VT_I4:0]*/;
_args[3] = Var /*[VT_VARIANT:1]*/;
OleFunction(_dispid, _args);
return _args.GetRetVariant();
}
[/code]

When generated using C++ Builder 6, the code becomes :
[code lang=cpp]
VARIANT_BOOL __fastcall GetText(long Col, long Row, VARIANT* Var)
{
_TDispID _dispid(/* GetText */ DISPID(252));
TAutoArgs<3> _args;
_args[1] = Col /*[VT_I4:0]*/;
_args[2] = Row /*[VT_I4:0]*/;
_args[3] = Var /*[VT_VARIANT:1]*/;
OleFunction(_dispid, _args);
return _args.GetRetVariant();
}
[/code]

Notice the Var parameter, whose type was changed from TVariant* to VARIANT* : that’s the source of the problem.

The issue comes from the TAutoArgs class, more specifically from its array of Variant.
The Variant assignment operator (=) behaves differently depending if its RHS is a TVariant* or a VARIANT* :

  1. Variant = TVariant* : The Variant is initialized with a reference to the TVariant* object (vt = VT_BYREF|VT_VARIANT, and pvarVal receives a pointer to the TVariant*
  2. Variant = VARIANT* : the Variant ‘=’ operator assumes the VARIANT* is a VT_BOOL. Changes to the Variant are not reflected on the VARIANT*

To fix the problem, one must explicitly set the Variant as a reference to the VARIANT*. For example, the previous example must be changed to :
[code lang=cpp]
VARIANT_BOOL __fastcall GetText(long Col, long Row, VARIANT* Var)
{
_TDispID _dispid(/* GetText */ DISPID(252));
TAutoArgs<3> _args;
_args[1] = Col /*[VT_I4:0]*/;
_args[2] = Row /*[VT_I4:0]*/;
_args[3].vt = VT_BYREF|VT_VARIANT /*[VT_VARIANT:1]*/;
_args[3].pvarVal = Var;
OleFunction(_dispid, _args);
return _args.GetRetVariant();
}
[/code]

C++ builder EAccessViolation when calling Variant.OlePropertySet() for Excel Automation

After migrating an application from C++ Builder 4 to C++builder 6, the excel COM automation started to crash with error EAccessViolation at address 00000800 when calling the Variant.OlePropertySet(), OlePropertyGet() or OleFunction() methods, as in the following code :

[code lang=cpp]
Variant xlApp = Variant::CreateObject(“Excel.Application”);
xlApp.OlePropertySet(“Visible”, true); // causes the EAccessViolation
Variant workbooks = xlApp.OlePropertyGet(“Workbooks”);
Variant currentWorkbook ClasseurCourant = workbooks.OleFunction(“Open”, L”C:\\MyExcelFile.xls”);
[/code]
Excel-OlePropertySet-EAccessViolation
This code was working fine with Builder 4, it was also working fine when used in a brand new application, but it always crashed in the converted app. Given that many developers reported the same error, with no known fix, and that one couldn’t expect support for a 12 years old IDE, I eventually fixed the issue by bypassing the Borland Wrappers and using directly COM.
Continue reading