关于DSHOW和COM学习一个疑点解析 2010-11-3 18:53
2013-01-11 11:08
92 查看
class CMyComponent : public CUnknown, public ISomeInterface{public: DECLARE_IUNKNOWN; STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv) { if( riid == IID_ISomeInterface ) { return GetInterface((ISomeInterface*)this, ppv); } return CUnknown::NonDelegatingQueryInterface(riid,
ppv); } CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr) : CUnknown(tszName, pUnk, phr) { /* Other initializations */ }; // More declarations will be added later.}; 调用QueryInterface和NonDelegatingQueryInterface的几种形式:this-> QueryInterface
this-> NonDelegatingQueryInterface
(INonDelegatingUnknown *)this-> NonDelegatingQueryInterface
(IUnknown *)(INonDelegatingUnknown *)this-> QueryInterface
注意:最后一种实际上调用的是NonDelegatingQueryInterface。
下面看看CMyComponent类如何查询接口:
CMyComponent *pCMyComponent = new CMyComponent (L”MyComponent”,
NULL,NULL);
ISomeInterface *pSomeInterface = NULL;
pMyComponent->QueryInterface(IID_ISomeInterface,
(void**)&pSomeInterface)
在这里使用的是“this-> QueryInterface”方式调用QueryInterface函数。
对象要查询接口,首先调用QueryInterface成员函数进行查询, CMyComponent类通过DECLARE_IUNKNOWN宏定义了QueryInterface成员函数,DECLARE_IUNKNOWN的定义如下:
#define DECLARE_IUNKNOWN \
STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) { \
return GetOwner()->QueryInterface(riid,ppv); \
}; \
STDMETHODIMP_(ULONG) AddRef() { \
return GetOwner()->AddRef(); \
}; \
STDMETHODIMP_(ULONG) Release() { \
return GetOwner()->Release(); \
};
所以MyComponent.QueryInterface(IID_ISomeInterface,
(void**)&pSomeInterface)
产生的结果等价于:
GetOwner()->QueryInterface(IID_ISomeInterface,
(void**)&pSomeInterface)
下面看GetOwner()函数:
LPUNKNOWN GetOwner() const {
return m_pUnknown;
};
The utility function CUnknown::GetOwner retrieves a pointer to the IUnknown interface of the component that owns this component. For an aggregated component, the owner is the outer component. Otherwise, the component owns itself. Include the DECLARE_IUNKNOWN
macro in the public section of your class definition.
CMyComponent::CMyComponent(IUnknown *pOuterUnkown){ if (pOuterUnknown == NULL) m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this; else m_pUnknown = pOuterUnknown; [ ... more constructor code ... ]}
GetOwner获取一个指向该对象(CMyComponent)所属对象的IUnknown接口的指针,如果该对象(CMyComponent)是聚合对象,它的拥有者是外部对象(m_pUnknown = pOuterUnknown),否则,此对象拥有自己(m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this)。
注意m_pUnknown为IUnknown *类型,这一点很重要。
m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this;也将this转换成了IUnknown *对象。
STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) { \
return GetOwner()->QueryInterface(riid,ppv); \
};
可以看出QueryInterface函数可以改写成下面的形式:
HRESULT QueryInterface(REFIID iid, void **ppv) { return m_pUnknown->QueryInterface(iid, ppv);}在这里使用的是“(IUnknown *)(INonDelegatingUnknown *)this-> QueryInterface”方式调用,实际上调用的是NonDelegatingQueryInterface。
因为m_pUnknown是通过语句m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this;转换过来的。
注意:这里不是“this-> QueryInterface”,而是“(IUnknown *)(INonDelegatingUnknown *)this-> QueryInterface”,这两者有本质的区别:
如果是“this-> QueryInterface”,这样调用的是DECLARE_IUNKNOWN宏中定义的QueryInterface, 如下所示:
STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) {
return GetOwner()->QueryInterface(riid,ppv);
};
这样将导致死循环。
如果是(INonDelegatingUnknown *)this-> QueryInterface,将导致编译错误,因为INonDelegatingUnknown接口没有QueryInterface函数。
语句(IUnknown *)(INonDelegatingUnknown *)this先将this转换成INonDelegatingUnknown指针,因为this和INonDelegatingUnknown之间存在继承关系,所以经过转换得到的指针将指向this物体中的INonDelegatingUnknown部分,然后再将INonDelegatingUnknown指针转换成IUnknown指针,因为INonDelegatingUnknown和IUnknown之间不存在继承关系,所以指针实际上还是指向this物体中的INonDelegatingUnknown部分,而这样做的目的是用一条语句使对于聚合和非聚合都适应,如果是非聚合,m_pUnknown
等于(IUnknown *)(INonDelegatingUnknown *)this,所以m_pUnknown-> QueryInterface将调用
自己INonDelegatingUnknown接口的 NonDelegatingQueryInterface,而如果是聚合m_pUnknown等于外部对象IUnknown接口指针,则m_pUnknown-> QueryInterface调用的是外部对象IUnknown接口的QueryInterface
来看NonDelegatingQueryInterface的定义:
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv) { if( riid == IID_ISomeInterface ) { return GetInterface((ISomeInterface*)this, ppv); } return CUnknown::NonDelegatingQueryInterface(riid, ppv);} 再来看GetInterface函数的定义:
STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv)
{
CheckPointer(ppv, E_POINTER);
*ppv = pUnk;
pUnk->AddRef();
return NOERROR;
}
注意:这里pUnk->AddRef();调用的是
STDMETHODIMP_(ULONG) AddRef() { \
return GetOwner()->AddRef(); \
};
而GetOwner()->AddRef();即m_pUnknown-> AddRef();调用的是NonDelegatingAddRef();
class CMyFilter : public CSource
{
……
}
class CMyPin : public CSourceStream,IKsPropertySet,IAMStreamConfig
{
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
……
}
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 ;
}
如果查询IID_IUnknown接口,那么先是调用*ppv = static_cast<INondelegatingUnknown*>(this); 经过static_cast<INondelegatingUnknown*>的转换,*ppv指向INondelegatingUnknown,而INondelegatingUnknown并不是IUnknown派生得到的,那么语句reinterpret_cast<IUnknown*>(*ppv)->AddRef()为什么要转化为指针(IUnknown *),明明INondelegatingUnknown不是继承自IUnknown?这样写是为了使代码对聚合和不聚合都适用。语句reinterpret_cast<IUnknown*>(*ppv)->AddRef()调用的实际上还是INondelegatingUnknown::AddRef();
为什么调用的是INondelegatingUnknown::AddRef()呢?
函数的调用实际是汇编 call 函数地址.对于一个类里定义的函数实际是一个一个的地址偏移.如果地址偏移是一样而且参数个数与排列都一样,函数叫什么名字是没有关系的。
((IUnknown *)(*ppv))->AddRef() ;只是把编译器给骗了,好让它通过. 不过因为偏移与参数都是一样(没参数) 所以就会有那样的结果罗. 你可以把INondelegatingUnknown的AddRef与Release位置换一下看看是不是就调用了Release()
如果查询IID_IY接口,那么先是调用*ppv = static_cast<IY*>(this); 经过static_cast<IY*>的转换,*ppv指向IY,而IY又是从IUnknown派生来的,所以语句reinterpret_cast<IUnknown*>(*ppv)->AddRef()调用的是IUnknown的AddRef()。
本文来自CSDN博客:http://blog.csdn.net/fxwzzbd/archive/2008/04/13/2288391.aspx
ppv); } CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr) : CUnknown(tszName, pUnk, phr) { /* Other initializations */ }; // More declarations will be added later.}; 调用QueryInterface和NonDelegatingQueryInterface的几种形式:this-> QueryInterface
this-> NonDelegatingQueryInterface
(INonDelegatingUnknown *)this-> NonDelegatingQueryInterface
(IUnknown *)(INonDelegatingUnknown *)this-> QueryInterface
注意:最后一种实际上调用的是NonDelegatingQueryInterface。
下面看看CMyComponent类如何查询接口:
CMyComponent *pCMyComponent = new CMyComponent (L”MyComponent”,
NULL,NULL);
ISomeInterface *pSomeInterface = NULL;
pMyComponent->QueryInterface(IID_ISomeInterface,
(void**)&pSomeInterface)
在这里使用的是“this-> QueryInterface”方式调用QueryInterface函数。
对象要查询接口,首先调用QueryInterface成员函数进行查询, CMyComponent类通过DECLARE_IUNKNOWN宏定义了QueryInterface成员函数,DECLARE_IUNKNOWN的定义如下:
#define DECLARE_IUNKNOWN \
STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) { \
return GetOwner()->QueryInterface(riid,ppv); \
}; \
STDMETHODIMP_(ULONG) AddRef() { \
return GetOwner()->AddRef(); \
}; \
STDMETHODIMP_(ULONG) Release() { \
return GetOwner()->Release(); \
};
所以MyComponent.QueryInterface(IID_ISomeInterface,
(void**)&pSomeInterface)
产生的结果等价于:
GetOwner()->QueryInterface(IID_ISomeInterface,
(void**)&pSomeInterface)
下面看GetOwner()函数:
LPUNKNOWN GetOwner() const {
return m_pUnknown;
};
The utility function CUnknown::GetOwner retrieves a pointer to the IUnknown interface of the component that owns this component. For an aggregated component, the owner is the outer component. Otherwise, the component owns itself. Include the DECLARE_IUNKNOWN
macro in the public section of your class definition.
CMyComponent::CMyComponent(IUnknown *pOuterUnkown){ if (pOuterUnknown == NULL) m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this; else m_pUnknown = pOuterUnknown; [ ... more constructor code ... ]}
GetOwner获取一个指向该对象(CMyComponent)所属对象的IUnknown接口的指针,如果该对象(CMyComponent)是聚合对象,它的拥有者是外部对象(m_pUnknown = pOuterUnknown),否则,此对象拥有自己(m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this)。
注意m_pUnknown为IUnknown *类型,这一点很重要。
m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this;也将this转换成了IUnknown *对象。
STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) { \
return GetOwner()->QueryInterface(riid,ppv); \
};
可以看出QueryInterface函数可以改写成下面的形式:
HRESULT QueryInterface(REFIID iid, void **ppv) { return m_pUnknown->QueryInterface(iid, ppv);}在这里使用的是“(IUnknown *)(INonDelegatingUnknown *)this-> QueryInterface”方式调用,实际上调用的是NonDelegatingQueryInterface。
因为m_pUnknown是通过语句m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this;转换过来的。
注意:这里不是“this-> QueryInterface”,而是“(IUnknown *)(INonDelegatingUnknown *)this-> QueryInterface”,这两者有本质的区别:
如果是“this-> QueryInterface”,这样调用的是DECLARE_IUNKNOWN宏中定义的QueryInterface, 如下所示:
STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) {
return GetOwner()->QueryInterface(riid,ppv);
};
这样将导致死循环。
如果是(INonDelegatingUnknown *)this-> QueryInterface,将导致编译错误,因为INonDelegatingUnknown接口没有QueryInterface函数。
语句(IUnknown *)(INonDelegatingUnknown *)this先将this转换成INonDelegatingUnknown指针,因为this和INonDelegatingUnknown之间存在继承关系,所以经过转换得到的指针将指向this物体中的INonDelegatingUnknown部分,然后再将INonDelegatingUnknown指针转换成IUnknown指针,因为INonDelegatingUnknown和IUnknown之间不存在继承关系,所以指针实际上还是指向this物体中的INonDelegatingUnknown部分,而这样做的目的是用一条语句使对于聚合和非聚合都适应,如果是非聚合,m_pUnknown
等于(IUnknown *)(INonDelegatingUnknown *)this,所以m_pUnknown-> QueryInterface将调用
自己INonDelegatingUnknown接口的 NonDelegatingQueryInterface,而如果是聚合m_pUnknown等于外部对象IUnknown接口指针,则m_pUnknown-> QueryInterface调用的是外部对象IUnknown接口的QueryInterface
来看NonDelegatingQueryInterface的定义:
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv) { if( riid == IID_ISomeInterface ) { return GetInterface((ISomeInterface*)this, ppv); } return CUnknown::NonDelegatingQueryInterface(riid, ppv);} 再来看GetInterface函数的定义:
STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv)
{
CheckPointer(ppv, E_POINTER);
*ppv = pUnk;
pUnk->AddRef();
return NOERROR;
}
注意:这里pUnk->AddRef();调用的是
STDMETHODIMP_(ULONG) AddRef() { \
return GetOwner()->AddRef(); \
};
而GetOwner()->AddRef();即m_pUnknown-> AddRef();调用的是NonDelegatingAddRef();
class CMyFilter : public CSource
{
……
}
class CMyPin : public CSourceStream,IKsPropertySet,IAMStreamConfig
{
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
……
}
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 ;
}
如果查询IID_IUnknown接口,那么先是调用*ppv = static_cast<INondelegatingUnknown*>(this); 经过static_cast<INondelegatingUnknown*>的转换,*ppv指向INondelegatingUnknown,而INondelegatingUnknown并不是IUnknown派生得到的,那么语句reinterpret_cast<IUnknown*>(*ppv)->AddRef()为什么要转化为指针(IUnknown *),明明INondelegatingUnknown不是继承自IUnknown?这样写是为了使代码对聚合和不聚合都适用。语句reinterpret_cast<IUnknown*>(*ppv)->AddRef()调用的实际上还是INondelegatingUnknown::AddRef();
为什么调用的是INondelegatingUnknown::AddRef()呢?
函数的调用实际是汇编 call 函数地址.对于一个类里定义的函数实际是一个一个的地址偏移.如果地址偏移是一样而且参数个数与排列都一样,函数叫什么名字是没有关系的。
((IUnknown *)(*ppv))->AddRef() ;只是把编译器给骗了,好让它通过. 不过因为偏移与参数都是一样(没参数) 所以就会有那样的结果罗. 你可以把INondelegatingUnknown的AddRef与Release位置换一下看看是不是就调用了Release()
如果查询IID_IY接口,那么先是调用*ppv = static_cast<IY*>(this); 经过static_cast<IY*>的转换,*ppv指向IY,而IY又是从IUnknown派生来的,所以语句reinterpret_cast<IUnknown*>(*ppv)->AddRef()调用的是IUnknown的AddRef()。
本文来自CSDN博客:http://blog.csdn.net/fxwzzbd/archive/2008/04/13/2288391.aspx
相关文章推荐
- 关于DSHOW和COM学习一个疑点解析
- 【树莓派学习笔记】关于树莓派在VNC远程登录时,弹出一个GDBus错误窗口的问题!!!
- 关于div+css学习的经典代码解析
- 一个不错的英语学习博客: http://www.eslbackpack.com/
- 一个后端的前端学习之旅——4.第一个demo上线以及关于前端框架我的看法
- JAVA学习日志 关于周易数字卦的一个算法
- 学习小记(2015/10/19)——工作中遇见的一个关于jQuery选择器的小要点。
- 【java学习】一个关于return和finally的例子
- [原创]java WEB学习笔记22:MVC案例完整实践(part 3)---多个请求对应一个Servlet解析
- 小试牛刀,学习PHP过程中关于环境配置的一个问题
- android菜鸟学习笔记25----与服务器端交互(二)解析服务端返回的json数据及使用一个开源组件请求服务端数据
- 关于 json解析过程中的一个问题的解决
- 一个关于数据连接语法的网站http://www.connectionstrings.com/
- 关于HttpURLConnection的一个疑问解析
- 一个简单的storyboard示例,其中关于添加navigation的部分可以学习,此前没用过
- 关于spring,IOC和AOP的解析原理和举例 http://blog.sina.com.cn/s/blog_624a352c0101fo9j.html
- 分享关于学习new BufferedWriter()方法时常遇到的一个无厘头的问题
- 关于Activity生命周期学习之窗口化一个Activity
- Android Backup 文件头解析(很不错的一个 ,之前研究过 http://bbs.pediy.com/showthread.php?t=206543)