模拟COM组件聚合的问题
// my_test_com8.cpp : 定义控制台应用程序的入口点。//
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;
//不考虑内存泄露
#defineIID_MYIUnknown 1000
#defineIID_IX 1001
#defineIID_IY 1002
#defineIID_IZ 1003
#defineCLSID_Component1 1024
#defineCLSID_Component2 1025
class MyTrace
{
public:
MyTrace(const char *msg)
{
memset(buff, 0, 1024);
printf(buff,msg);
cout << ">>>" << buff << endl ;
}
~MyTrace()
{
cout << ">>>" << buff << endl ;
}
private:
char buff;
};
//-------------------------------------------------------------------
struct INondelegatingUnknown
{
public:
virtual int __stdcall NondelegatingQueryInterface(const int& iid, void** ppv) = 0 ;
virtual int __stdcall NondelegatingAddRef() = 0 ;
virtual int __stdcall NondelegatingRelease() = 0 ;
} ;
class MYUnknown
{
public:
virtual int __stdcall QueryInterface(const int& iid, void** ppv)= 0;
virtual int __stdcall AddRef()= 0;
virtual int __stdcall Release() = 0;
};
class IX : public MYUnknown
{
public:
virtual void __stdcall Fx() = 0 ;
};
class IY : public MYUnknown
{
public:
virtual void __stdcall Fy() = 0 ;
};
class IZ : public MYUnknown
{
public:
virtual void __stdcall Fz() = 0 ;
};
//////////////////////////////////////////////////////////////////////////////////
void trace2(const char* msg) { cout << "Component 2:\t" << msg << endl ;}
class CB : public IY,
public INondelegatingUnknown
{
public:
// Delegating IUnknown
virtual int __stdcall
QueryInterface(const int& iid, void** ppv)
{
trace2("Delegate QueryInterface.") ;
return m_pUnknownOuter->QueryInterface(iid, ppv) ;
}
virtual int __stdcall AddRef()
{
trace2("Delegate AddRef.") ;
return m_pUnknownOuter->AddRef() ;
}
virtual int __stdcall Release()
{
trace2("Delegate Release.") ;
return m_pUnknownOuter->Release() ;
}
// Nondelegating IUnknown
virtual int __stdcall
NondelegatingQueryInterface(const int& iid, void** ppv) ;
virtual int __stdcall NondelegatingAddRef() ;
virtual int __stdcall NondelegatingRelease() ;
// Interface IY
virtual void __stdcall Fy() { cout << "Fy" << endl ;}
// Constructor
CB(MYUnknown* m_pUnknownOuter) ;
// Destructor
~CB() ;
private:
long m_cRef ;
MYUnknown* m_pUnknownOuter ;
} ;
//
// IUnknown implementation
//
int __stdcall CB::NondelegatingQueryInterface(const int& iid,
void** ppv)
{
//MyTrace say("CB::NondelegatingQueryInterface");
if (iid == IID_MYIUnknown)
{
// !!! CAST IS VERY IMPORTANT !!!
*ppv = static_cast<INondelegatingUnknown*>(this) ;// @N
}
else if (iid == IID_IY)
{
*ppv = static_cast<IY*>(this) ;
}
else
{
*ppv = NULL ;
return 2 ;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
return 0 ;
}
int __stdcall CB::NondelegatingAddRef()
{
return ::InterlockedIncrement(&m_cRef) ;
}
int __stdcall CB::NondelegatingRelease()
{
if (::InterlockedDecrement(&m_cRef) == 0)
{
delete this ;
return 0 ;
}
return m_cRef ;
}
//
// Constructor
//
CB::CB(MYUnknown* pUnknownOuter)
: m_cRef(1)
{
;
if (pUnknownOuter == NULL)
{
trace2("Not aggregating; delegate to nondelegating IUnknown.") ;
m_pUnknownOuter = reinterpret_cast<MYUnknown*>
(static_cast<INondelegatingUnknown*>
(this)) ;
}
else
{
trace2("Aggregating; delegate to outer IUnknown.") ;
m_pUnknownOuter = pUnknownOuter ;
}
}
//
// Destructor
//
CB::~CB()
{
trace2("Destroy self.") ;
}
/////////////////////////////////////////////////////////////////////////
void trace1(const char* msg) { cout << "Component 1:\t" << msg << endl ;}
class CA : public IX
// public IY @N
{
public:
// IUnknown
virtual int __stdcall QueryInterface(const int& iid, void** ppv) ;
virtual int __stdcall AddRef() ;
virtual int __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
int __stdcall Init() ;// @N
private:
// 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
MYUnknown* m_pUnknownInner ; // @N
} ;
//
// Constructor
//
CA::CA()
: m_cRef(1),
m_pUnknownInner(NULL) //@N
{
}
//
// Destructor
//
CA::~CA()
{
trace1("Destroy self.") ;
// Prevent recursive destruction on next AddRef/Release pair.
m_cRef = 1 ;
// Counter the pUnknownOuter->Release in the Init method.
MYUnknown* pUnknownOuter = this ;
pUnknownOuter->AddRef() ;
// Properly release the pointer; there might be per-interface
// reference counts.
m_pIY->Release() ;
// Release contained component.
if (m_pUnknownInner != NULL) // @N
{
m_pUnknownInner->Release() ;
}
}
// Initialize the component by creating the contained component.
int __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.
MYUnknown* pUnknownOuter = (MYUnknown*)this ;
trace1("Create inner component.") ;
CB *pCB = new CB(pUnknownOuter);
pCB->NondelegatingQueryInterface(IID_MYIUnknown , (void **)&m_pUnknownInner);
int hr = m_pUnknownInner == NULL ? -1:0;
/*
::CoCreateInstance(CLSID_Component2,
pUnknownOuter, // Outer component's IUnknown @N
CLSCTX_INPROC_SERVER,
IID_IUnknown,// IUnknown when aggregating@N
(void**)&m_pUnknownInner) ;
*/
if (hr == -1)
{
trace1("Could not create contained component.") ;
return -1 ;
}
// This call will increment the reference count on the outer component.
trace1("Get the IY interface from the inner component.") ;
hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY) ; //@N
if (hr == -1)
{
trace1("Inner component does not support interface IY.") ;
m_pUnknownInner->Release() ;
return -1 ;
}
// 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 0 ;
}
//
// IUnknown implementation
//
int __stdcall CA::QueryInterface(const int& iid, void** ppv)
{
if (iid == IID_MYIUnknown)
{
*ppv = static_cast<MYUnknown*>(this) ;
}
else if (iid == IID_IX)
{
*ppv = static_cast<IX*>(this) ;
}
else if (iid == IID_IY)
{
trace1("Return inner component's IY interface.") ;
#if 1
// You can query for the interface.
return m_pUnknownInner->QueryInterface(iid,ppv) ; //@N
#else
// Or you can return a cached pointer.
*ppv = m_pIY ; //@N
// Fall through so it will get AddRef'ed
#endif
}
else
{
*ppv = NULL ;
return 2 ;
}
reinterpret_cast<MYUnknown*>(*ppv)->AddRef() ;
return 0 ;
}
int __stdcall CA::AddRef()
{
return ::InterlockedIncrement(&m_cRef) ;
}
int __stdcall CA::Release()
{
if (::InterlockedDecrement(&m_cRef) == 0)
{
delete this ;
return 0 ;
}
return m_cRef ;
}
/////////////////////////////////////////////////////////////////////////////////
int _tmain(int argc, _TCHAR* argv[])
{
CA *pCA = new CA();
pCA->Init();
IX *pIX = NULL;
int rs = pCA->QueryInterface(IID_IX,(void **)&pIX);
if (pIX)
{
pIX->Fx();
}
IY * pIY = NULL;
pIX->QueryInterface(IID_IY,(void **)&pIY);
if (pIY)
{
pIY->Fy();
pIY->Release() ;
}
pIX->Release() ;
return 0;
} 为什么在CA::Init()中(302行)
hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY) ;
调用的是
CB类的NondelegatingQueryInterface(const int& iid, void** ppv) ;
而不是
CB类的QueryInterface ?????? 出了啥问题?
你问的问题,属于COM里面的接口调用问题,具体内容我已经忘记了,不过可以查一下COM本质论,里面有说明。 这是《COM技术内幕》第8章的代码,因为原来的范例代码只有一个MAKEFILE,不好调试,我就把他的逻辑拿出来,不用组件方式,其他都一样的。VS2003下编译可运行,问题就是
CA::Init()中(302行)
hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY) ;
调用的是
CB类的NondelegatingQueryInterface(const int& iid, void** ppv) ;
而不是
CB类的QueryInterface
多谢了, 我去看看那本书 参考http://blog.chinaunix.net/u2/66646/showart_673644.html
m_pUnknownInner是从pCB->NondelegatingQueryInterface(IID_MYIUnknown , (void **)&m_pUnknownInner); 中得来的,
int __stdcall CB::NondelegatingQueryInterface(const int& iid,
void** ppv)
{
//MyTrace say("CB::NondelegatingQueryInterface");
if (iid == IID_MYIUnknown)
{
// !!! CAST IS VERY IMPORTANT !!!
*ppv = static_cast<INondelegatingUnknown*>(this) ;// @N
}
else if (iid == IID_IY)
}
hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY) ; //@N
==
(IUnknown *)(INonDelegatingUnknown *)this-> QueryInterface实际上调用的是NonDelegatingQueryInterface。 m_pUnknownInner被声明为MYUnknow * ,但他其实是 m_pUnknownInner = (MYUnknow * )static_cast<INondelegatingUnknown*>(CB* this);尽管m_pUnknownInner 指向的内存是按MYUnknow排布(包括虚函数表),但实际装载的是INondelegatingUnknown类型的内容,所以m_pUnknownInner->QueryInterface会跳转到CB::NondelegatingQueryInterface。如果改变INondelegatingUnknown的内存布局,即改变INondelegatingUnknown的虚函数声明顺序,那么这种做法就不合需求了。可以把virtual int __stdcall NondelegatingAddRef() = 0 ;声明在第一个。m_pUnknownInner->QueryInterface会跳转到CB::NondelegatingAddRef() 而不是CB::NondelegatingQueryInterface()。
真的很酷!
页:
[1]