COM技术内幕--引用计数及动态链接
2016-12-15 14:36
316 查看
引用计数简介
AddRef 和 Release实现的是一种名为引用计数的内存管理技术。引用计数是使组件能够自己将自己删除的最简单同时效率最高的方法。COM组件维护一个称作是引用计数的数值。当客户从组件取得一个接口时,此引用计数值将增1。当客户使用完某个接口后,组件的引用计数值将减1。当引用计数值为0时,组件即可将自己从内存中删除。
规则:
1)在返回之前调用AddRef。对于那些返回接口的指针函数,在返回之前应用相应的指针调用AddRef。这些函数包括QueryInterface及CreateInstance。这样当客户从这种函数得到一个接口后,它将无需调用AddRef。
2)使用完接口后调用Release。在使用完某个接口之后应调用些接口的Release函数。
IUnKnown* pIUnknown = CreateInstance();
IX* pIX = NULL;
HRESULT hr = pIUnknown->QueryInterface(IID_IX,(void**)&pIX);
pIUnknown->Release();
if (SUCCEEDED(hr))
{
pIX->Fx();
pIX->Release();
}
3)在赋值之后调用AddRef。在将一个接口指针赋给另外一个接口指针时,应调用AddRef。换句话说,在建立接口的另外一个引用之后应增加相应组件的引用计数。
IUnKnown* pIUnknown = CreateInstance();
IX* pIX = NULL;
HRESULT hr = pIUnknown->QueryInterface(IID_IX,(void**)&pIX);
pIUnknown->Release();
if (SUCCEEDED(hr))
{
pIX->Fx();
IX* pIX2 = pIX;
pIX2->AddRef();
pIX2->Fx();
pIX2->Release();
pIX->Release();
}
引用计数接口:
组件可以选择是对整个组件维护一个引用计数不是对每一个接口分别维护一个引用计数
///////////////////////
AddRef和Release的实现
ULONG __stdcall AddRef()
{
return ++m_cRef;
}
ULONG __stdcall Release()
{
if (--m_cRef==0)
{
delete this;
return 0;
}
return m_cRef;
}
许多情况下用InterlockedIncrement和InterlockedDeCrement来实现 AddRef和Release。这两个函数可以确保在同一时刻只会有同一个线程来访问成员变量。
ULONG __stdcall AddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG __stdcall Release()
{
if (InterlockedDeCrement(&m_cRef)==0)
{
delete this;
return 0;
}
return m_cRef;
}
何时进行引用计数
1)引用计数的优化
IUnKnown* pIUnknown = CreateInstance();
IX* pIX = NULL;
HRESULT hr = pIUnknown->QueryInterface(IID_IX,(void**)&pIX);
pIUnknown->Release();
if (SUCCEEDED(hr))
{
IX* pIX2 = pIX;
pIX2->AddRef();
pIX->Fx();
pIX2->Fx();
pIX>Release();
pIX2>Release();
}
对于上面的代码,只有当客户将pIX释放时组件才会被从内存中删除。而客户只是在用完了pIX和pIX2之后才会将释放。正是由于组件只是在被释放之后才被从内存中删除掉,因此可以保证在pIX2的生命期内相应 的组件将一直在内存中。因此对pix2并不真的需要AddRef和Release。
动态链接
1)从DLL中输出函数
extern "C"
IUnknown* CreateInstance()
{
IUnknown* pI=(IUnknown*)(void*) new CA;
pI->AddRef();
return pI;
}
在函数定义前加上 extern "C"可防止c++编译器在函数名称上加上类型信息。
例如:
?CreateInstance@@YAPAUUnknown@@XZ
dumpbin -exports *.dll
可将dll的函数导出
2)DLL的装载
using namespace std;
typedef IUnknown* (*CREATEFUNCPTR)();
IUnknown *CallCreateInstance(char* name)
{
HINSTANCE hComponent = ::LoadLibrary(name);
if (hComponent == NULL)
{
cout<<"error load library"<<endl;
return NULL;
}
CREATEFUNCPTR CreateInstance =
(CREATEFUNCPTR)::GetProcAddress(hComponent,"CreateInstance");
if (CreateInstance==NULL)
{
cout<<"can not find the function"<<endl;
return NULL;
}
return CreateInstance();
}
使用DLL的原因:
动态链接库将被映射到它们所链接的应用程序的进程空间中
//////////////////////
AddRef 和 Release实现的是一种名为引用计数的内存管理技术。引用计数是使组件能够自己将自己删除的最简单同时效率最高的方法。COM组件维护一个称作是引用计数的数值。当客户从组件取得一个接口时,此引用计数值将增1。当客户使用完某个接口后,组件的引用计数值将减1。当引用计数值为0时,组件即可将自己从内存中删除。
规则:
1)在返回之前调用AddRef。对于那些返回接口的指针函数,在返回之前应用相应的指针调用AddRef。这些函数包括QueryInterface及CreateInstance。这样当客户从这种函数得到一个接口后,它将无需调用AddRef。
2)使用完接口后调用Release。在使用完某个接口之后应调用些接口的Release函数。
IUnKnown* pIUnknown = CreateInstance();
IX* pIX = NULL;
HRESULT hr = pIUnknown->QueryInterface(IID_IX,(void**)&pIX);
pIUnknown->Release();
if (SUCCEEDED(hr))
{
pIX->Fx();
pIX->Release();
}
3)在赋值之后调用AddRef。在将一个接口指针赋给另外一个接口指针时,应调用AddRef。换句话说,在建立接口的另外一个引用之后应增加相应组件的引用计数。
IUnKnown* pIUnknown = CreateInstance();
IX* pIX = NULL;
HRESULT hr = pIUnknown->QueryInterface(IID_IX,(void**)&pIX);
pIUnknown->Release();
if (SUCCEEDED(hr))
{
pIX->Fx();
IX* pIX2 = pIX;
pIX2->AddRef();
pIX2->Fx();
pIX2->Release();
pIX->Release();
}
引用计数接口:
组件可以选择是对整个组件维护一个引用计数不是对每一个接口分别维护一个引用计数
///////////////////////
AddRef和Release的实现
ULONG __stdcall AddRef()
{
return ++m_cRef;
}
ULONG __stdcall Release()
{
if (--m_cRef==0)
{
delete this;
return 0;
}
return m_cRef;
}
许多情况下用InterlockedIncrement和InterlockedDeCrement来实现 AddRef和Release。这两个函数可以确保在同一时刻只会有同一个线程来访问成员变量。
ULONG __stdcall AddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG __stdcall Release()
{
if (InterlockedDeCrement(&m_cRef)==0)
{
delete this;
return 0;
}
return m_cRef;
}
何时进行引用计数
1)引用计数的优化
IUnKnown* pIUnknown = CreateInstance();
IX* pIX = NULL;
HRESULT hr = pIUnknown->QueryInterface(IID_IX,(void**)&pIX);
pIUnknown->Release();
if (SUCCEEDED(hr))
{
IX* pIX2 = pIX;
pIX2->AddRef();
pIX->Fx();
pIX2->Fx();
pIX>Release();
pIX2>Release();
}
对于上面的代码,只有当客户将pIX释放时组件才会被从内存中删除。而客户只是在用完了pIX和pIX2之后才会将释放。正是由于组件只是在被释放之后才被从内存中删除掉,因此可以保证在pIX2的生命期内相应 的组件将一直在内存中。因此对pix2并不真的需要AddRef和Release。
动态链接
1)从DLL中输出函数
extern "C"
IUnknown* CreateInstance()
{
IUnknown* pI=(IUnknown*)(void*) new CA;
pI->AddRef();
return pI;
}
在函数定义前加上 extern "C"可防止c++编译器在函数名称上加上类型信息。
例如:
?CreateInstance@@YAPAUUnknown@@XZ
dumpbin -exports *.dll
可将dll的函数导出
2)DLL的装载
using namespace std;
typedef IUnknown* (*CREATEFUNCPTR)();
IUnknown *CallCreateInstance(char* name)
{
HINSTANCE hComponent = ::LoadLibrary(name);
if (hComponent == NULL)
{
cout<<"error load library"<<endl;
return NULL;
}
CREATEFUNCPTR CreateInstance =
(CREATEFUNCPTR)::GetProcAddress(hComponent,"CreateInstance");
if (CreateInstance==NULL)
{
cout<<"can not find the function"<<endl;
return NULL;
}
return CreateInstance();
}
使用DLL的原因:
动态链接库将被映射到它们所链接的应用程序的进程空间中
//////////////////////
相关文章推荐
- COM 技术内幕学习之五 (动态链接)
- COM技术内幕第四章笔记-引用计数
- COM的引用计数规则
- COM技术内幕中聚合的实现
- 关于一个VC++6.0技术内幕的COM错误问题,错误信息:error C2504: 'IMotion' : base class undefined
- COM 技术内幕学习之九 (简化程序编写)
- COM技术内幕学习笔记
- MFC技术内幕系列之(三)---MFC执行期类型识别与动态创建技术内幕
- COM 技术内幕学习之二 (接口)
- com技术内幕
- COM 引用计数规则
- inside com(com技术内幕)重读-摘录
- 包容和聚合(COM技术内幕笔记五)
- COM组件的类厂(COM技术内幕笔记之四)
- COM 组件技术内幕之四 (引用计数)
- ***求书***COM技术内幕
- COM中的HRESULT, CLISD,ProgID, DLL注册,COM库函数的知识(COM技术内幕笔记之三)
- [COM技术内幕](四)引用计数
- COM 技术内幕学习之七 (类厂)
- COM技术内幕摘要