问题代码有一点长,但是对于明白聚合的高手来说很容易,只是一个聚合的例子。
先对您的眼说抱歉……… 解决问题必连开3帖(300分)酬谢。
有关COM聚合的问题。先贴出部分代码,大家看看。
//client.cpp
void trace(const char* msg) { cout << "Client: \t" << msg << endl ;}
//这时是为了显示输出是从哪个模块来的。
int main()
{
// Initialize COM Library
CoInitialize(NULL) ;
trace("Get interface IX from Component 1.") ;
IX* pIX = NULL ;
HRESULT hr = ::CoCreateInstance(CLSID_Component1, //这里是所请求的聚合对象
NULL,
CLSCTX_INPROC_SERVER,
IID_IX,
(void**)&pIX) ;
if (SUCCEEDED(hr))
{
trace("Succeeded creating component.") ;
.........
}
..........
CoUninitialize() ;
return 0 ;
}
先对您的眼说抱歉……… 解决问题必连开3帖(300分)酬谢。
有关COM聚合的问题。先贴出部分代码,大家看看。
//client.cpp
void trace(const char* msg) { cout << "Client: \t" << msg << endl ;}
//这时是为了显示输出是从哪个模块来的。
int main()
{
// Initialize COM Library
CoInitialize(NULL) ;
trace("Get interface IX from Component 1.") ;
IX* pIX = NULL ;
HRESULT hr = ::CoCreateInstance(CLSID_Component1, //这里是所请求的聚合对象
NULL,
CLSCTX_INPROC_SERVER,
IID_IX,
(void**)&pIX) ;
if (SUCCEEDED(hr))
{
trace("Succeeded creating component.") ;
.........
}
..........
CoUninitialize() ;
return 0 ;
}
解决方案 »
- BitBlt形成的扫描线的疑惑
- 我想问一下五角星的画法
- 新手提问,登陆编译成功,运行时出现错误,求助!!
- 有谁知道怎样控制声音面板上的属性?
- 什么地方、什么情况下要加IMPLEMENT_DYNCREATE ? 有什么用处?
- 如何在ListCtrl的非第一列中显示Bmp图片
- winsock编程
- 用Cdaodatabase打开accees2000数据库应该怎么用?
- 我想把ELF(EXECUTABLE AND LINKABLE FORMAT)转为其它格式,谁有ELF中文文档!!!
- CInternetSession::OpenURL返回的CHttpFile不能Seek
- 谁能提供详细safearray 多维数组用法
- 黑白位图转换成彩色位图 、新手求教?
......
void trace(const char * msg){cout<<"Component 1:\t"<<msg<<endl;}class CA : public IX
// public IY @N
{
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 ;}
/* @N Component1 aggregates instead of implementing interface IY.
// Interface IY
virtual void __stdcall Fy() { m_pIY->Fy() ;}
*/
// Constructor
CA() ;
// Destructor
~CA() ;
// Initialization function called by the class factory
// to create the contained component
HRESULT __stdcall Init() ; // @Nprivate:
// Reference count
long m_cRef ;
// Pointer to the aggregated component's IY interface
// (We do not have to retain an IY pointer. However, we
// can use it in QueryInterface.)
IY* m_pIY ; // @N
// Pointer to inner component's IUnknown
IUnknown* m_pUnknownInner ; // @N
} ;HRESULT __stdcall CA::Init()
{
// Get the pointer to the outer unknown.
// Since this component is not aggregated, the outer unknown
// is the same as the this pointer.
IUnknown* pUnknownOuter = this ;
trace("Create inner component.") ;
HRESULT hr =
::CoCreateInstance(CLSID_Component2,
pUnknownOuter, // Outer component's IUnknown @N
CLSCTX_INPROC_SERVER,
IID_IUnknown, // IUnknown when aggregating @N
(void**)&m_pUnknownInner) ;
if (FAILED(hr))
{
trace("Could not create contained component.") ;
return E_FAIL ;
}
// This call will increment the reference count on the outer component.
trace("Get the IY interface from the inner component.") ;
hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY) ; //@N
if (FAILED(hr))
{
trace("Inner component does not support interface IY.") ;
m_pUnknownInner->Release() ;
return E_FAIL ;
}
// We need to release the reference count added to the
// outer component in the above call. So call Release
// on the pointer you passed to CoCreateInstance.
pUnknownOuter->Release() ; //@N
return S_OK ;
}
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,
const IID& iid,
void** ppv)
{
// Cannot aggregate
if (pUnknownOuter != NULL)
{
return CLASS_E_NOAGGREGATION ;
}
// Create component.
CA* pA = new CA ;
if (pA == NULL)
{
return E_OUTOFMEMORY ;
}
// Initialize the component. @N
HRESULT hr = pA->Init() ;
if (FAILED(hr))
{
// Initialization failed. Delete component.
pA->Release() ;
return hr ;
}
// Get the requested interface.
hr = pA->QueryInterface(iid, ppv) ;
pA->Release() ;
return hr ;
}
struct INondelegatingUnknown
{
virtual HRESULT __stdcall
NondelegatingQueryInterface(const IID&, void**) = 0 ;
virtual ULONG __stdcall NondelegatingAddRef() = 0 ;
virtual ULONG __stdcall NondelegatingRelease() = 0 ;
} ; //非委托IUnknown接口class CB : public IY,
public INondelegatingUnknown
{
public:
// Delegating IUnknown
virtual HRESULT __stdcall
QueryInterface(const IID& iid, void** ppv)
{
trace("Delegate QueryInterface.") ;
return m_pUnknownOuter->QueryInterface(iid, ppv) ;
} virtual ULONG __stdcall AddRef()
{
trace("Delegate AddRef.") ;
return m_pUnknownOuter->AddRef() ;
} virtual ULONG __stdcall Release()
{
trace("Delegate Release.") ;
return m_pUnknownOuter->Release() ;
} // Nondelegating IUnknown
virtual HRESULT __stdcall
NondelegatingQueryInterface(const IID& iid, void** ppv) ;
virtual ULONG __stdcall NondelegatingAddRef() ;
virtual ULONG __stdcall NondelegatingRelease() ; // Interface IY
virtual void __stdcall Fy() { cout << "Fy" << endl ;} // Constructor
CB(IUnknown* m_pUnknownOuter) ; // Destructor
~CB() ;private:
long m_cRef ;
IUnknown* m_pUnknownOuter ;
} ;HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid,
void** ppv)
{
if (iid == IID_IUnknown)
{
// !!! CAST IS VERY IMPORTANT !!!
*ppv = static_cast<INondelegatingUnknown*>(this) ; // @N
}
else if (iid == IID_IY)
{
*ppv = static_cast<IY*>(this) ;
}
else
{
*ppv = NULL ;
return E_NOINTERFACE ;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
return S_OK ;
}ULONG __stdcall CB::NondelegatingAddRef()
{
return ::InterlockedIncrement(&m_cRef) ;
}ULONG __stdcall CB::NondelegatingRelease()
{
if (::InterlockedDecrement(&m_cRef) == 0)
{
delete this ;
return 0 ;
}
return m_cRef ;
}CB::CB(IUnknown* pUnknownOuter)
: m_cRef(1)
{
::InterlockedIncrement(&g_cComponents) ; if (pUnknownOuter == NULL)
{
trace("Not aggregating; delegate to nondelegating IUnknown.") ;
m_pUnknownOuter = reinterpret_cast<IUnknown*>
(static_cast<INondelegatingUnknown*>
(this)) ;
}
else
{
trace("Aggregating; delegate to outer IUnknown.") ;
m_pUnknownOuter = pUnknownOuter ;
}
}
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,
const IID& iid,
void** ppv)
{
// Aggregate only if the requested iid is IID_IUnknown.
if ((pUnknownOuter != NULL) && (iid != IID_IUnknown)) //@N
{
return CLASS_E_NOAGGREGATION ;
}
// Create component.
CB* pB = new CB(pUnknownOuter) ; // @N
if (pB == NULL)
{
return E_OUTOFMEMORY ;
}
// Get the requested interface.
HRESULT hr = pB->NondelegatingQueryInterface(iid, ppv) ; //@N
pB->NondelegatingRelease() ;
return hr ;
}
Client: Get interface IX from Component1.
Component 1: Create inner component.
Component 2: Aggregating;delegate to outer IUnknown.
Component 1: Get the IY interface from the inner component.
Component 2: Delegate AddRef.
Client: Succeeded creating component.让我不明白的是:"Component 2: Delegate AddRef."是从哪里出来的??
你看,对于CA:: m_pUnknownInner 得到的是内部对象的非委托IUnknown指针(*ppv = static_cast<INondelegatingUnknown*>(this) ;)那么对于外部对象(聚合对象)来说,它应该不可能访问
非委托IUnknown指针也就不可能调用
virtual ULONG __stdcall AddRef()
{
trace("Delegate AddRef.") ;
return m_pUnknownOuter->AddRef() ;
}
虽然在
HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid,
void** ppv)
{
if (iid == IID_IUnknown)
{
// !!! CAST IS VERY IMPORTANT !!!
*ppv = static_cast<INondelegatingUnknown*>(this) ; // @N
}
else if (iid == IID_IY)
{
*ppv = static_cast<IY*>(this) ;
}
else
{
*ppv = NULL ;
return E_NOINTERFACE ;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
return S_OK ;
}
看这里:reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;虽然把非委托IUnknown指针进行了转化,但是它也不可能变为委托针啊????。为什么,请大家指教。真的是因为这里么,这也是唯一的可能了。
{
virtual func1();
virtual func2();
virtual func3();
};Class B
{
virtual func4();
virtual func5();
virtual func6();
};Class C:public A,public B
{
func1(){};
func2(){};
func3(){};
func4(){};
func5(){};
func6(){};
}main()
{
A * pA=new C();
B * pB=(B *)A;
B->func5();//notice!!!! func5 Not the B interface;
}B->func5();调用的是A接口的func2()函数!明白了没?
reinterpret_cast<IUnknown*>(*ppv)->AddRef() 调用的是
ULONG __stdcall CB::NondelegatingAddRef()
{
return ::InterlockedIncrement(&m_cRef) ;
}
对吧。可是,你看显示的是什么?Component 2: Delegate AddRef.
这不是在 virtual ULONG __stdcall AddRef()
{
trace("Delegate AddRef.") ;
return m_pUnknownOuter->AddRef() ;
}
为什么,请指教,
virtual ULONG __stdcall AddRef()
{
trace("Delegate AddRef.") ;
return m_pUnknownOuter->AddRef() ;
}
而至于NondelegatingQueryInterface,NondelegatingAddRef只有在创建对象的时候才会调用唯一的一次,其他的时候在被聚合对象上调用AddRef,Release,QueryInterface时都会转到外部对象上去,而只要调用一次NondelegatingAddRef,就能够保证在外部对象的生命周期内,被聚合对象始终都是存活的。你应该把外部对象的Release方法也贴出来,你应该能够在这个函数里面找到问题的答案
"在COM中,所有的接口都是派生于IUnknown的",我认为不完会吧,看这里;
struct INondelegatingUnknown
{
virtual HRESULT __stdcall
NondelegatingQueryInterface(const IID&, void**) = 0 ;
virtual ULONG __stdcall NondelegatingAddRef() = 0 ;
virtual ULONG __stdcall NondelegatingRelease() = 0 ;
} ; //非委托IUnknown接口
“CB::NondelegatingQueryInterface中,能够得到*ppv的两个接口一个本身就是IUnknown”看这里:
HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid,
void** ppv)
{
if (iid == IID_IUnknown)
{
// !!! CAST IS VERY IMPORTANT !!!
*ppv = static_cast<INondelegatingUnknown*>(this) ; // 得到的是非委托IUnknown
}
else if (iid == IID_IY)
{
*ppv = static_cast<IY*>(this) ;
}
else
{
*ppv = NULL ;
return E_NOINTERFACE ;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;//这里进行了转化,实际上目的是为了聚合,不聚合都可用,变了名字不变本性,它一定是调用CB::NondelegatingAddRef()不信你跟踪看看。to anyone:HELP ME,HELP ME~~~~~~
CoInitialize(NULL) ;
trace("Get interface IX from Component 1.") ;
IX* pIX = NULL ;
HRESULT hr = ::CoCreateInstance(CLSID_Component1, //这里是所请求的聚合对象
trace("Get interface IX from Component 1.") ;
IX* pIX = NULL ;
HRESULT hr = ::CoCreateInstance(CLSID_Component1, //这里是所请求的聚合对象
这样的程序永远都是有问题的,因为你想使用COM的底层机制,却不愿遵守它的规则
建议仔细研究一下COM理论,我想你一定是看了那本书上写了IX这样的接口,如果作者不想误人的话,一定会认真解释IX的作用以及其与IUnknown的关系
HRESULT __stdcall CA::Init()中的
hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY) ;
这里要调用class CB 的QueryInterface,而class CB的QueryInterface又调用了class CA的QueryInterface,只要你观察class CA的QueryInterface,就会发现如果查询的接口是IY的话,那么这个函数会直接调用class CB的NondelegatingQueryInterface,从而引起NondelegatingQueryInterface中的else if (iid == IID_IY)
{
*ppv = static_cast<IY*>(this) ;
}
被执行,这样*ppv就是IUnknow的VPTR,在它上面调用AddRef的时候当然会打印出那样一条语句
你看这里hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY);
实际上调用的是CB::NodelegatingQueryIntercace,那么由于查询的是IY接口,那么
else if (iid == IID_IY)
{
*ppv = static_cast<IY*>(this) ;
}
就必然会被执行到,这样就必然会调用到AddRef方法
void** ppv)
{
if (iid == IID_IUnknown)
{
// !!! CAST IS VERY IMPORTANT !!!
*ppv = static_cast<INondelegatingUnknown*>(this) ; // @N
}
else if (iid == IID_IY)
{
*ppv = static_cast<IY*>(this) ; // 注意这一行
}
else
{
*ppv = NULL ;
return E_NOINTERFACE ;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
return S_OK ;
}>让我不明白的是:"Component 2: Delegate AddRef."是从哪里出来的??如果你跟踪代码,就会发现,经过 *ppv = static_cast<IY*>(this) ; 转换后,
*ppv 这个指针已经开始指向 IY 了,而 IY 又是从 IUnknown 派生来的,
所以 reinterpret_cast<IUnknown*>(*ppv)->AddRef() ; 肯定调用
IUnknown版的AddRef()啦
if (iid == IID_IUnknown)
{
// !!! CAST IS VERY IMPORTANT !!!
*ppv = static_cast<INondelegatingUnknown*>(this) ; // @N
}
是调用的INondelegatingUnknown::ADDREF(),而没有看到当
else if (iid == IID_IY)
{
*ppv = static_cast<IY*>(this) ; // 注意这一行
}
而IID_IY是从IUnknown来的,呵,好了,给分,
谢谢
brave_heart(intrepid)更加感谢 golden_alvin(Alvin)
请两位去那说句话,我才能给分,快啊~~~