ECOM架构
ECOM是一个通用的、可扩展的框架,它可以定义抽象接口,并且可以识别接口的实现,还负责装载并管理它们。该框架:
可以识别所有特定接口的具体实现。
允许接口的客户动态指定应该使用哪一个接口实现。这个选择的过程被称为决议(resolution)。ECOM提供了一个默认的决议者,在需要的地方,接口定义可以提供它们自己自定义的决议者。
通过调用恰当的工厂函数(factory function)来实例化实现了接口的具体类的实例。
ECOM使用了客户机/服务器架构,ECOM客户类REComSession提供函数来列出、实例化以及销毁接口的实现。每个线程都存在一个单独ECOM客户会话实例,并且它可以被接口的实例化和析构代码所访问,这些代码使用了一组静态函数。
一个由ECOM插件实现的接口有两个特征,第一,它是一个定义了一组包含一个或多个纯虚函数的抽象类,第二,接口还必须提供一个或多个工厂方法,从而可以是客户实例化接口的实现对象。
工厂方法不会直接实例化对象,因为一个接口无法预测究竟哪个类实现了它。相反,工厂函数会将请求交给ECOM框架,而由框架在运行时动态地实例化恰当的实现类。为了决定实例化哪个实现,ECOM需要获得一点提示,这个提示可以是UID,也可以是文本,它们将被传递给决议者。还有一种情况是将特定接口所有实现的列表返回给调用者,再由调用者决定使用哪个实现。
ECOM接口的特性
* 接口将定义一组纯虚函数,它们将在具体实例中实现
* 接口必须提供一个或多个工厂函数,这些函数向ECOM传递信息,使其可以从正确的实现类实例化出对象
* 接口还必须为其客户提供释放方法,诸如析构函数可以使其被销毁,或者是诸如Release()或Close()之类的方法
* 一个ECOM接口定义还必须具有一个TUid数据成员,该成员由ECOM内部使用,出于清除的目的以此来标识实现类的实例
以下示例之,
class CCryptoInterface : public CBase
{
public:
enum TAlgorithm { EDES, E3DES, EAES, ERC2, ERC4 };
// 该类型的缺省对象实例化
IMPORT_C static CCryptoInterface* NewL();
// 实例化,通过aCue来指定使用哪个实现
IMPORT_C static CCryptoInterface* NewL(const TDesC8& aCue);
IMPORT_C virtual ~CCryptoInterface();
// 列出该接口的所有实现
IMPORT_C static void ListImplementionsL(RImplInfoPtrArray& aImplInfoArray);
public:
// 需要由具体实例来实现的接口函数
virtual void EncryptL(TDesC8& aPlaintext, TDesC8& aKey, TDes8& aCiphertext, CryptoInterface::TAlgorithm) = 0;
virtual void DecryptL(TDesC8& aCiphrtext, TDesC8& aKey, TDes8& aPlaintext, CryptoInterface::TAlgorithm) = 0;
private:
TUid iDtor_ID_Key; // 在清除中使用的标识符
};
工厂方法
不接受参数的NewL()重载形式会创建CCryphtoInterface默认实现的对象,有两种方法决定创建的默认实现,一是通过向ECOM传递UID来硬编码一个特定实现;另一中方法具有更松的耦合性,使用ECOM决议者,向决议者传递一些信息,使其能够进行实例化。例如,实例化它发现的第一个实现了接口的具体类。
第一种方法:
EXPORT_C CCryptoInterface* CCryptoInterface::NewL()
{
// 硬编码以在默认情况下使用CCryptoInterface
const TUid KSWCryptoUid = { 0x10008EE5 };
TAny* defaultCrypto = REComSession::CreateImplementationL(KSWCryptoUid, _FOFF(CCryptoInterface, iDtor_ID_Key));
return (reinterpret_cast<CCryptoInterface*>(defaultCrypto);
}
第二种方法接受一个参数,该方法会将参数传递给默认的ECOM决议者。决议者使用该参数,通过与接口注册实现的默认数据属性进行匹配,从而决定实例化哪个实现的具体实例。
// CCryptoInterface的接口UID
const TUid KCCryptoInterfaceUid = { 0x10008EE0 };
EXPORT_C CCryptoInterface* CCryptoInterface::NewL(const TDesC8& aCue)
{
// 使用默认ECOM决议者的决议
TEComResolverParams resolverParams;
resolverParams.SetDataType(aCue);
// 允许在字符串匹配中使用通配符
resolverParams.SetWildcardMatch(ETrue);
TAny* cryptoInterface = REComSession::CreateImplementationL(KSWCryptoUid, _FOFF(CCryptoInterface, iDtor_ID_Key), NULL, resolverParams);
return (reinterpret_cast<CCryptoInterface*>(cryptoInterface);
}
第三个参数可以用于向具体类的初始化方法传递数据。如果CreateImplementationL()根据给出的提示找不到恰当的接口实现,它就会以KErrNotFound异常退出。
REComSession提供了一个ListImplementationsL()函数,该函数返回关于给定接口的实现的信息,这些内容都包装在RImplInfoPtrArray类的对象中,这可以用于向客户提供所有有效接口实现类的列表。
EXPORT_C void CCryptoInterface::ListImplementationsL(RImplInfoPtrArray& aImplInfoArray)
{
REComSession::ListImplementationsL(KCCryptoInterfaceUid, aImplInfoArray);
}
在CCryptoInterface的虚析构函数中,它会将iDtor_ID_Key作为识别对象用的参数来调用ECOM框架。
EXPORT_C CCryptoInterface::~CCryptoInterface()
{
// 通过ECOM,该对象已被删除
REComSession::DestroyedImplementation(iDtor_ID_Key);
}
实现一个ECOM接口
具体类的实现必须定义在一个ECOM插件的dll中,该dll是以mmp文件中TARGETTYPE dll来构建的。在一个dll中,一个ECOM接口集合可能包含一个或多个ECOM接口的一个或多个实现。
除了接口函数,每个实现必须向ECOM"注册"一个实例化函数,即示例中的静态NewL()工厂函数。当调用REComSession::CreateImplementation()指定类直接决议或根据提示决议某个实现时,ECOM会调用类的NewL()工厂函数。
一个dll通过导出一个标准函数(ImplementationGroupProxy())向ECOM“注册”这些实例化函数。该标准函数返回一个指向TImplementationProxy对象数组的指针,而且它是一个多态dll导出的唯一函数。每个TImplementationProxy对象代表一个单独的实现类,其中还包含了可以识别实现的TUid以及一个指向其实例化方法的指针。
http://hi.baidu.com/richiechyi/blog/item/2ba5ab221ac6fff7d6cae2a1.html