《高级软件工程(com基础:接口与实现.ppt》由会员分享,可在线阅读,更多相关《高级软件工程(com基础:接口与实现.ppt(54页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、高级软件工程(高级软件工程(COM基础:接口与实现)基础:接口与实现)内内 容容 基础部分基础部分综述综述接口接口实现实现高级部分高级部分包含与聚合包含与聚合COM与与VC自动化自动化DCOM2(1)COM的起源的起源 源于源于OLE:Object Link and Embedding OLE1 采用采用DDE(Dynamic Data Exchange)在不同的程序之间进行通信在不同的程序之间进行通信DDE缺点缺点:效率低效率低,稳定性不好稳定性不好,使用不方便使用不方便 COM是为克服上述不足而出现的是为克服上述不足而出现的 OLE2 以以 COM 为基础为基础 但但OLE未能体现未能体现
2、COM优点优点 1 综述综述COMCOM基础基础基础基础3(2)什么是什么是COM 构件对象模型构件对象模型:Component Object Model 客户与构件为了能够互操作而遵循的标准客户与构件为了能够互操作而遵循的标准 COM标准包括规范与实现两部分标准包括规范与实现两部分规范部分定义了构件之间的通信机制规范部分定义了构件之间的通信机制这些规范不依赖于任何特定的语言这些规范不依赖于任何特定的语言和操作系统和操作系统实现部分即实现部分即COM库库为为COM规范的具体实现提供一些核心服务规范的具体实现提供一些核心服务COMCOM基础基础基础基础4(3)COM构件构件以以 DLL或或EXE
3、形式发布的代码形式发布的代码与语言无关与语言无关以二进制形式发布以二进制形式发布可以在不妨碍客户的形式下被升级可以在不妨碍客户的形式下被升级可以透明地在网络上被重新分配可以透明地在网络上被重新分配构件与类构件与类:一个构件可以由多个类实现一个构件可以由多个类实现 接口与类接口与类:一个类可以实现多个接口一个类可以实现多个接口COMCOM基础基础基础基础5(4)COM库库(COM Library)功能功能:(1)实现客户方与服务器方实现客户方与服务器方COM应用的创建过程应用的创建过程(2)COM通过注册表查找本地服务器通过注册表查找本地服务器(即即EXE程序程序)以及程序名与以及程序名与CLS
4、ID的转换的转换(3)提供标准的内存控制方法提供标准的内存控制方法DCOM的实现提供了分布式环境下的通信机制的实现提供了分布式环境下的通信机制在操作系统层次在操作系统层次 以以DLL文件的形式存在文件的形式存在COMCOM基础基础基础基础6(5)COM特性特性语言无关性语言无关性为跨语言合作开发提供了统一标准为跨语言合作开发提供了统一标准并得到不同集成开发环境的支持并得到不同集成开发环境的支持 进程透明性进程透明性进程内服务程序进程内服务程序:DLL本地服务程序本地服务程序:EXE远地服务程序远地服务程序:DLL或或EXE实现进程透明性的关键是实现进程透明性的关键是COM库库它负责服务体的定位
5、它负责服务体的定位 管理对象的创建及对象与客户之间的通信管理对象的创建及对象与客户之间的通信复用性复用性包含方式包含方式 聚合方式聚合方式COMCOM基础基础基础基础7(6)COM发展趋势发展趋势操作系统操作系统 成为系统的基本软件模型成为系统的基本软件模型数据库数据库 OLE DB/ADO 以以 COM 的方式的方式为数据访问提供一致的接口为数据访问提供一致的接口Internet ActiveX包含了所有基于包含了所有基于COM的的Internet相关技术相关技术COM+增加增加MTS等服务等服务COMCOM基础基础基础基础82 COM接口接口COM接口是接口是COM规范的核心内容规范的核心
6、内容接口的意义接口的意义(略略)一个接口包含了一组函数一个接口包含了一组函数在在C+中中,可以用抽象基类来定义可以用抽象基类来定义COM接口接口接口的实现接口的实现:vtbl 指针指针 虚拟函数表虚拟函数表COMCOM基础基础基础基础9Vtbl指针指针虚拟函数表虚拟函数表pIX接口的内存结构接口的内存结构IX&Fx1&Fx2&Fx3&Fx4COMCOM基础基础基础基础10Vtbl的作用的作用:提高接口实现的灵活性提高接口实现的灵活性例子例子:一个一个实现接口实现接口IX的类的类CA,CA包含包含2个数据个数据:Vtbl指针指针虚拟函数表虚拟函数表IX&Fx1&Fx2&Fx3&Fx4Data1D
7、ata2pAFx1Fx2Fx3Fx4CACOMCOM基础基础基础基础11两个实例两个实例 共享同一共享同一Vtbl:Vtbl指针指针虚拟函数表虚拟函数表&Fx1&Fx2&Fx3&Fx4Data1Data2pA1pA2Fx1Fx2Fx3Fx4CAVtbl指针指针Data1Data2COMCOM基础基础基础基础12 接口特点接口特点实现级实现级二进制,独立于编程语言二进制,独立于编程语言稳定性稳定性客户与服务器依赖于接口客户与服务器依赖于接口继承性继承性便于扩展接口便于扩展接口,不提倡继承不提倡继承所有接口皆继承所有接口皆继承Iunknown)多态性:多态性:COMCOM基础基础基础基础13(1)
8、功能)功能提供:提供:生存期控制生存期控制接口查询接口查询 IUnknown的定义(的定义(IDL):):interface IUnkownvirtual HRESULT QueryInterface(const IID&,void*ppv)=0;virtual ULONG AddRef()=0;virtual ULONG Release()=0;IUnknownCOMCOM基础基础基础基础14Vtbl指针指针虚拟函数表虚拟函数表IXQueryInterfaceAddRefRelease&FxpAQueryInterfaceAddRefReleaseFxCA所有接口都必须继承所有接口都必须继承
9、IUnknownCOMCOM基础基础基础基础15IUnknown指针的获取指针的获取 IUnknown*CreateInstance();创建构件时,客户可以使用创建构件时,客户可以使用CreateInstance,而不是而不是new。CreateInstance的定义:的定义:IUnknown*CreateInstance()IUnknown*pI=static_cast(new foo);pI-AddRef();return pI;COMCOM基础基础基础基础16(2)引用计数)引用计数AddRef与与Release控制构件的生命期控制构件的生命期解决内存管理问题解决内存管理问题使构件能够
10、自己将自己删除使构件能够自己将自己删除使用规则使用规则返回接口指针之前调用返回接口指针之前调用 AddRef;使用完接口之后调用使用完接口之后调用Release;赋值之后调用赋值之后调用AddRef;COMCOM基础基础基础基础17引用计数的实现方式引用计数的实现方式:在什么层次上进行计数在什么层次上进行计数构件构件对象对象接口接口构件构件构件引用记数构件引用记数对象引用记数对象引用记数对象引用记数对象引用记数对象对象1对象对象2接口接口接口接口接口接口接口接口接口引用记数接口引用记数接口引用记数接口引用记数接口引用记数接口引用记数接口引用记数接口引用记数COMCOM基础基础基础基础18(3)
11、接口查询)接口查询一个一个COM对象(构件)可以实现多个接口对象(构件)可以实现多个接口使用使用QueryInterface查询某个构件是否支持某个特定的接口查询某个构件是否支持某个特定的接口 QueryInterfaceQueryInterface的的的的使用使用使用使用 void foo(Iunknown*pI)/Define a pointer for the interface.IX*pIX=NULL;/Ask for nterface IXHRESULT hr=pI-QueryUbterface(IID_IX,(void*)&pIX);/Check return value.If(S
12、UCCEEDED(hr)/Use interfacepIX-Fx();COMCOM基础基础基础基础19QueryInterfaceQueryInterface的实现的实现的实现的实现 假定存在类假定存在类 CA,继承接口继承接口 IX 与与 IY:HRESULT _sfdcall CA:QueryInterface(const IID&iid,void*ppv)if(iid=IID_IUnknown)*ppv=static_cast(this);else if(iid=IID_IX)*ppv=static_cast(this);else if(iid=IID_IY)*ppv=static_ca
13、st(this);else *ppv=NULL;return E_NOINTERFACE;static_cast(*ppv)-AddRef();return S_OK;COMCOM基础基础基础基础20QueryInterfaceQueryInterface的实现规则的实现规则的实现规则的实现规则QueryInterface返回的总是同一个返回的总是同一个IUnknown指针指针若客户曾经获取过某个接口若客户曾经获取过某个接口,那么它将总能获取此接口那么它将总能获取此接口客户可以再次获取已经拥有的接口客户可以再次获取已经拥有的接口客户可以返回到起始接口客户可以返回到起始接口若能够从某个接口获取某
14、特定接口若能够从某个接口获取某特定接口则可以从则可以从(该构件的该构件的)任意接口获取此接口任意接口获取此接口COMCOM基础基础基础基础21 新版本构件的处理新版本构件的处理COM接口永远不会变化接口永远不会变化:一个一个IID就是一个接口就是一个接口 通过发行新版本构件解决兼容性通过发行新版本构件解决兼容性当下列条件中的任何一个变化时当下列条件中的任何一个变化时应给新接口指定新应给新接口指定新IID:接口中函数数目接口中函数数目接口中函数顺序接口中函数顺序某个函数的参数某个函数的参数某个函数参数的顺序某个函数参数的顺序某个函数参数的类型某个函数参数的类型函数可能的返回值函数可能的返回值函数
15、返回值的类型函数返回值的类型等等不同版本接口的命名不同版本接口的命名:在老名称后加一个数字在老名称后加一个数字COMCOM基础基础基础基础223 COM实现实现(1)预备知识预备知识:DLLDLL是一个构件服务器是一个构件服务器EXE也可以是构件服务器也可以是构件服务器使用户在应用程序的运行过程中替换构件使用户在应用程序的运行过程中替换构件构件是构件是DLL中实现的接口集中实现的接口集DLL共享它们所链入的应用程序地址空间共享它们所链入的应用程序地址空间HRESULT向用户报告构件运行结果状况向用户报告构件运行结果状况“Here is the RESULT”WINERROR.H中进行定义中进行
16、定义用户可以定义自己的代码用户可以定义自己的代码COMCOM基础基础基础基础23GUID:Globally Unique IDentifier用于标识构件用于标识构件(CLSID)与接口与接口(IID)128位位(长整数长整数)由于空间足够大由于空间足够大 接口标识冲突较小接口标识冲突较小可以用编程的方法生成具有唯一性的可以用编程的方法生成具有唯一性的GUIDVC:UUIDGEN.EXE,GUIDGEN.EXE借鉴了借鉴了OSF的的UUID(DCE中的中的RPC使用使用).对对GUID值的传递通常通过引用进行值的传递通常通过引用进行COMCOM基础基础基础基础CLSID:CLaSs IDent
17、ifier24Windows 注册表注册表Windows操作系统的共享系统数据库操作系统的共享系统数据库包括包括 硬件硬件 软件软件 配置及用户等各种信息配置及用户等各种信息由由REGEDIT.EXE(95/98)REGEDIT32.EXE(NT)启动启动可以使用可以使用REGSVR32.EXE来注册某个构件来注册某个构件注册表是一个由许多元素构成的层次结构注册表是一个由许多元素构成的层次结构每一个元素均被称作是一个关键字每一个元素均被称作是一个关键字每一个关键字可以包含一系列子关键字等每一个关键字可以包含一系列子关键字等 例如:例如:HKEY_CLASSES_ROOTCLSIDProgID
18、等等COMCOM基础基础基础基础25COMCOM基础基础基础基础26COMCOM基础基础基础基础27(2)COM库库COM构件与客户皆需要完成的相同操作构件与客户皆需要完成的相同操作由由OLE32.DLL、OLE32.LIB实现实现COM库中常用的函数:库中常用的函数:初始化函数初始化函数与与GUID相关的函数相关的函数对象创建函数对象创建函数内存管理函数内存管理函数COMCOM基础基础基础基础28 在使用在使用COM库中的其他函数(除库中的其他函数(除CoBuildVersion)之前,进程必须先调用:之前,进程必须先调用:HRESULT CoInitialize(void*reserved
19、)在退出之前调用:在退出之前调用:void CoUninitialize(void*reserved)其他:其他:CoBuildVersionCoFreeUnusedLibraries OleInitialize建立在建立在CoInitialize基础之上基础之上 DCOM使用使用CoInitializeEx初始化函数:初始化函数:COMCOM基础基础基础基础29与与GUID(CLSID)相关的函数:相关的函数:例如:将例如:将GUID转换为一个字符串:转换为一个字符串:wchar_t szCLSID39;int r=:StringFromGUID2(CLSID_Component1,szCL
20、SID,39);其它:其它:StringFromCLSIDStringFromIIDCLSIDFromStringIIDFromStringIsEqualGUIDIsEqualIIDIsEqualCLSIDCLSIDFromProgIDCOMCOM基础基础基础基础30对象创建函数:对象创建函数:CoGetClassObjectCoCreateInstanceCoCreateInstanceExCoRegisterClassObjectCoRevokeClassObjectCoDisconnectObject内存管理函数:内存管理函数:CoTaskMemAllocCoTaskMemRealloc
21、CoTaskMemFreeCoGerMallocCOMCOM基础基础基础基础31(3)类厂类厂(Class Factory)能够创建其他构件的构件能够创建其他构件的构件(构件厂构件厂)其本身也是一个其本身也是一个COM对象对象支持一个特殊的接口支持一个特殊的接口 IClassFacroty每一个每一个COM对象类应该有一个相应的类厂对象对象类应该有一个相应的类厂对象COMCOM基础基础基础基础32CoCreateInstanceCOM库函数之一库函数之一HRESULT_stdcall CoCreateInstance(const CLSID&clsid,Iunkown*pIUnknownOut
22、er,DWORD dwClsContext,const IID&iid,void*ppv);clsid:待创建构件的标识;待创建构件的标识;pIUnknownOuter:用于聚合;:用于聚合;dwClsContext:限定所创建构件的上下文;:限定所创建构件的上下文;iid:构件上待使用接口的标识;:构件上待使用接口的标识;ppv:所返回接口的指针。:所返回接口的指针。COMCOM基础基础基础基础33一个使用例子:一个使用例子:IX*pIX=NULL;HRESULT he=:CoCreateInstance(CLSID_Component1,NULL,CLSCTX_INPROC_SERVER,
23、IID_IDX,(void*)&pIX);if(SUCCEEDED(hr)pIX-FX();pIX-Release();COMCOM基础基础基础基础34类厂类厂CoCreateInstance实际上实际上未直接创建未直接创建COM构件构件创建了一个被称为类厂的构件创建了一个被称为类厂的构件类厂构件的唯一功能是创建其他构件类厂构件的唯一功能是创建其他构件客户可以通过类厂所支持的接口来客户可以通过类厂所支持的接口来对类厂创建对类厂创建构件的过程加以控制构件的过程加以控制CoCreateInstance调用调用CoGetClassObject创建构件的标准接口是创建构件的标准接口是IClassFac
24、toryCOMCOM基础基础基础基础35CoGetClassObject创建类厂创建类厂HRESULT_stdcall CoGetClassObject(const CLSID&clsid,DWORD dwClsContext,COSERVERINFO*pServerInfo,/用于用于DCOMconst IID&iid,void*ppv /指向类厂中某个接口的指针指向类厂中某个接口的指针);COMCOM基础基础基础基础36IClassFactory 用于创建构件的标准接口用于创建构件的标准接口Interface IClassFactory:IUnknownHRESULT _stdcallCr
25、eateInstance(IUnknown*pUnknownOuter,const IID&iid,void*ppv);HRESULT _stdcall LockServer(BOOL block);未接收未接收CLSID:只能创建同某个:只能创建同某个CLSID相应的构件相应的构件IClassFactory2COMCOM基础基础基础基础37CoCreateInstance 与与 CoGetClassObject的关系:的关系:CoCreateInstance 通过通过 CoGetClassObject实现实现HRESULT CoCreateInstance(const CLSID&clsid
26、,IUnknown*pUnknownDuter,DWOED dwClsContext,const IID&iid,void*ppv)*ppv=NULL;IClassFactory*pIFactory=NULL;HRESULT hr=CoGetClassObject(clsid,dwClsContext,NULL,IID_IClassFactory,(void)*&pIFactory);if(SUCCEEDED(hr)hr=pIFactory-CreateInstance(pUnknownOuter,iid,ppv);pIFactory-Release();return hr;COMCOM基础基
27、础基础基础38在下列情况下应直接使用在下列情况下应直接使用CoGetClassObject 而应使用而应使用CoCreateInstance:(1)如果希望用不同于如果希望用不同于IClassFactory的某个创建接口的某个创建接口来创建构件来创建构件 例如例如 IClassFactory2(2)如果希望创建同一构件的多个实例如果希望创建同一构件的多个实例COMCOM基础基础基础基础 39(4)类厂的实现)类厂的实现CoGetClassObject需要需要DLL中的一个特定的函数中的一个特定的函数来创建构件的类厂来创建构件的类厂DllGetClassObject:STDAPI DllGetC
28、lassObject(const CLSID&clsid,const IID&iid,void*ppv);COMCOM基础基础基础基础40创建、调用构件的过程:创建、调用构件的过程:客户客户COM库库DLLCoGetClassObject调用调用CoGetClassObjectDllGetClassObjectIClassFactoryIXpIClassFactorypIXCOMCOM基础基础基础基础创建类厂创建类厂创建构件创建构件返回返回IClassFactory调用调用IClassFactory:CreateInstance返回返回IX调用调用IX:Fx41#include#include
29、#include Iface.hint main()CoInitialize(NULL);IX*pIX=NULL;HRESULT hr=:CoCreateInstance(CLSID_Component1,NULL,CLSCTX_INPROC_SERVER,IID_IX,(void*)&pIX);if(SUCCEEDED(hr)pIX-Fx();/Use interface IX.IY*pIY=NULL;hr=pIX-QueryInterface(IID_IY,(void*)&pIY);if(SUCCEEDED(hr)pIY-Fy();/Use interface IY.pIY-Release
30、();客户方代码客户方代码COMCOM基础基础基础基础(5)例子)例子42IZ*pIZ=NULL;hr=pIX-QueryInterface(IID_IZ,(void*)&pIZ);if(SUCCEEDED(hr)pIZ-Fz();pIZ-Release();pIX-Release();elsecout Client:ttCould not create component.hr=hex hr endl;/Uninitialize COM LibraryCoUninitialize();return 0;COMCOM基础基础基础基础43#include#include#include Ifac
31、e.h /Interface declarations#include Registry.h /Registry helper functionsstatic HMODULE g_hModule=NULL;/DLL module handlestatic long g_cComponents=0;/Count of active componentsstatic long g_cServerLocks=0;/Count of locks/Friendly name of componentconst char g_szFriendlyName=Inside COM,Ch 7 Example;/
32、Version-independent ProgIDconst char g_szVerIndProgID=InsideCOM.Chap07;服务器方代码服务器方代码COMCOM基础基础基础基础44class CA:public IX,public IY public:/IUnknownvirtual HRESULT _stdcall QueryInterface(const IID&iid,void*ppv);virtual ULONG _stdcall AddRef();virtual ULONG _stdcall Release();/Interface IXvirtual void _
33、stdcall Fx()cout Fx endl;/Interface IYvirtual void _stdcall Fy()cout Fy endl;/ConstructorCA();/DestructorCA();private:/Reference countlong m_cRef;COMCOM基础基础基础基础45HRESULT _stdcall CA:QueryInterface(const IID&iid,void*ppv)if(iid=IID_IUnknown)*ppv=static_cast(this);else if(iid=IID_IX)*ppv=static_cast(t
34、his);else if(iid=IID_IY)*ppv=static_cast(this);else*ppv=NULL;return E_NOINTERFACE;reinterpret_cast(*ppv)-AddRef();return S_OK;COMCOM基础基础基础基础46class CFactory:public IClassFactorypublic:/IUnknownvirtual HRESULT _stdcall QueryInterface(const IID&iid,void*ppv);virtual ULONG _stdcall AddRef();virtual ULO
35、NG _stdcall Release();/Interface IClassFactoryvirtual HRESULT _stdcall CreateInstance(IUnknown*pUnknownOuter,const IID&iid,void*ppv);virtual HRESULT _stdcall LockServer(BOOL bLock);/ConstructorCFactory():m_cRef(1)/DestructorCFactory()private:long m_cRef;COMCOM基础基础基础基础47HRESULT _stdcall CFactory:Quer
36、yInterface(const IID&iid,void*ppv)if(iid=IID_IUnknown)|(iid=IID_IClassFactory)*ppv=static_cast(this);else *ppv=NULL;return E_NOINTERFACE;reinterpret_cast(*ppv)-AddRef();return S_OK;ULONG _stdcall CFactory:AddRef()return InterlockedIncrement(&m_cRef);ULONG _stdcall CFactory:Release()if(InterlockedDec
37、rement(&m_cRef)=0)delete this;return 0;return m_cRef;COMCOM基础基础基础基础48/IClassFactory implementationHRESULT _stdcall CFactory:CreateInstance(IUnknown*pUnknownOuter,const IID&iid,void*ppv)if(pUnknownOuter!=NULL)return CLASS_E_NOAGGREGATION;CA*pA=new CA;if(pA=NULL)return E_OUTOFMEMORY;HRESULT hr=pA-Quer
38、yInterface(iid,ppv);/Release the IUnknown pointer./(If QueryInterface failed,component will delete itself.)pA-Release();return hr;COMCOM基础基础基础基础49/LockServerHRESULT _stdcall CFactory:LockServer(BOOL bLock)if(bLock)InterlockedIncrement(&g_cServerLocks);elseInterlockedDecrement(&g_cServerLocks);return
39、 S_OK;STDAPI DllCanUnloadNow()if(g_cComponents=0)&(g_cServerLocks=0)return S_OK;elsereturn S_FALSE;COMCOM基础基础基础基础50STDAPI DllGetClassObject(const CLSID&clsid,const IID&iid,void*ppv)if(clsid!=CLSID_Component1)return CLASS_E_CLASSNOTAVAILABLE;CFactory*pFactory=new CFactory;if(pFactory=NULL)return E_OU
40、TOFMEMORY;HRESULT hr=pFactory-QueryInterface(iid,ppv);pFactory-Release();return hr;COMCOM基础基础基础基础51STDAPI DllRegisterServer()return RegisterServer(g_hModule,CLSID_Component1,g_szFriendlyName,g_szVerIndProgID,g_szProgID);STDAPI DllUnregisterServer()return UnregisterServer(CLSID_Component1,g_szVerIndP
41、rogID,g_szProgID);COMCOM基础基础基础基础52BOOL APIENTRY DllMain(HANDLE hModule,DWORD dwReason,void*lpReserved)if(dwReason=DLL_PROCESS_ATTACH)g_hModule=hModule;return TRUE;COMCOM基础基础基础基础53clientCOM LibDLLCFactoryCApIX-Fx()New CANew CFactoryIClassFactory:ReleaseIClassFactory:CreateInstance(IID_IX)CoGetClassObjectDllGetClassObjectCOMCOM基础基础基础基础54