ECom是一種Symbian的plugin,他的想法類似design pattern的Factory模式,只是把類似的概念套用到Symbian的dll裡面,
讓dll中各個class可以視不同情況分別被執行,只要設計時依照當初講好的interface來寫,未來要新增class時就像套一層插件,
很方便就能跑這個class的功能了,而不用改動很多地方,保持程式的模組化。
只是ECom framework中是利用Symbian的C/S架構,而ECom server是包好在Symbian內的,因此,要讓server懂得launch class,要依照協議寫interface。
示意圖:
以Symbian 9.1內建的example說明:
1.interface.h:
定義interface的class,如CExampleInterface。
CExampleInterface這個class的角色,就像Factory的泛型。
const TUid KCExampleInterfaceUid = {0x10009DC0};
class CExampleInterface : public CBase
{
public:
struct TExampleInterfaceInitParams
{
TInt integer;
const TDesC* descriptor;
};
static CExampleInterface* NewL(const TDesC8& aMatchString);
virtual ~CExampleInterface();
static void ListAllImplementationsL(RImplInfoPtrArray& aImplInfoArray);
virtual void DoMethodL(TDes& aString) = 0;
protected:
//Default c'tor
inline CExampleInterface();
private:
// Unique instance identifier key
TUid iDtor_ID_Key;
};
2.interface.inl:
定義interface中各初始化的內容,在NewL()中須透過EComSession跟Server溝通,告訴ECom server現在要建立的是KCExampleInterfaceUid這個interface的實體。
inline CExampleInterface* CExampleInterface::NewL(const TDesC8& aMatchString)
{
// Set up the interface find for the default resolver.
TEComResolverParams resolverParams;
resolverParams.SetDataType(aMatchString);
resolverParams.SetWildcardMatch(ETrue); // Allow wildcard matching
// Set up some empty initialisation parameters
TExampleInterfaceInitParams initParams;
initParams.integer = 0;
initParams.descriptor = NULL;
return REINTERPRET_CAST(CExampleInterface*,
REComSession::CreateImplementationL(KCExampleInterfaceUid,
_FOFF(CExampleInterface,iDtor_ID_Key),
&initParams,
resolverParams));
}
inline void CExampleInterface::ListAllImplementationsL(RImplInfoPtrArray& aImplInfoArray)
{
REComSession::ListImplementationsL(KCExampleInterfaceUid, aImplInfoArray);
}
3.CImplementationClassOne.h,CImplementationClassOne.cpp:
定義自己需要的plugin class及這個plugin要做的事的內容,要繼承CExampleInterface。
class CImplementationClassOne : public CExampleInterface
{
public:
static CImplementationClassOne* NewL(TAny* aInitParams);
~CImplementationClassOne();
// Implementation of CExampleInterface
void DoMethodL(TDes& aString);
private:
CImplementationClassOne(TAny* aParams);
void ConstructL();
private:
// Data to pass back from implementation to client
HBufC* iDescriptor;
// Parameters taken from client
CExampleInterface::TExampleInterfaceInitParams* iInitParams;
};
4.proxy.cpp:
定義我們所實作的class名稱及UID的對應,存到ImplementationTable這個array。
實作ImplementationGroupProxy函式並匯出。
const TImplementationProxy ImplementationTable[] =
{
IMPLEMENTATION_PROXY_ENTRY(0x10009DC3, CImplementationClassOne::NewL),
IMPLEMENTATION_PROXY_ENTRY(0x10009DC4, CImplementationClassTwo::NewL)
};
EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
{
aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
return ImplementationTable;
}
5.rss檔:
定義dll的UID、要實作那個interface的UID、實作class的Implentation_uid,透過這個檔的定義跟系統註冊。
RESOURCE REGISTRY_INFO theInfo
{
// UID for the DLL
dll_uid = 0x10009DB1;
// Declare array of interface info
interfaces =
{
INTERFACE_INFO
{
// UID of interface that is implemented
interface_uid = 0x10009DC0;
implementations =
{
// Info for CImplementation1
IMPLEMENTATION_INFO
{
implementation_uid = 0x10009DC3;
version_no = 1;
display_name = "Implementation 1";
default_data = "text/wml||This is the type of data that this implementation understands. (Can be anything which will allow the resolver to identify this implementation as the correct one at run time. In this case it is a mime type).";
opaque_data = "test_params";
},
// Info for CImplementation2
IMPLEMENTATION_INFO
{
implementation_uid = 0x10009DC4;
version_no = 1;
display_name = "Implementation 1||Copyright � 1997-2001 Symbian Ltd. All Rights Reserved.||";
default_data = "text/xml||Type of data handled";
opaque_data = "";
}
};
}
};
}
6.InterfaceClient.cpp:
在這個自行定義的exe檔中,即可透過實體化interface,調用NewL()時就會要求ECom server,
實體化並執行ImplementationTable中的plugin class(dll)。
//把proxy table中所有plugin都執行一次
void TInterfaceClient::GetByDiscoveryL()
{
// Read info about all implementations into infoArray
RImplInfoPtrArray infoArray;
// Note that a special cleanup function is required to reset and destroy
// all items in the array, and then close it.
TCleanupItem cleanup(CleanupEComArray, &infoArray);
CleanupStack::PushL(cleanup);
CExampleInterface::ListAllImplementationsL(infoArray);
// Loop through each info for each implementation
// and create and use each in turn
CExampleInterface* ex;
TBuf<255> buf;
for (TInt i=0; i< infoArray.Count(); i++)
{
// Slice off first sub-section in the data section
TPtrC8 type = infoArray[i]->DataType();
type.Set(type.Left(type.Locate('|')));
// Need to convert narrow descriptor to be wide in order to print it
buf.Copy(type);
// Create object of type and call its function
ex = CExampleInterface::NewL(type);
CleanupStack::PushL(ex);
ex -> DoMethodL(buf);
CleanupStack::PopAndDestroy(); //ex
ex = NULL;
buf.Zero();
}
// Clean up
CleanupStack::PopAndDestroy(); //infoArray, results in a call to CleanupEComArray
}
//執行特定的plugin
void TInterfaceClient::GetBySpecificationL()
{
// Prepare data to pass to implementation
CExampleInterface::TExampleInterfaceInitParams p;
p.integer = 0;
// Get the implementation that has a data identifier text/xml
_LIT8(KSpec,"text/xml");
CExampleInterface* ex1 = CExampleInterface::NewL(KSpec,p);
CleanupStack::PushL(ex1);
TBuf<100> buf;
ex1 -> DoMethodL(buf);
CleanupStack::PopAndDestroy(); //ex1
}
如此,自行定義的exe裡面就可以要求dll中的所有plugin都執行一遍,或是擇某一執行。