高级软件工程06(COM基础:接口与实现)nullnull构件对象模型:COMnull 内 容
基础部分
综述
接口
实现
高级部分
包含与聚合
COM与VC
自动化
DCOM null(1) COM的起源
源于OLE: Object Link and Embedding
OLE1 采用DDE(Dynamic Data Exchange)
在不同的程序之间进行通信
DDE缺点: 效率低,稳定性不好,使用不方便
COM是为克服上述不足而出现的
OLE2 以 ...
nullnull构件对象模型:COMnull 内 容
基础部分
综述
接口
实现
高级部分
包含与聚合
COM与VC
自动化
DCOM null(1) COM的起源
源于OLE: Object Link and Embedding
OLE1 采用DDE(Dynamic Data Exchange)
在不同的程序之间进行通信
DDE缺点: 效率低,稳定性不好,使用不方便
COM是为克服上述不足而出现的
OLE2 以 COM 为基础
但OLE未能体现COM优点
1 综述COM基础null(2)什么是COM
构件对象模型:Component Object Model
客户与构件为了能够互操作而遵循的标准
COM标准包括
与实现两部分
规范部分定义了构件之间的通信机制
这些规范不依赖于任何特定的语言
和操作系统
实现部分即COM库
为COM规范的具体实现提供一些核心服务
COM基础null(3) COM构件以 DLL或EXE形式发布的代码与语言无关
以二进制形式发布
可以在不妨碍客户的形式下被升级
可以透明地在网络上被重新分配
构件与类:一个构件可以由多个类实现
接口与类:一个类可以实现多个接口COM基础null(4) COM库 (COM Library)
功能:
(1)实现客户方与服务器方COM应用的创建过程
(2)COM通过注册
查找本地服务器(即EXE程序)
以及程序名与CLSID的转换
(3)提供标准的内存控制
DCOM的实现提供了分布式环境下的通信机制
在操作系统层次
以DLL文件的形式存在
COM基础null(5) COM特性
语言无关性
为跨语言合作开发提供了统一标准
并得到不同集成开发环境的支持
进程透明性
进程内服务程序: DLL
本地服务程序: EXE
远地服务程序: DLL或EXE
实现进程透明性的关键是COM库
它负责服务体的定位
管理对象的创建及对象与客户之间的通信
复用性
包含方式
聚合方式COM基础null(6) COM发展趋势
操作系统
成为系统的基本软件模型
数据库
OLE DB/ADO 以 COM 的方式
为数据访问提供一致的接口
Internet
ActiveX包含了所有基于COM的Internet相关技术
COM+
增加MTS等服务COM基础null2 COM接口COM接口是COM规范的核心内容
接口的意义(略)
一个接口包含了一组函数
在C++中, 可以用抽象基类来定义COM接口
接口的实现 : vtbl 指针
虚拟函数表COM基础nullVtbl指针虚拟函数表pIX接口的内存结构IX&Fx1&Fx2&Fx3&Fx4COM基础nullVtbl的作用:提高接口实现的灵活性例子:一个实现接口IX的类CA,CA包含2个数据:Vtbl指针虚拟函数表IX&Fx1&Fx2&Fx3&Fx4Data1Data2pAFx1
Fx2
Fx3
Fx4CACOM基础null两个实例 共享同一Vtbl:Vtbl指针虚拟函数表&Fx1&Fx2&Fx3&Fx4Data1Data2pA1
pA2Fx1
Fx2
Fx3
Fx4CAVtbl指针Data1Data2COM基础null 接口特点
实现级
二进制,独立于编程语言
稳定性
客户与服务器依赖于接口
继承性
便于扩展接口, 不提倡继承
所有接口皆继承Iunknown)
多态性:COM基础null(1)功能
提供: 生存期控制
接口查询
IUnknown的定义(IDL):
interface IUnkown
{
virtual HRESULT QueryInterface(
const IID&, void **ppv) = 0;
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
} IUnknownCOM基础nullVtbl指针虚拟函数表IXQueryInterfaceAddRefRelease&FxpAQueryInterface
AddRef
Release
FxCA所有接口都必须继承IUnknownCOM基础nullIUnknown指针的获取
IUnknown * CreateInstance();
创建构件时,客户可以使用CreateInstance,
而不是new。
CreateInstance的定义:
IUnknown * CreateInstance()
{
IUnknown * pI = static_cast
(new foo);
pI -> AddRef();
return pI;
}
COM基础null(2)引用计数
AddRef与Release
控制构件的生命期
解决内存管理问题
使构件能够自己将自己删除
使用规则
返回接口指针之前调用 AddRef;
使用完接口之后调用Release;
赋值之后调用AddRef;COM基础null引用计数的实现方式:
在什么层次上进行计数
构件
对象
接口构件构件引用记数对象引用记数对象引用记数对象1对象2接口接口接口接口接口引用记数接口引用记数接口引用记数接口引用记数COM基础null(3)接口查询一个COM对象(构件)可以实现多个接口
使用QueryInterface查询某个构件是否支持某个特定的接口
QueryInterface的使用
void foo(Iunknown * pI){
//Define a pointer for the interface.
IX * pIX = NULL;
//Ask for nterface IX
HRESULT hr = pI->QueryUbterface(IID_IX, (void **)&pIX);
//Check return value.
If (SUCCEEDED(hr)) {
// Use interface
pIX->Fx();
}
}COM基础nullQueryInterface的实现
假定存在类 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_cast(this);
}
else {
*ppv = NULL;
return E_NOINTERFACE;
}
static_cast(*ppv)->AddRef();
return S_OK;
}COM基础nullQueryInterface的实现规则QueryInterface返回的总是同一个IUnknown指针
若客户曾经获取过某个接口,那么它将总能获取此接口
客户可以再次获取已经拥有的接口
客户可以返回到起始接口
若能够从某个接口获取某特定接口
则可以从(该构件的)任意接口获取此接口COM基础null 新版本构件的处理COM接口永远不会变化 :一个IID就是一个接口
通过发行新版本构件解决兼容性
当下列条件中的任何一个变化时
应给新接口指定新IID:
接口中函数数目
接口中函数顺序
某个函数的参数
某个函数参数的顺序
某个函数参数的类型
函数可能的返回值
函数返回值的类型 等
不同版本接口的命名:在老名称后加一个数字
COM基础null3 COM实现(1)预备知识:
DLL
DLL是一个构件服务器
EXE也可以是构件服务器
使用户在应用程序的运行过程中替换构件
构件是DLL中实现的接口集
DLL共享它们所链入的应用程序地址空间
HRESULT
向用户报告构件运行结果状况
“Here is the RESULT”
WINERROR.H中进行定义
用户可以定义自己的代码COM基础nullGUID:Globally Unique IDentifier用于标识构件(CLSID)与接口(IID)
128位(长整数)
由于空间足够大
接口标识冲突较小
可以用编程的方法生成具有唯一性的GUID
VC: UUIDGEN.EXE, GUIDGEN.EXE
借鉴了OSF的UUID(DCE中的RPC使用).
对GUID值的传递通常通过引用进行COM基础CLSID:CLaSs IDentifiernullWindows 注册表Windows操作系统的共享系统数据库
包括 硬件 软件 配置及用户等各种信息
由 REGEDIT.EXE (95/98)
REGEDIT32.EXE(NT) 启动
可以使用REGSVR32.EXE来注册某个构件
注册表是一个由许多元素构成的层次结构
每一个元素均被称作是一个关键字
每一个关键字可以包含一系列子关键字等
例如: HKEY_CLASSES_ROOT
CLSID
ProgID 等COM基础nullCOM基础nullCOM基础null(2)COM库COM构件与客户皆需要完成的相同操作
由OLE32.DLL、OLE32.LIB实现
COM库中常用的函数:
初始化函数
与GUID相关的函数
对象创建函数
内存管理函数COM基础null 在使用COM库中的其他函数(除CoBuildVersion)
之前,进程必须先调用:
HRESULT CoInitialize(void * reserved)
在退出之前调用:
void CoUninitialize(void * reserved)
其他: CoBuildVersion
CoFreeUnusedLibraries
OleInitialize建立在CoInitialize基础之上
DCOM使用CoInitializeEx初始化函数:COM基础null与GUID(CLSID)相关的函数:
例如:将GUID转换为一个字符串:
wchar_t szCLSID[39];
int r = :: StringFromGUID2(CLSID_Component1,
szCLSID, 39);
其它:
StringFromCLSID
StringFromIID
CLSIDFromString
IIDFromString
IsEqualGUID
IsEqualIID
IsEqualCLSID
CLSIDFromProgIDCOM基础null对象创建函数:CoGetClassObject
CoCreateInstance
CoCreateInstanceEx
CoRegisterClassObject
CoRevokeClassObject
CoDisconnectObject内存管理函数:CoTaskMemAlloc
CoTaskMemRealloc
CoTaskMemFree
CoGerMallocCOM基础null(3) 类厂(Class Factory)能够创建其他构件的构件
(构件厂)
其本身也是一个COM对象
支持一个特殊的接口 IClassFacroty
每一个COM对象类应该有一个相应的类厂对象COM基础nullCoCreateInstance
COM库函数之一
HRESULT_stdcall CoCreateInstance(
const CLSID& clsid,
Iunkown * pIUnknownOuter,
DWORD dwClsContext,
const IID& iid,
void ** ppv
);
clsid:待创建构件的标识;
pIUnknownOuter:用于聚合;
dwClsContext:限定所创建构件的上下文;
iid:构件上待使用接口的标识;
ppv:所返回接口的指针。COM基础null一个使用例子:
IX * pIX = NULL;
HRESULT he = ::CoCreateInstance(
CLSID_Component1,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDX,
(void **) &pIX);
if (SUCCEEDED(hr)) {
pIX -> FX();
pIX -> Release();
}COM基础null类厂CoCreateInstance实际上
未直接创建COM构件
创建了一个被称为类厂的构件
类厂构件的唯一功能是创建其他构件
客户可以通过类厂所支持的接口来
对类厂创建 构件的过程加以控制
CoCreateInstance调用CoGetClassObject
创建构件的标准接口是IClassFactoryCOM基础nullCoGetClassObject
创建类厂HRESULT_stdcall CoGetClassObject(
const CLSID& clsid,
DWORD dwClsContext,
COSERVERINFO * pServerInfo,//用于DCOM
const IID& iid,
void ** ppv //指向类厂中某个接口的指针
);
COM基础nullIClassFactory
用于创建构件的标准接口Interface IClassFactory: IUnknown
{
HRESULT _stdcall
CreateInstance( IUnknown * pUnknownOuter,
const IID & iid,
void ** ppv );
HRESULT _stdcall
LockServer(BOOL block);
}未接收CLSID:只能创建同某个CLSID相应的构件IClassFactory2COM基础nullCoCreateInstance 与 CoGetClassObject的关系:
CoCreateInstance 通过 CoGetClassObject实现
HRESULT CoCreateInstance(const CLSID& clsid,
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;
}COM基础null在下列情况下应直接使用CoGetClassObject
而应使用CoCreateInstance:
(1)如果希望用不同于IClassFactory的某个创建接口
来创建构件
例如 IClassFactory2
(2)如果希望创建同一构件的多个实例
COM基础 null(4)类厂的实现
CoGetClassObject需要DLL中的一个特定的函数
来创建构件的类厂
DllGetClassObject:
STDAPI DllGetClassObject(
const CLSID& clsid,
const IID& iid,
void ** ppv
);
COM基础null创建、调用构件的过程:客户COM库DLLCoGetClassObject调用CoGetClassObjectDllGetClassObjectIClassFactoryIXpIClassFactorypIXCOM基础创建类厂创建构件返回IClassFactory调用IClassFactory::CreateInstance返回IX调用IX::Fxnull#include
#include
#include "Iface.h"
int 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() ;
}客户方代码COM基础(5)例子null IZ* pIZ = NULL ;
hr = pIX->QueryInterface(IID_IZ, (void**)&pIZ) ;
if (SUCCEEDED(hr)){
pIZ->Fz() ;
pIZ->Release() ;
}
pIX->Release() ;
}
else
{
cout << "Client: \t\tCould not create component. hr = "
<< hex << hr << endl ;
}
// Uninitialize COM Library
CoUninitialize() ;
return 0 ;
}COM基础null#include
#include
#include "Iface.h" // Interface declarations
#include "Registry.h" // Registry helper functions
static HMODULE g_hModule = NULL ; // DLL module handle
static long g_cComponents = 0 ; // Count of active components
static long g_cServerLocks = 0 ; // Count of locks
// Friendly name of component
const char g_szFriendlyName[] = "Inside COM, Ch 7 Example" ;
// Version-independent ProgID
const char g_szVerIndProgID[] = "InsideCOM.Chap07" ;服务器方代码COM基础nullclass CA : public IX, public IY {
public:
// IUnknown
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;
virtual ULONG __stdcall AddRef() ;
virtual ULONG __stdcall Release() ;
// Interface IX
virtual void __stdcall Fx() { cout << "Fx" << endl ;}
// Interface IY
virtual void __stdcall Fy() { cout << "Fy" << endl ;}
// Constructor
CA() ;
// Destructor
~CA() ;
private:
// Reference count
long m_cRef ;
} ;COM基础nullHRESULT __stdcall 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_cast(this) ;
}
else{ *ppv = NULL ;
return E_NOINTERFACE ;
}
reinterpret_cast(*ppv)->AddRef() ;
return S_OK ;
}COM基础nullclass CFactory : public IClassFactory{
public:
// IUnknown
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;
virtual ULONG __stdcall AddRef() ;
virtual ULONG __stdcall Release() ;
// Interface IClassFactory
virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
const IID& iid, void** ppv) ;
virtual HRESULT __stdcall LockServer(BOOL bLock) ;
// Constructor
CFactory() : m_cRef(1) {}
// Destructor
~CFactory() {}
private:
long m_cRef ;
} ;COM基础nullHRESULT __stdcall CFactory::QueryInterface(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 (InterlockedDecrement(&m_cRef) == 0){
delete this ;
return 0 ;
}
return m_cRef ;
}COM基础null// IClassFactory implementation
HRESULT __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->QueryInterface(iid, ppv) ;
// Release the IUnknown pointer.
// (If QueryInterface failed, component will delete itself.)
pA->Release() ;
return hr ;
}
COM基础null// LockServer
HRESULT __stdcall CFactory::LockServer(BOOL bLock) {
if (bLock){
InterlockedIncrement(&g_cServerLocks) ; }
else{
InterlockedDecrement(&g_cServerLocks) ;}
return S_OK ;
}
STDAPI DllCanUnloadNow()
{
if ((g_cComponents == 0) && (g_cServerLocks == 0)){
return S_OK ;}
else{
return S_FALSE ;}
}COM基础nullSTDAPI 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_OUTOFMEMORY ;}
HRESULT hr = pFactory->QueryInterface(iid, ppv) ;
pFactory->Release() ;
return hr ;
}
COM基础nullSTDAPI DllRegisterServer(){
return RegisterServer(g_hModule,
CLSID_Component1,
g_szFriendlyName,
g_szVerIndProgID,
g_szProgID) ;
}
STDAPI DllUnregisterServer()
{
return UnregisterServer(CLSID_Component1,
g_szVerIndProgID,
g_szProgID) ;
}COM基础nullBOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason,
void* lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
g_hModule = hModule ;
}
return TRUE ;
}COM基础nullclientCOM LibDLLCFactoryCApIX->Fx()New CANew CFactoryIClassFactory::ReleaseIClassFactory::CreateInstance(IID_IX)CoGetClassObjectDllGetClassObjectCOM基础
本文档为【高级软件工程06(COM基础:接口与实现)】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。