280 likes | 357 Views
the first step to COM. By Huang Yi-Chin 1998/7/28. Outline. 程式語言的危機 What’s COM? 以 C++ 實作 COM Interface COM Object Demo. 程式語言的危機(1/7). 牽一髮動全身 class FastString { char *m_psz; public: FastString(const char *psz); ~FastString(void); void Delete(void); // deletes this instance
E N D
the first step toCOM By Huang Yi-Chin 1998/7/28
Outline • 程式語言的危機 • What’s COM? • 以C++實作COMInterface • COM Object • Demo
程式語言的危機(1/7) • 牽一髮動全身 class FastString { char *m_psz; public: FastString(const char *psz); ~FastString(void); void Delete(void); // deletes this instance int Length(void) const; int Find(const char *psz) const; // returns offest };
ApplicationA ApplicationB ApplicationC FastString.obj FastString.obj FastString.obj 程式語言的危機(2/7) • Client各有一份FastString.obj
程式語言的危機(3/7) • 動態連結 class __declspec(dllexport) FastString { char *m_psz; public: FastString(const char *psz); ~FastString(void); void Delete(void); // deletes this instance int Length(void) const; int Find(const char *psz) const; // returns offest };
ApplicationA ApplicationB ApplicationC 程式語言的危機(4/7) FastString Import Library FastString.dll
程式語言的危機(5/7) • 版本更新時的問題 // FastString ver 2.0 class __declspec(dllexport) FastString { const int m_cch; // count of character char *m_psz; public: FastString(const char *psz); ~FastString(void); void Delete(void); // deletes this instance int Length(void) const; int Find(const char *psz) const; // returns offest };
ApplicationA Ver 2.0 ApplicationB Ver1.0 程式語言的危機(6/7) Sizeof(FastString)==8 Sizeof(FastString)==8 Sizeof(FastString)==4 FastString.dll Ver 2.0 Sizeof(FastString)==4 ApplicationC Ver1.0
程式語言的危機(7/7) • 各程式語言之間連結困難 • 無法使用舊有的函式庫 • So, we need... • 一套建構在binary code的基礎上,能使各種語言能互相溝通的機制。 • COM : MicroSoft • CORBA : OMG
What’s COM? • COM的簡史 • DDE (Dynamic Data Exchange) • OLE (Object Linking and Embedding) • COM是一種規格 • 規定了製作具有動態替換元件的方法 • Client端程式能與軟體元件相互溝通
軟體元件的概念 Monolithic Application Component Application A B C new C D E
COM元件的基本要求 • 元件必須以動態連結方式與Client連結 • 元件必須封裝(隱藏)實作上的細節 • 語言獨立性 • 元件必須以Binary Code存在 • 元件升級後必須仍與新舊版本的Client程式相容 • 元件必須具有網路透通性
COM Object、Interface與Client SCV(Object) I_Gather DB.LittleStar (Client) I_BuildStructure Marine(Object) I_Patrol I_Attack
以C++實作COM介面(1/3) • Virtual Function • declare: virtual MyFun() =0; • Interface / declaration class // interface.h class IFastString { public : virtual int Length(void) const=0; virtual int Find(const char *psz) const=0; };
以C++實作COM介面(2/3) • Object / implementation class // object.h #include "interface.h" class FastString : public IFastString { const int m_cch; // count of characters char *m_psz; public: FastString(const char *psz); ~FastString(void); int Length(void) const; int Find(const char *psz) const; // returns offest }; Ex:Demo1
FastString &Length Length vptr m_cch &Find Find m_psz 以C++實作COM介面(3/3) • Why Virtual Function works? IFastString &Length vptr &Find
多重介面與繼承(1/2) • 當物件想要擴充介面的功能時,必須實作另一組介面:(Ex:Demo2) // interface.h ///// class IExtensibleObject { public : virtual void *Dynamic_Cast(const char *pszType)=0; virtual void Delete(void)=0; }; class IPersistentObject : public IExtensibleObject { public : virtual bool Load(const char *pszFileName)=0; virtual bool Save(const char *pszFileName)=0;}; class IFastString : public IExtensibleObject { public : virtual int Length(void) const=0; virtual char* GetString(void) const=0; virtual int Find(const char *psz) const=0;};
多重介面與繼承(2/2) • 採用多重繼承的方式來使用新的介面 #include "interface.h" class FastString : public IFastString ,public IPersistentObject { const int m_cch; // count of characters char *m_psz; public: FastString(const char *psz); ~FastString(void); // IExtensibleObject methods void *Dynamic_Cast(const char *pszType); void Delete(void); // deletes this instance // IFastString methods int Length(void) const; char* GetString(void) const; int Find(const char *psz) const; // returns offest // IPersistentObject methods bool Load(const char *pszFileName); bool Save(const char *pszFileName);};
參用計數問題(1/2) • Client不易管理COM Object釋放的時機 void terrenCommander() { IResearch *pIres; IProduce *pIpro; pIres = CreateFactory(“Terren Factory”); if (pIres) { pIres->ResearchSiegeTech(); } pIpro=Dynamic_Cast(“IProduce”); pIpro->produce(“Tank”); pIpro->Delete(); };
參用計數問題(2/2) • 由COM Object自行記錄參用計數 class IExtensibleObject { public : virtual void *Dynamic_Cast(const char *pszType)=0; //virtual void Delete(void)=0; virtual void DuplicatePointer(void)=0; virtual void DestroyPointer(void)=0; }; • Ex:Demo3
IUnknown(1/2) • 所有介面都必須繼承IUnknown class IExtensibleObject { public : virtual void *Dynamic_Cast(const char *pszType)=0; virtual void DuplicatePointer(void)=0; virtual void DestroyPointer(void)=0; }; interface IUnknown { virtual STDMETHODIMP QueryInterface(REFIID riid, void **ppv)= 0; virtual STDMETHODIMP_(ULONG) AddRef(void) =0; virtual STDMETHODIMP_(ULONG) Release(void)=0; }; • QueryInterface • 利用GUID來query介面
IUnknown(2/2) • IUnknown的構造 FastString IFastString &QueryInterface QueryInterface vptr &AddRef AddRef &Release Release &Find Find ….. …..
如何識別介面 • GUID (Globally Unique identifier) typedef struct _IID { unsigned long x; unsigned short s1; unsigned short s2; unsigned char c[8]; } IID; extern "C" const IID IID_IPersistentObject = { 0x8ca351c0, 0x24c0, 0x11d2, { 0x8d, 0xa1, 0x0, 0xa0, 0xc9, 0x5c, 0x43, 0x27}}; // {8CA351C0-24C0-11d2-8DA1-00A0C95C4327} • 可利用guidgen.exe產生GUID
HRESULT • HRESULT --32 bit的錯誤識別碼(defined in WINERROR.H) • 常見的HRESULT值 • S_OK • S_FALSE • E_NOINTERFACE • 利用巨集SUCCEEDED來判斷QueryInterface是否有取得interface的指標
COM物件 • 以CLSID作為識別碼 • Registry的概念 • Regedit.exe • \HKEY_CLASSES_ROOT\CLSID\ • ProgID命名慣例 • <應用程式名稱>.<元件名稱>.<版本> • ex.Office.Word.95
如何建立COM物件 • 使用CoCreateInstance IX* pIX = Null HRESULT hr = ::CoCreateInstance(CLSID_Component, NULL, CLSCTX_ALL, IID_IX, (void**) &pIX); if (SUCCEEDED(hr)) { pIX->Fx(); pIX->Release(); } • 必須在DLL裡實作DllGetObject()函式,取得IClassFactory指標,再利用IClassFactory->CreateInstance()來建立Object
Class Factory COM Library Class Factory Component Client DLL CoCreateInstance CoGetClassObject DllGetClassObject new ClsFactory new FastString time IClsFactory->CreateInstance (IID_IFastString) IClsFactory->Release() pIfs->Length()
實作上的細節 • 實作元件的DLL檔必須export下列method: • DllRegisterServer • DllUnregisterServer • DllGetObject • DllCanUnloadNow • 利用regsvr32.exe來登錄registry • Demo4: All in one...