Calling Functions and Accessing Properties

From Apache OpenOffice Wiki
Jump to: navigation, search



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( &param1); 
      param1.vt= VT_BSTR; 
      param1.bstrVal= SysAllocString( L"com.sun.star.reflection.CoreReflection"); 
      DISPPARAMS dispparams= { &param1, 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 DISPIDs are generated by the bridge, as required. There is no fixed mapping from member names to DISPIDs, 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 VARIANTs.

  //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).
Personal tools
In other languages