Difference between revisions of "Zh/Documentation/DevGuide/WritingUNO/C++/Provide Implementation Environment"
m (New page: {{Documentation/DevGuide/WritingUNOTOC/Zh |WritingUNO2d=block |ShowPrevNext=block |PrevPage=Zh/Documentation/DevGuide/WritingUNO/C++/Write Registration Info Using a Helper Method |NextPage...) |
m |
||
| Line 1: | Line 1: | ||
| − | {{Documentation/DevGuide/WritingUNOTOC | + | {{Documentation/DevGuide/WritingUNOTOC |
|WritingUNO2d=block | |WritingUNO2d=block | ||
|ShowPrevNext=block | |ShowPrevNext=block | ||
| − | |PrevPage= | + | |PrevPage=Documentation/DevGuide/WritingUNO/C++/Provide Implementation Environment |
| − | |NextPage= | + | |NextPage=Documentation/DevGuide/WritingUNO/C++/Storing the Service Manager for Further Use |
}} | }} | ||
| − | [[ | + | [[zh:Zh/Documentation/DevGuide/WritingUNO/C++/Implementing without Helpers]] |
| − | {{DISPLAYTITLE: | + | {{DISPLAYTITLE:不使用 Helper 的实现}} |
| − | + | __NOTOC__ | |
| − | <!--[SOURCE:Components/CppComponent/ | + | 下一节将介绍不使用帮助程序的可能的实现。如果要通过帮助程序模板实现多于规划的接口,这种实现非常有用。帮助程序模板只允许最多十个接口。本节还将介绍核心接口的工作方式。 |
| + | |||
| + | |||
| + | |||
| + | === XInterface 实现 === | ||
| + | |||
| + | |||
| + | 对象生命周期通过通用基接口 <idl>com.sun.star.uno.XInterface</idl> 的方法 <code>acquire()</code> 和 <code>release()</code> 来进行控制。这两种方法使用引用计数实现,即每使用一次 <code>acquire()</code>,计数器递增,每使用一次 <code>release()</code>,计数器递减。最后一次递减之后,对象“死亡”。在线程安全的模式下编程时,此计数器成员变量的修改通常通过一对名为 <code>osl_incrementInterlockedcount()</code> 和 <code>osl_decrementInterlockedcount()</code>(包括 '''osl/interlck.h''')的 sal 库函数执行。 | ||
| + | |||
| + | <!--[SOURCE:Components/CppComponent/service1_impl.cxx]--> | ||
| + | {{Documentation/Caution|请注意编写代码时的符号冲突。将代码包装到单独的名称空间(例如 "<tt>my_sc_impl</tt>")是很常见的操作。问题是,在 Unix 上加载您的共享库时,运行时期间可能会发生符号冲突。}} | ||
| + | |||
| + | <source lang="cpp"> | ||
| + | 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 | ||
| + | } | ||
| + | } | ||
| + | </source> | ||
| + | |||
| + | |||
| + | 在 <code>queryInterface()</code> 方法中,接口指针必须提供给对象的接口。这意味着,将 this 类型分别转换为由接口的 '''cppumaker''' 工具生成的纯粹的 C++ 虚类。必须返回所有支持的接口,包括已继承的接口,如 <code>XInterface</code>。 | ||
| + | |||
| + | <!--[SOURCE:Components/CppComponent/service1_impl.cxx]--> | ||
| + | <source lang="cpp"> | ||
| + | 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(); | ||
| + | } | ||
| + | </source> | ||
| + | |||
| + | |||
| + | |||
| + | === XTypeProvider 实现 === | ||
| + | |||
| + | |||
| + | 实现 <idl>com.sun.star.lang.XTypeProvider</idl> 接口时,有两个方法必须编码。第一个是 <code>getTypes()</code>,提供实现的所有实现的类型,不包括基本类型,例如 <idl>com.sun.star.uno.XInterface</idl>。第二个是 <code>getImplementationId()</code>,提供此组接口的唯一ID。上文提到的线程安全的实现如下所示: | ||
| + | |||
| + | <!--[SOURCE:Components/CppComponent/service1_impl.cxx]--> | ||
| + | <source lang="cpp"> | ||
| + | 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; | ||
| + | } | ||
| + | </source> | ||
| + | |||
| + | |||
| + | {{Documentation/Caution|通常,如果不知道调用的代码在做什么,调用陌生代码时,不要 <tt>acquire()</tt> 互斥。您永远不会知道陌生代码获取什么样的互斥,而这可以导致死锁。这就是在获取初始化互斥之前创建后一个值 (uuid) 的原因。成功获取互斥后,将再次检查 s_pID 的值并进行指定(如果以前未指定)。这就是“双重检查锁定”设计模式。 | ||
| + | |||
| + | |||
| + | 以上实现 ID 的初始化操作在特定平台不能正常运行。如果需要实现此操作的更佳方法,请参阅 [[Zh/Documentation/DevGuide/AdvUNO/UNO Design Patterns and Coding Styles#Double-Checked Locking|高级UNO - 设计模式 - 双检测锁定]]。}} | ||
| + | |||
| + | |||
| + | |||
| + | === 提供单个工厂 === | ||
| + | |||
| + | |||
| + | 函数 <code>component_getFactory()</code> 为请求的实现提供单个对象工厂,即它可以提供创建服务实现之一的对象实例的工厂。使用 '''cppuhelper/factory.hxx''' 的帮助程序,这可以通过以下代码快速实现: | ||
| + | |||
| + | <!--[SOURCE:Components/CppComponent/service1_impl.cxx]--> | ||
<source lang="cpp"> | <source lang="cpp"> | ||
| − | + | #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 | ||
} | } | ||
</source> | </source> | ||
| − | + | 在以上的示例中,请注意在函数 <code>::my_sc_impl::create_MyService1Impl()</code> 需要实例化类时,它被工厂对象调用。组件上下文 <idl>com.sun.star.uno.XComponentContext</idl> 提供给该函数,并且可能会传递给 <code>MyService1Impl</code> 的构造函数。 | |
| + | |||
| + | |||
| + | |||
| + | === 编写注册信息 === | ||
| + | |||
| + | |||
| + | 在将组件注册到注册表数据库文件 ('''.rdb''') 时,共享库组件加载程序将调用函数 <code>component_writeInfo()</code>。当 '''regcomp''' 调用注册表时,组件将有关它可以实例化的对象的信息写入注册表中。 | ||
| + | <!--[SOURCE:Components/CppComponent/service1_impl.cxx]--> | ||
| + | <source lang="cpp"> | ||
| + | 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; | ||
| + | } | ||
| + | </source> | ||
{{PDL1}} | {{PDL1}} | ||
[[Category:文档/开发者指南/编写 UNO 组件]] | [[Category:文档/开发者指南/编写 UNO 组件]] | ||
Revision as of 07:30, 30 July 2008
- Class Definition with Helper Template Classes
- Implementing your own Interfaces
- Providing a Single Factory Using a Helper Method
- Write Registration Info Using a Helper Method
- Provide Implementation Environment
- Implementing without Helpers
- Storing the Service Manager for Further Use
- Create Instance with Arguments
- Multiple Components in One Dynamic Link Library
- Building and Testing C++ Components
下一节将介绍不使用帮助程序的可能的实现。如果要通过帮助程序模板实现多于规划的接口,这种实现非常有用。帮助程序模板只允许最多十个接口。本节还将介绍核心接口的工作方式。
XInterface 实现
对象生命周期通过通用基接口 com.sun.star.uno.XInterface 的方法 acquire() 和 release() 来进行控制。这两种方法使用引用计数实现,即每使用一次 acquire(),计数器递增,每使用一次 release(),计数器递减。最后一次递减之后,对象“死亡”。在线程安全的模式下编程时,此计数器成员变量的修改通常通过一对名为 osl_incrementInterlockedcount() 和 osl_decrementInterlockedcount()(包括 osl/interlck.h)的 sal 库函数执行。
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;
}
| 通常,如果不知道调用的代码在做什么,调用陌生代码时,不要 acquire() 互斥。您永远不会知道陌生代码获取什么样的互斥,而这可以导致死锁。这就是在获取初始化互斥之前创建后一个值 (uuid) 的原因。成功获取互斥后,将再次检查 s_pID 的值并进行指定(如果以前未指定)。这就是“双重检查锁定”设计模式。
|
提供单个工厂
函数 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). |