不使用 Helper 的实现

From Apache OpenOffice Wiki
< Zh‎ | Documentation
Revision as of 20:16, 13 July 2018 by Sancho (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search



下一节将介绍不使用帮助程序的可能的实现。如果要通过帮助程序模板实现多于规划的接口,这种实现非常有用。帮助程序模板只允许最多十个接口。本节还将介绍核心接口的工作方式。


XInterface 实现

对象生命周期通过通用基接口 com.sun.star.uno.XInterface 的方法 acquire()release() 来进行控制。这两种方法使用引用计数实现,即每使用一次 acquire(),计数器递增,每使用一次 release(),计数器递减。最后一次递减之后,对象“死亡”。在线程安全的模式下编程时,此计数器成员变量的修改通常通过一对名为 osl_incrementInterlockedcount()osl_decrementInterlockedcount()(包括 osl/interlck.h)的 sal 库函数执行。

Documentation caution.png 请注意编写代码时的符号冲突。将代码封装到一个单独的名称空间(例如 "my_sc_impl")是很常用的方式。问题是,在 Unix 上加载您的共享库时,运行时期间可能会发生符号冲突。
  namespace my_sc_impl
  {
  class MyService1Impl
      ...
  {
      oslInterlockedCount m_refcount;
  public:
      inline MyService1Impl() throw ()
          : m_refcount( 0 )
          {}
 
      // XInterface
      virtual Any SAL_CALL queryInterface( Type const & type )
          throw (RuntimeException);
      virtual void SAL_CALL acquire()
          throw ();
      virtual void SAL_CALL release()
          throw ();
      ...
  };
  void MyService1Impl::acquire()
      throw ()
  {
      // thread-safe incrementation of reference count
      ::osl_incrementInterlockedCount( &m_refcount );
  }
  void MyService1Impl::release()
      throw ()
  {
      // thread-safe decrementation of reference count
      if (0 == ::osl_decrementInterlockedCount( &m_refcount ))
      {
          delete this; // shutdown this object
      }
  }


queryInterface() 方法中,接口指针必须提供给对象的接口。这意味着,将 this 类型分别转换为由接口的 cppumaker 工具生成的纯粹的 C++ 虚类。必须返回所有支持的接口,包括已继承的接口,如 XInterface

  Any MyService1Impl::queryInterface( Type const & type )
      throw (RuntimeException)
  {
      if (type.equals( ::cppu::UnoType< Reference< XInterface > >::get()))
      {
          // return XInterface interface (resolve ambiguity caused by multiple inheritance from 
          // XInterface subclasses by casting to lang::XTypeProvider)
          Reference< XInterface > x( static_cast< lang::XTypeProvider * >( this ) );
          return makeAny( x );
      }
      if (type.equals( ::cppu::UnoType< Reference< lang::XTypeProvider > >::get()))
      {
          // return XInterface interface
          Reference< XInterface > x( static_cast< lang::XTypeProvider * >( this ) );
          return makeAny( x );
      }
      if (type.equals(( ::cppu::UnoType< Reference< lang::XServiceInfo > >::get()))
      {
          // return XServiceInfo interface
          Reference< lang::XServiceInfo > x( static_cast< lang::XServiceInfo * >( this ) );
          return makeAny( x );
      }
      if (type.equals( ::cppu::UnoType< Reference< ::my_module::XSomething > >::get()))
      {
          // return sample interface
          Reference< ::my_module::XSomething > x( static_cast< ::my_module::XSomething * >( this ) );
          return makeAny( x );
      }
      // querying for unsupported type
      return Any();
  }

XTypeProvider 实现

实现 com.sun.star.lang.XTypeProvider 接口时,有两个方法必须编码。第一个是 getTypes(),提供实现的所有实现的类型,不包括基本类型,例如 com.sun.star.uno.XInterface。第二个是 getImplementationId(),提供此组接口的唯一ID。上文提到的线程安全的实现如下所示:

  Sequence< Type > MyService1Impl::getTypes()
      throw (RuntimeException)
  {
      Sequence< Type > seq( 3 );
      seq[ 0 ] = ::cppu::UnoType< Reference< lang::XTypeProvider > >::get();
      seq[ 1 ] = ::cppu::UnoType< Reference< lang::XServiceInfo > >::get();
      seq[ 2 ] = ::cppu::UnoType< Reference< ::my_module::XSomething > >::get();
      return seq;
  }
  Sequence< sal_Int8 > MyService1Impl::getImplementationId()
      throw (RuntimeException)
  {
      static Sequence< sal_Int8 > * s_pId = 0;
      if (! s_pId)
      {
          // create unique id
          Sequence< sal_Int8 > id( 16 );
                  ::rtl_createUuid( (sal_uInt8 *)id.getArray(), 0, sal_True );
          // guard initialization with some mutex
          ::osl::MutexGuard guard( ::osl::Mutex::getGlobalMutex() );
          if (! s_pId)
          {
              static Sequence< sal_Int8 > s_id( id );
              s_pId = &s_id;
          }
      }
      return *s_pId;
  }


Documentation caution.png 通常,如果不知道调用的代码在做什么,调用陌生代码时,不要 acquire() 互斥对象(Mutex)。您永远不会知道陌生代码获取什么样的互斥对象,而这可以导致死锁。这就是为什么在获取初始化互斥对象之前要创建后一个值 (uuid)。成功获取互斥对象后,将再次检查 s_pID 的值并进行指定(如果以前未指定)。这就是“双重检查锁定”设计模式。


以上实现 ID 的初始化操作在特定平台不能正常运行。如果需要实现此操作的更佳方法,请参阅 高级UNO - 设计模式 - 双检测锁定

提供单个工厂

函数 component_getFactory() 为请求的实现提供单个对象工厂,以创建其中某个服务实现的对象实例。使用 cppuhelper/factory.hxx 的帮助程序,这可以通过以下代码快速实现:

  #include <cppuhelper/factory.hxx>
 
  namespace my_sc_impl
  {
  ...
  static Reference< XInterface > SAL_CALL create_MyService1Impl(
      Reference< XComponentContext > const & xContext )
      SAL_THROW( () )
  {
      return static_cast< lang::XTypeProvider * >( new MyService1Impl() );
  }
  static Reference< XInterface > SAL_CALL create_MyService2Impl(
      Reference< XComponentContext > const & xContext )
      SAL_THROW( () )
  {
      return static_cast< lang::XTypeProvider * >( new MyService2Impl() );
  }
  }
 
  extern "C" void * SAL_CALL component_getFactory(
      sal_Char const * implName, lang::XMultiServiceFactory * xMgr, void * )
  {
      Reference< lang::XSingleComponentFactory > xFactory;
      if (0 == ::rtl_str_compare( implName, "my_module.my_sc_impl.MyService1" ))
      {
          // create component factory for MyService1 implementation
          OUString serviceName( RTL_CONSTASCII_USTRINGPARAM("my_module.MyService1") );
          xFactory = ::cppu::createSingleComponentFactory(
              ::my_sc_impl::create_MyService1Impl,
              OUString( RTL_CONSTASCII_USTRINGPARAM("my_module.my_sc_impl.MyService1") ),
              Sequence< OUString >( &serviceName, 1 ) );
      }
      else if (0 == ::rtl_str_compare( implName, "my_module.my_sc_impl.MyService2" ))
      {
          // create component factory for MyService12 implementation
          OUString serviceName( RTL_CONSTASCII_USTRINGPARAM("my_module.MyService2") );
          xFactory = ::cppu::createSingleComponentFactory(
              ::my_sc_impl::create_MyService2Impl,
              OUString( RTL_CONSTASCII_USTRINGPARAM("my_module.my_sc_impl.MyService2") ),
              Sequence< OUString >( &serviceName, 1 ) );
      }
      if (xFactory.is())
          xFactory->acquire();
      return xFactory.get(); // return acquired interface pointer or null
  }


在以上的示例中,请注意在函数 ::my_sc_impl::create_MyService1Impl() 需要实例化类时,它被工厂对象调用。组件上下文 com.sun.star.uno.XComponentContext 提供给该函数,并且可能会传递给 MyService1Impl 的构造函数。

编写注册信息

在将组件注册到注册表数据库文件 (.rdb) 时,共享库组件加载程序将调用函数 component_writeInfo()。当 regcomp 调用注册表时,组件将有关它可以实例化的对象的信息写入注册表中。

  extern "C" sal_Bool SAL_CALL component_writeInfo(
      lang::XMultiServiceFactory * xMgr, registry::XRegistryKey * xRegistry )
  {
      if (xRegistry)
      {
          try
          {
              // implementation of MyService1A
              Reference< registry::XRegistryKey > xKey(
                  xRegistry->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                      "my_module.my_sc_impl.MyService1/UNO/SERVICES") ) ) );
              // subkeys denote implemented services of implementation
              xKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                  "my_module.MyService1") ) );
              // implementation of MyService1B
              xKey = xRegistry->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                  "my_module.my_sc_impl.MyService2/UNO/SERVICES") ) );
              // subkeys denote implemented services of implementation
              xKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM(
                  "my_module.MyService2") ) );
              return sal_True; // success
          }
          catch (registry::InvalidRegistryException &)
          {
              // function fails if exception caught
          }
      }
      return sal_False;
  }
Content on this page is licensed under the Public Documentation License (PDL).
Personal tools
In other languages