Calling Functions and Accessing Properties
The essence of Automation objects is the IDispatch interface. All function calls, including the access to properties, ultimately require a call to IDispatch::Invoke
. When using C++, the use of IDispatch
is rather cumbersome. For example, the following code calls createInstance("com.sun.star.reflection.CoreReflection"):
OLECHAR* funcname = L"createInstance"; DISPID id; IDispatch* pdispFactory= NULL; CLSID clsFactory= {0x82154420,0x0FBF,0x11d4,{0x83, 0x13,0x00,0x50,0x04,0x52,0x6A,0xB4}}; HRESULT hr= CoCreateInstance( clsFactory, NULL, CLSCTX_ALL, __uuidof(IDispatch), (void**)&pdispFactory); if( SUCCEEDED(pdispFactory->GetIDsOfNames( IID_NULL, &funcName, 1, LOCALE_USER_DEFAULT, &id))) { VARIANT param1; VariantInit( ¶m1); param1.vt= VT_BSTR; param1.bstrVal= SysAllocString( L"com.sun.star.reflection.CoreReflection"); DISPPARAMS dispparams= { ¶m1, 0, 1, 0}; VARIANT result; VariantInit( &result); hr= pdispFactory->Invoke( id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, &result, NULL, 0); }
First the COM ID for the method name createInstance()
is retrieved from GetIdsOfNames
, then the ID is used to invoke()
the method createInstance()
.
Before calling a certain function on the IDispatch
interface, get the DISPID
by calling GetIDsOfNames
. The DISPID
s are generated by the bridge, as required. There is no fixed mapping from member names to DISPID
s, that is, the DISPID
for the same function of a second instance of an object might be different. Once a DISPID
is created for a function or property name, it remains the same during the lifetime of this object.
Helper classes can make it easier. The next example shows the same call realized with helper classes from the Active Template Library:
CComDispatchDriver spDisp(pdispFactory); CComVariant param(L"com.sun.star.reflection.CoreReflection"); CComVariant result; hr= spUnk.Invoke1(L"createInstance",param, result);
Some frameworks allow the inclusion of COM type libraries that is an easier interface to Automation objects during development. These helpers cannot be used with UNO, because the SDK does not provide COM type libraries for UNO components. While COM offers various methods to invoke functions on COM objects, UNO supports IDispatch
only.
Programming of Automation objects is simpler with VB or JScript, because the IDispatch
interface is hidden and functions can be called directly. Also, there is no need to wrap the arguments into VARIANT
s.
//VB Dim objRefl As Object Set objRefl= dispFactory.createInstance("com.sun.star.reflection.CoreReflection")
//JScript var objRefl= dispFactory.createInstance("com.sun.star.reflection.CoreReflection");
Pairs of get/set functions following the pattern
SomeType getSomeProperty() void setSomeProperty(SomeType aValue)
are handled as COM object properties.
Accessing such a property in C++ is similar to calling a method. First, obtain a DISPID
, then call IDispatch::Invoke
with the proper arguments.
DISPID dwDispID; VARIANT value; VariantInit(&value); OLECHAR* name= L"AttrByte"; HRESULT hr = pDisp->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dwDispID); if (SUCCEEDED(hr)) { // Get the property DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; pDisp->Invoke(dwDispID, IID_NULL,LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispparamsNoArgs, &value, NULL, NULL); // The VARIANT value contains the value of the property // Sset the property VARIANT value2; VariantInit( value2); value2.vt= VT_UI1; value2.bval= 10; DISPPARAMS disparams; dispparams.rgvarg = &value2; DISPID dispidPut = DISPID_PROPERTYPUT; dispparams.rgdispidNamedArgs = &dispidPut; pDisp->Invoke(dwDispID, IID_NULL,LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL); }
When the property is an IUnknown*,IDispatch*
, or SAFEARRAY*
, the flag DISPATCH_PROPERTYPUTREF
must be used. This is also the case when a value is passed by reference (VARIANT.vt = VT_BYREF | ...
).
The following example shows using the ATL helper it looks simple:
CComVariant prop; CComDispatchDriver spDisp( pDisp); // get the property spDisp.GetPropertyByName(L"AttrByte",&prop); //set the property CComVariant newVal( (BYTE) 10); spDisp.PutPropertyByName(L"AttrByte",&newVal);
The following example using VB and JScript it is simpler:
//VB Dim prop As Byte prop= obj.AttrByte Dim newProp As Byte newProp= 10 obj.AttrByte= newProp 'or obj.AttrByte= 10
//JScript var prop= obj.AttrByte; obj.AttrByte= 10;
Service properties are not mapped to COM object properties. Use interfaces, such as com.sun.star.beans.XPropertySet to work with service properties.
Content on this page is licensed under the Public Documentation License (PDL). |