Introduction
Sometimes the BCB 4 ActiveX header file generation process (part of Import
ActiveX Control) fails to create entries for properties and methods which are
documented for that control. In that situation, if you need those properties
and methods, you need a way to access them. In all liklihood, you do not have
the DISPID (which is the internal ID number of the property or method). This
article describes how to deal with that situation.
Accessing A Property
The following code shows how to access a property whose name is the only thing
known.
int __fastcall get_Count(void)
{
DISPID dispid;
HRESULT hr;
WideString Member("Count"); // Name of the property
BSTR szMember = (BSTR) Member; // BSTR Name of the property
hr =
GetIDsOfNames
(
IID_NULL,
(LPOLESTR __RPC_FAR *)&szMember,
1,
0,
&dispid
);
_TDispID _dispid(dispid); // Make the dispid usable by OlePropertyGet
TAutoArgs<0> _args; // Create a TAutoArgs structure
with room only for a return value - there are no parameters
OlePropertyGet(_dispid, _args); // Ask the control for the
property
return _args.GetRetVariant(); // Extract the control return
value from the passed args
};
Calling A Method With One Parameter
This is very similar to accessing a property, except that the OlePropertyGet
function is not used - it is replaced with OleFunction. The example also gets
back a return value - the value is a "Ptr" object, used to access
the IDispatch interface of the returned object.
SomethingPtr __fastcall Item(TVariant Index)
{
DISPID dispid;
HRESULT hr;
WideString Member("Item");
BSTR szMember = (BSTR) Member;
hr =
GetIDsOfNames
(
IID_NULL,
(LPOLESTR __RPC_FAR *)&szMember,
1,
0,
&dispid
);
_TDispID _dispid(dispid);
TAutoArgs<1> _args;
_args[1] = Index; // Parameter - note, this
is 1-based, not 0-based
OleFunction(_dispid, _args);
return (Some_tlb::SomethingPtr*)(LPDISPATCH)_args.GetRetVariant();
};
If you need to pass more arguments, simply set the TAutoArgs<1>
to use the number of parameters to be passed.
Where This Goes
These functions should be placed, body and all, in the class definition to
which they pertain in the _TLB.h file for the control. They will be inlined
if your compiler options allow.
Performance Optimization
Calls to GetIDsOfNames are potentially expensive. Though I have not tested
this, the following seems a likely optimization:
int __fastcall get_Count(void)
{
static DISPID dispid = -1; // A DISPID of 0 may be valid
HRESULT hr;
WideString Member("Count"); // Name of the property
BSTR szMember = (BSTR) Member; // BSTR Name of the property
if (dispid == -1)
{
hr =
GetIDsOfNames
(
IID_NULL,
(LPOLESTR
__RPC_FAR *)&szMember,
1,
0,
&dispid
);
};
_TDispID _dispid(dispid); // Make the dispid usable by OlePropertyGet
TAutoArgs<0> _args; // Create a TAutoArgs structure
with room only for a return value - there are no parameters
OlePropertyGet(_dispid, _args); // Ask the control for the
property
return _args.GetRetVariant(); // Extract the control return
value from the passed args
};
Obviously, one could also add error checking, to deal with the possibility
that the name is incorrect, or that something else goes wrong.
This code, however, is patterned after generated code and should be safe.
Conclusion
Controls which do not follow the standard expected by BCB for responding to
interrogation by the IDE at import time can still be used to their fullest with
this technique.
|