COM组件
COM组件
Risun
初稿:2004-2-19
前言
前几天我在公司的电脑被人换了,里面保存的文档、程序遭恶人陷害全部遇难,此时才发现她们的珍贵。对于以前看过的COM组件知识再次回顾,重新整理补充一下,此后要学会写学习心得更要珍惜。
COM-Component Object Model
使用组件的好处:
应用程序定制
组件库
分布式组件
组件要求
1. 动态链接
2. 信息封装(二进制语言无关)
COM是一个说明如何建立组件的规范
COM组件以Win32动态连接库(dlls)或可执行文件(EXEs)的形式发布的二进制代码
COM库API?Windows上实现的如:coCreateInstance()??
COM原理
接口
QueryInterface函数
接口查询:QueryInterface([in, IID] iid, [out,void **]ppv);
iid: 接口id,ppv:指向接口指针
引用计数
客户通过接口的指针来调用方法,一个组件可以被多个客户引用,何时组件注销?需要引用计数。
QueryInterface() 中计数增加,
客户显示增加引用时,需调用AddRef()增加计数
IX *pIX= pIY; pIX->AddRef();
客户端主动调用Release()减少计数
动态链接
HISTANCE LoadLibrary(
LPCTSTR lpLibFileName //filename of DLL
);
FARPROC GetProcAddress(
HMODULE hModule, //handle to DLL module
LPCSTR lpProcName //name of function
);
进程内空间
HRESULT GUID 注册表等
HRESULT
32位,低16位代码,其余调用成功标志(1)、类型及返回值起源(15)等信息;
MAKE_HRESULT宏
#define MAKE_HRESULT(sev,fac,code)\ ( (HRESULT) (((unsigned long)(sev)<<31) | ((unsigned
long)(fac)<<16) \ | ((unsigned long)(code))) )
GUID
128位,接口或组件的ID,参数一般传递应用 REFIID
uuidgen.exe guidgen.exe
Windows注册表
HKEY-CLASSES_ROOT
CLSID
COM组件的相关信息记录在注册表中,注册,反注册在dll中
STDAPI DllRegisterServer();
STDAPI DllUnregisterServer();
其中调用RegOpenKeyEx, RegCreateKayEx, RegSetValueEx, RegDeleteKey, RegCloseKey
COM库函数
OLE32.dll或OLE32.lib
初始化
进程COM库其他函数(CoBuildVersion之外)调用CoInitialize()初始化,不需要用时CoUninitialize()(如果未调用后者会怎样??)
内存管理
1 CoGetMalloc(DWORD, LPMALLOC*) 获得接口Imalloc,Imalloc::Alloc(), Imalloc::Free();
2 void * CoTaskMemAlloc( ULONG Cb); void CoTaskMemFree( void *pv);
类厂
类厂是一个组件,控制组件实体的生成,一个类厂实例只能产生一种组件(看参数)
CoCreateInstance() à CoGetClassObject() à DllGetClassObject() à CreateInstance()
COM 库函数 COM库函数 dll中输出函数(生成类厂) 类厂方法(生成实用组件)
DllCanUnloadNow(), used in CoFreeUnusedLibraries() , which is called periodically to free resources by Applictaions.
组件复用
(暂略)
编程工作简化
(暂略)
EXE服务器
(暂略)
调度接口
IDispath;
IDispatch : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(
/* [out] */ UINT __RPC_FAR *pctinfo) = 0;
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(
/* [in] */ UINT iTInfo,
/* [in] */ LCID lcid,
/* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) = 0;
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(
/* [in] */ REFIID riid,
/* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames,
/* [in] */ UINT cNames,
/* [in] */ LCID lcid,
/* [size_is][out] */ DISPID __RPC_FAR *rgDispId) = 0;
virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke(
/* [in] */ DISPID dispIdMember,
/* [in] */ REFIID riid, //reserved must be IID_NULL
/* [in] */ LCID lcid, //location information??
/* [in] */ WORD wFlags, //denote the method type
/* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams, //parameters
/* [out] */ VARIANT __RPC_FAR *pVarResult, //returned result, if no then NULL
/* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo, //异常标志
/* [out] */ UINT __RPC_FAR *puArgErr) = 0; //参数错误码
};
typedef struct tagDISPPARAMS //命名参数for VB
{
/* [size_is] */ VARIANTARG __RPC_FAR *rgvarg;
/* [size_is] */ DISPID __RPC_FAR *rgdispidNamedArgs;
UINT cArgs;
UINT cNamedArgs;
} DISPPARAMS;
参数被限制,只能是通过VARIANT表达的
调度接口
通过IDispatch::Invoke()调用实现的一系列接口
双重接口
从IDispatch继承的COM接口,其成员函数也可以通过Invoke()方式访问
VARIANT
VariantInit(), VariantClear()
运行时类型检查
类型转化:VariantChangeType()
BSTR
SysAllocString()
SysFreeString()
SAFEARRAY类型
调度接口可传递的另外一种类型
???
类型库
语言无关适合解释性语言和宏编程语言使用的C++头文件的等价无,是IDL文件的一个编译版本,二进制
创建:midl : idl文件中Library LibName{…} 中定义或引用的组件或接口信息
分发:独立或包含在Exe, Dll中???
使用:LoadRegTypeLib() / LoadTypeLib(), RegisterTypeLib(), ItypeLib::GetTypeInfoOfGuid
通过类型库接口ITypeInfo实现IDispatch
在类型库中完成查询调度工作
(未完待续)
COM应用
COM编程思想
posted on 2004-06-19 17:34 哲学 艺术 程序 人生 阅读(804) 评论(0) 编辑 收藏 举报