COM接口对应的vtbl,何时变为无效的com接口

[笔记]COM组件初识
我的图书馆
[笔记]COM组件初识
COMCOMCOMCOM
COMCOMAPICOMMicrosoftActiveXDirectXOLECOM
COMmicrosoft windows COMAPICOM
COMIUnknownIUnknownwin32 SDKUNKNOWN.H
QueryInterface(const IID& iid,void **ppv)=0;
COMIUnknownIUnknownvtbl3QueryInterfaceAddRefReleaseCOMIUnknownQueryInterface
QueryInterfaceIUnknownAddRefRelease
AddRefRelease110AddRefRelease
DLLDLLDLLDLL
DLLCreateInstanceDLLCOMCoCreateInstanceCoCreateInstanceCLSIDCoCreateInstanceIClassFactoryDllRegisterSeverwindows
COMCOMCOMC++CDELPHIVBCOM
COMIIinterfaceIUnknown
COMCOMCOMCOM
COM128128GUIDGUIDGUIDinterface identifier IIDGUIDClassID CLSID
GUIDGEN.EXTGUIDUUIDGENGUID
GUIDGUID32GUID
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
Windows GUID{}
Win32 SDKGUID
CLSIDFromString:CLSIDCoCreateGuid:GUIDIIDFromString:IIDIsEqualCLSID:2CLSIDIsEqualGUID:GUIDIsEqualIID:2IIDStringFromCLSID:CLSIDStringFromCLSIDGUIDStringFromIID:IID
4.IUnknown
COMIUnknownIUnknown2COMIUnknown
COMIUknown
IUnknownIDL
IUnknown3QueryInterfaceAddRefReleaseQueryInterfaceCOMAddRefRelease
01AddRefRelease0
QueryInterfaceAddRefReleaseQueryInterfaceIUnknownQueryInterface
QueryInterface
QueryInterface
QueryInterface1QueryInterfaceQueryInterfaceQueryInterfaceQueryInterface
COMQueryInterfaceHRESULT32SUCCEEDEDFAILED
CoCreateInstanceCOMCLSID
**)&pGraph);
CoCreateInstanceIGraphBuidlerIGraphBuilder
COMCOM3DLLEXEEXE
COMclass objectCOMCLSIDCLSIDCLSID
COMCOMCLSIDCOM
IClassFactoryIClassFactoryIUnKnown2CreateInstanceCLSIDCOMLockServer
CreateInstanceCTestQueryInterfacewindows 2000CoCreateInstanceCLSIDCoGetClassObjectAPICreateInstanceCOM
COMCoCreateInstance
COMCLSIDDLLInProcServer32
[HKEY_CLASSES_ROOT\CLSID\{32GUID}\InprocServer32]
”D:\\Program Files\Common Files\\Microsoft shared\\DAO\\DAO350.DLL”.
DLLMain:DLLGetClassObjectCOMwindows
DLLCanUnloadNowwindowsDLL11
COMMFCATLMFCCOMATLCOMCOM
MFCwindowsSDKAPIMicrosoftMFCCOMMFCvisual C++COMMicrosoft CCmdTargetMFCCOM
MFCCOMCCmdTargetCCmdTargetIUnknownm_dwRefIUnknown6InternalAddRefInternalReleaseInternalQueryInterfaceExternalAddRefExternalReleaseExternalQueryInterfaceQueryInterfaceAddRefReleaseCOMInternalAddRefInternalReleaseInternalQueryInterfaceQueryInterfaceExternalAddRefExternalReleaseExternalQueryInterface
MFCCOMMFCCOMCCmdTargetCCmdTargetMFCBEGIN_INTERFACE_PARTEND_INTERFACE_PART
MFCQueryInterfaceMFCMFCwindowsC++MFCGUIDvptrCCmdTargetCOMDECLARE_INTERFACE_MAPBEGIN_INTERFACE_MAPINTERFACE_PARTEND_INTERFACE_MAP
IUnKnownMFCIClassFactoryMFCMFC2DECLARE_OLECREATE_EXIMPLEMENT_OLECREATE_EXCCmdTargetCOleObjectFactoryAFXDISP.HCOleObjectFactoryCOleObjectFactoryMFCIClassFactory2IClassFactory::CreateInstanceMFCMFCDECLARE_DYNCREATEIMPLEMENT_DYNCREATECOM
MFCClassWizardClassWizardMFCIDispatchCCmdTargetIDispatchMFCCOleDispatchImplCOleDispatchImplIDispatch4IDispatchGetTypeInfoCountGetTypeInfoGetIDsNamesInvokeCCmdTargetEnableAutomationIDispatch vptrMFCCOMIDispatchQueryInterfaceCCmdTargetCOleDispatchImplvptr
ClassWizardDISPIDsC++COleDispatchImplGetIDsOfNamesDISPIDMFCCOMOLEOLE
ATLActiveX template libraryC++ATLCOMmicrosoftATLvisual C++
ATLIUnknownIDispatchIClassFactoryDLLEXECOMDLLEXEATLMFCCOMATLCOM
ATLCOMIUnknownATLIUnknownCComObjectRootExATL2CComSingleThreadModelCComMultiThreadModelCComSingleThreadModelC++++--CComMultiThreadModelInterlockedIncrementInterlockedDecrementCComObjectRootExMFCATLQueryInterfaceCComObjectRootBaseQueryInterfaceBEGIN_COM_MAPEND_COM_MAPMFCATL17ATLIOleObjectImplvptrstear-offvptrs
ATLC++CComObjectRootExMFCIUnknownCCmdTargetCOM
ATLIClassFactoryMFCCOleObjectFactoryATLCComCoClass/CComClassFactoryCComCreatorCComCoClassGUIDCOMCComCreatorCreateInstanceCComClassFactoryMFCATLDECLARE_CLASS_FACTORY,DECLARE_CLASS_FACTORY2,DECLARE_CLASS_FACTORY_AUTO_THREADDECLARE_CLASS_FACTORY_SINGLETON
ATLIDispatch—IDispatchImplMFCIDispatchATLIDispatchMFChand-rolledIDispatchATL
喜欢该文的人也喜欢fangyukuan
客户同组件的交互都是通过一个接口完成的。在客户查询组件的其他接口时,也是通过接口完成的。这个接口就是IUnknown。它在UNKNWN.H头文件定义 :如下
&&&&&& Interface IUnknown
&&&&&&&&&&&
virtual HRESULT __stdcall QueryInterface(
REFIID riid, void ** ppvObject) = 0;
&&&&&&&&&&&
virtual ULONG __stdcall &AddRef( void) =
&&&&&&&&&&&
virtual ULONG __stdcall &Release( void)
所有的COM接口都继承了IUnknown,每个接口的vtbl中的前三个函数都是QueryInterface、AddRef、Release(如图3-1)。这样所有COM接口都可以被当成IUnknown接口来处理。
由于所有的接口都是从IUnknown继承的,因此所有的接口都支持QueryInterface,所以组件的任何一个接口都可以被客户用来获取它所支持的其他接口。
QueryInterface
IUnknown的一个成员函数QueryInterface,客户可以通过此函数来查询某个组件是否支持某个特定的接口。若支持QueryInterface将返回一个指向些接口的指针,不支持返回值将是一个错误代码。
QueryInterface 有两个参数,和一个HRESULT返回值
HRESULT __stdcall QueryInterface(
REFIID riid, void ** ppvObject);
第一个参数:接口标识符(IID)
第二个参数:存放所请求接口指针的地址。
返回值:查询成功返回S_OK,如果不成功则返回相应错误码。
QueryInterface的使用
void foo(IUnknown* pI)
&&& // 定义一个接口指针
&&& IX* pIX = NULL;
&&& // 查询接口IX
&&& HRESULT hr = pI-&QueryInterface(IID_IX, (void**)&pIX);
&&& if (SUCCEEDED(hr))
&&&&&& // 通过接口调用函数
&&&&&& pIX-&Fx();
QueryInterface实现
根据某个给定的IID返回指向相应接口的指针。若组件支持客户指定的接口,那么应返回S_OK以及相应的指针。若不支持返回测返回E_NoINTERFACE并将相应的指针返回值置成NULL。
QueryInterface的实现要求可以将一种类型映射成另外一种类型的结构。如:if
else 、数组、哈希表或者是树来实现,但是case语句是无法用的。因为接口标识符是一个结构而不是一个数。
注意:IX和IY不能按虚拟方式继承IUnknown。否则IX和IY的vtbl中的头三个函数指向的将不是IUnknown的三个成员函数。
HRESULT __stdcall
CA::QueryInterface(const
void** ppv)
&&& if (iid
== IID_IUnknown)
&&&&&& trace("QueryInterface: Return pointer to IUnknown.");
&&&&&& *ppv = static_cast&IX*&(this);
&&& else if (iid == IID_IX)
&&&&&& trace("QueryInterface: Return pointer to IX.");
&&&&&& *ppv = static_cast&IX*&(this);
&&& else if (iid == IID_IY)
&&&&&& trace("QueryInterface: Return pointer to IY.");
&&&&&& *ppv = static_cast&IY*&(this);
&&&&&& trace("QueryInterface: Interface not supported.");
&&&&&& *ppv = NULL;
&&&&&& return E_NOINTERFACE;
&&& reinterpret_cast&IUnknown*&(*ppv)-&AddRef();
&&& return S_OK;
接口标准化,在COM中有两方面的内容:一是接口基本功能的标准化,二是接口内存结构的标准化。为了保证组件接口在基本功能上的标准化,COM预定义了一个基本接口IUnknow。(在文件UNKNWN.H中定义)
Class&& Iunknown
&&& Public:
&&&&&&& Virtual& HRESULT _stdcall&
QueryInterface(const IID& iid, void **ppv)=0;
&&&&&&& Virtual& HRESULT _stdcal&&
AddRef( )=0;
&&&&&&& Virtual& HRESULT _stdcal&&
Release( )=0;
显然,Iunknown接口具有3个纯虚函数。COM 要求组件的所有接口必须继承自IUnknown接口,这样就保证组件的所有接口都能提供这3个服务(函数)。
一个完整的例子
:http://www.box.net/shared/m4yr9z73zu
#include &iostream&using namespace#include &objbase.h&void trace(const char* msg) {
cout && msg &&}// 接口定义interface IX : IUnknown{
virtual void __stdcall Fx() = 0;};interface IY : IUnknown{
virtual void __stdcall Fy() = 0;};interface IZ : IUnknown{
virtual void __stdcall Fz() = 0;};// Forward references for GUIDsextern const IID IID_IX;extern const IID IID_IY;extern const IID IID_IZ;//// 实现接口 IX,IY(这里表示一个组件)//class CA : public IX, public IY{
//IUnknown implementation
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall AddRef() { return 0;}
virtual ULONG __stdcall Release() { return 0;}
// Interface IX implementation
virtual void __stdcall Fx() { cout && "这里是Fx函数" &&}
// Interface IY implementation
virtual void __stdcall Fy() { cout && "这里是Fy函数" &&}};HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv){
if (iid == IID_IUnknown)
trace("QueryInterface: Return pointer to IUnknown.");
*ppv = static_cast&IX*&(this);
else if (iid == IID_IX)
trace("QueryInterface: Return pointer to IX.");
*ppv = static_cast&IX*&(this);
else if (iid == IID_IY)
trace("QueryInterface: Return pointer to IY.");
*ppv = static_cast&IY*&(this);
trace("QueryInterface: Interface not supported.");
*ppv = NULL;
return E_NOINTERFACE;
reinterpret_cast&IUnknown*&(*ppv)-&AddRef(); // 加计数
return S_OK;}//// 创建类CA,并返回一个指向IUnknown的指针//IUnknown* CreateInstance(){
IUnknown* pI = static_cast&IX*&(new CA);
pI-&AddRef();
return pI ;}//// 下面是各接口的IID//// {32bbcf-a6bb-d682}static const IID IID_IX = {0x32bb8320, 0xb41b, 0x11cf,{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};// {32bbcf-a6bb-d682}static const IID IID_IY = {0x32bb8321, 0xb41b, 0x11cf,{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};// {32bbcf-a6bb-d682}static const IID IID_IZ = {0x32bb8322, 0xb41b, 0x11cf,{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};//// 主函数(这里代表客户)//int main(){
trace("Client:获取 IUnknown指针.");
IUnknown* pIUnknown = CreateInstance();
trace("Client:获取接口IX.");
IX* pIX = NULL;
hr = pIUnknown-&QueryInterface(IID_IX, (void**)&pIX);
if (SUCCEEDED(hr))
trace("Client:获取接口IX成功.");
pIX-&Fx();
// 使用 IX.
trace("Client:获取接口IY.");
IY* pIY = NULL;
hr = pIUnknown-&QueryInterface(IID_IY, (void**)&pIY);
if (SUCCEEDED(hr))
trace("Client:
Succeeded getting IY.");
pIY-&Fy();
// 使用 IY.
trace("Client:是否支持接口IZ.");
IZ* pIZ = NULL;
hr = pIUnknown-&QueryInterface(IID_IZ, (void**)&pIZ);
if (SUCCEEDED(hr))
trace("Client:获取接口IZ成功.");
pIZ-&Fz();
trace("Client:获取接口IZ失败,不支持接口IZ.");
trace("Client:用接口IX查询接口IY.");
IY* pIYfromIX = NULL;
hr = pIX-&QueryInterface(IID_IY, (void**)&pIYfromIX);
if (SUCCEEDED(hr))
trace("Client:获取接口IY成功.");
pIYfromIX-&Fy();
trace("Client:用接口IY查询接口IUnknown.");
IUnknown* pIUnknownFromIY = NULL;
hr = pIY-&QueryInterface(IID_IUnknown, (void**)&pIUnknownFromIY);
if (SUCCEEDED(hr))
cout && "IUnknown指针是否相等?";
if (pIUnknownFromIY == pIUnknown)
cout && "Yes, pIUnknownFromIY == pIUnknown." &&
cout && "No, pIUnknownFromIY != pIUnknown." &&
// Delete the component.
delete pIU
return 0;}
QueryInterface的实现规则
&QueryInterface返回的总是同一IUnknown指针。
&若客户曾经获取过某个接口,那么将总能获取此接口。如果曾经不能,则将总是不能。
&客户可以再次获取已经拥有的接口。
&客户可以返回到接口。
&若能够从某个接口获取某特定接口,那么可以从任意接口都将可以获取此接口。
同一IUnknown指针:
组件的实例只有一个IUnknown接口。因为查询组件实例的IUnknown接口时,不论通过哪个接口,所得到的均将是同一指针值。所以可以通过两个接口的IUnknown,然后比较他们的值。看看是否相同来判断两个接口是否在同一个组件里。
&&& 判断两个接口是否在同一个组件里
BOOL SameComponents(IX*
pIX, IY* pIY)
&&& IUnknown* pI1 =
&&& IUnknown* pI2 =
&&& pIX-&QueryInterface(IID_IUnknown,
(void**)&pI1);
&&& pIY-&QueryInterface(IID_IUnknown,
(void**)&pI2);
&&& return pI1 == pI2;
QueryInterface定义了组件
一个组件实际上就是由QueryInterface定义的。组件所支持的接口集就是QueryInterface能够为之返回接口指针的那些接口。这一点是由QueryInterface的实现决定的,而不是由实现组伯的C++类决定的。实现组件的类的继承层次关系也不能决定组件。
新版本组件的处理
COM接口是不会发性变化的,当组件发布一个接口并补某个使用后,此接口将决不会发生任何变化。如果我们想改动它。只能通过增加新的接口。
何时需要建立一个新版本
当改了下列条件中任何一个时,就应该给新接口指定新的ID.
&接口中函数的数目。
&接口中函数的顺序。
&某个函数的参数。
&某个函数参数的顺序。
&某个函数参数的类型。
&函数可能的返回值。
&函数返回值的类型。
&函数参数的含义。
&接口中函数的含义。
总之,只要是所做的修改会影响客户的正常运行,都应该为接口指定新的ID
本文地址:&网站已改版,请使用新地址访问:
COMHook_Src Visual C++ COM接口 api 钩子与API截获 238万源代码下载- www.pudn.com
&文件名称: COMHook_Src
& & & & &&]
&&所属分类:
&&开发工具: Visual C++
&&文件大小: 55 KB
&&上传时间:
&&下载次数: 82
&&提 供 者:
&详细说明:Visual C++ HOOK COM接口-Visual C++ HOOK COM Interface
文件列表(点击判断是否您需要的文件,如果是垃圾请在下面评价投诉):
&&COMHook_Src\plus&&...........\....\dlldata.c&&...........\....\plus.cpp&&...........\....\plus.def&&...........\....\plus.dsp&&...........\....\plus.dsw&&...........\....\plus.h&&...........\....\plus.idl&&...........\....\plus.rc&&...........\....\plus.tlb&&...........\....\plusps.def&&...........\....\plusps.mk&&...........\....\plus_i.c&&...........\....\plus_p.c&&...........\....\resource.h&&...........\....\StdAfx.cpp&&...........\....\StdAfx.h&&...........\....\Sum.cpp&&...........\....\Sum.h&&...........\....\Sum.rgs&&...........\Pop&&...........\...\plus.tlh&&...........\...\Pop.clw&&...........\...\Pop.cpp&&...........\...\Pop.dsp&&...........\...\Pop.dsw&&...........\...\Pop.h&&...........\...\Pop.rc&&...........\...\PopDlg.cpp&&...........\...\PopDlg.h&&...........\...\ReadMe.txt&&...........\...\res&&...........\...\...\Pop.ico&&...........\...\...\Pop.rc2&&...........\...\resource.h&&...........\...\StdAfx.cpp&&...........\...\StdAfx.h&&...........\Riched20 Ver1&&...........\.............\ImgHandler.cpp&&...........\.............\ImgHandler.h&&...........\.............\myRichEditOle.h&&...........\.............\myTextServ.h&&...........\.............\ReadMe.txt&&...........\.............\RecvWin.cpp&&...........\.............\RecvWin.h&&...........\.............\Riched20.cpp&&...........\.............\Riched20.def&&...........\.............\Riched20.dsp&&...........\.............\Riched20.dsw&&...........\.............\Riched20.h&&...........\.............\StdAfx.cpp&&...........\.............\StdAfx.h&&...........\.............\TxtHandler.cpp&&...........\.............\TxtHandler.h&&...........\VtblStory1&&...........\..........\ReadMe.txt&&...........\..........\StdAfx.cpp&&...........\..........\StdAfx.h&&...........\..........\VtblStory1.cpp&&...........\..........\VtblStory1.dsp&&...........\..........\VtblStory1.dsw&&COMHook_Src
&[]:很好,推荐下载
&近期下载过的用户:
&相关搜索:
&输入关键字,在本站238万海量源码库中尽情搜索:
&[] - 一个示例工程源码,主要讲述如果对COM接口进行hook
&[] - Integrate the latest MSDN with VC6 and hook functions of COM
&[] - 通过COM接口来实现对应用程序的hook
&[] - hook directx com dinput
&[] - Diablo2游戏外挂,采用VC++编写。供参考
&[] - this is in-process com, it can hook call information by it
&[] - WINDOW下串口钩子技术
&[] - Visual C++实践与提高-ActiveX篇
&[] - 一个示例工程源码,主要讲述如果对COM接口进行hook
&[] - windows核心编程chm附源代码版,网上一般是pdf或pdg的,看起来很不方便,这个是chm版本的,很好用interface接口实例
C++标准中是没有接口interface的,但是我们在MFC的程序中经常可以看到接口的影子,我就自己查阅的资料和理解,做一个总结把。
首先,在objBase.h里面,有interface的定义
#define __STRUCT__ struct
#define interface __STRUCT__
这样我们就能知道,interface只不过是struct的重命名
但是为什么要把struct定义为interface呢,这其中大有渊源,接着往下看:
在C++中struct与Class可以说是没有区别,但是又可以说是很大区别。
  因为C++要向下兼容C。所以C具有的东西,那么在C++里也具有。所以谈struct应该是从C谈起
  struct在C中:struct是一种自定义的数据类型。既然是一种数据类型那么就肯定不能定义函数。C是面向过程的,面向对象的东西它自然也不具有。
  struct在C++中;C++是面向对象的。根据对象的思想,struct应该是等价于CLass(C是没有Class这个东西的)。这里我们又引出了一个很大的话题,面向过程和面向对象的区别。这里我们只选其中很小的一部分来说。
  面向过程认为,数据和数据的操作是分开的。(当然面向过程也可以刻意的实现把数据和数据的操作集合到一起)
  面向对象认为,数据和数据的操作是一个整体,不应该分开的。
  这样面向对象就和面向过程有了很大的冲突。这个冲突其实引发了struct的C和C++的差异性。
  C++中的struct是可以包含函数的,可以拥有构造函数,析构函数同样拥有继承等能力。这个时候。。很多人就会疑惑?那struct和CLASS不就一样了吗?
  对struct和class的确差别不大。从使用上差别不大。使用上的差别唯一的就是默认访问类型不一样struct默认公有,class默认私有。(改了- -!手误。。。)
  肯定就有朋友会问,平常我们都不会依赖于默认啦,不同的编译器可能默认方式都不一样的。照这个思维不就是完全没区别了。对我说的很大区别,其实针对的是思想上并非使用上。
  第一:struct是继承于C但又要适合于面向对象。所以struct是丢也不是,留下又多余的尴尬局面。
  第二:C++中的struct已经被扩展,已经不再是C时代的struct
  那么最大的思想差别是啥呢?我也说不清楚。思想的东西我觉得,是要靠感悟的,可能从我嘴来说出来的思想,在你眼里可能是狗屁不通,甚至是一堆臭鸡蛋。所以下面我说一个我认为的C++中struct思想。
  在面向对象横行的时代。相信大家都对几个面向对象词语有很深的认识,对象,类,接口,继承等等。
  但是大家留心会发现,C++里面没有“接口”这个东西。说起接口这个东西,就不能不说了,在JAVA里是不允许多继承的,但是能实现继承多个接口。但是C++却是允许实现多继承,那么如果C++里出现接口这个东西,最后的结果也会变成多余。
  所以我觉得“接口”其实已经在面向对象里形成了一种文化。但是作为编程界翘楚的C++却没有“接口”这样东西。人的思维是强大的,例如MS的做法就是将struct当成了接口来使用。
  "我觉得C++中的struct和class区别不是在于使用,不在于语法糖,而是在于思想,在于构架约定等方面。"
从以上我们可以知道,使用struct是为了和Java的面向对象编程思想保持一致,也就是说其实用abstract class也是一样的效果,但是interface看起来更像面向对象一些。
接口使用方法实例:
#include &iostream&
#include &objbase.h&
// Define interface.
输出一个字符串
void trace(const char* pMsg)
cout && pMsg &&
IX和IY为普通接口(非COM接口),其实它们是抽象基类
interface IX
virtual void __stdcall Fx1() = 0 ;
virtual void __stdcall Fx2() = 0 ;
interface IY
virtual void __stdcall Fy1() = 0 ;
virtual void __stdcall Fy2() = 0 ;
接口的实现,这里用了多重继承
class CA : public IX,
// Implement interface IX.
virtual void __stdcall Fx1() {cout && "CA::Fx1" &&}
virtual void __stdcall Fx2() {cout && "CA::Fx2" &&}
// Implement interface IY.
virtual void __stdcall Fy1() {cout && "CA::Fy1" &&}
virtual void __stdcall Fy2() {cout && "CA::Fy2" &&}
客户(在这里是一个主函数)
int main()
trace("Client: Create an instance of the component.");
CA* pA = new CA;
// Get an IX pointer.
IX* pIX = pA;
trace("Client: Use the IX interface.");
pIX-&Fx1();
pIX-&Fx2();
// Get an IY pointer.
IY* pIY = pA;
trace("Client: Use the IY interface.");
pIY-&Fy1();
pIY-&Fy2();
trace("Client: Delete the component.");
delete pA;
虽然C++可以直接操作和使用实例数据,但COM组件绝不会访问任何实例数据,在COM中,对一个组件的访问只能通过函数完成,而绝不能直接通过变量.这一点同我们对COM组件的定义是相符的.纯抽象基类只有虚拟函数,而没有任何实例数据.
对于COM来说,接口是一个包含一个函数指针数组的内存结构。
接口是由没有实现细节的虚线基类实现的。
在所有的前面都加有一个字母I, 如:IX表示的“接口X”。
而在类名称的前面所加的前缀则为C, 如CA表示“类A”。
Microsoft Win32软件开发工具(SDK)中OBJBASE.H头文件的定义:#define interface struct
使用struct的原因在于struct的成员将自动具有我公有的属性,因此不需要另外定义中加上public关键字。
Microsoft平台上COM接口所提供的所有函数使用的均是标准的调用约定.参数数目可变的函数使用的则是C调用约定.一般人们希望接口的实现使用这些约定.但要说明的是这并不是COM的绝对需要.
在WINDEF.H中pascal的定义如下:
#define pascal __stdcall
如果读者认为将pascal这个词放在代码中会让人莫名其妙,那么可以使用OBJBASE.H中所定义的如下宏:
#define STDMEFHODCALLTYPE __stdcall
类并非组件
用C++开发组件时不一定非用类不可。组件也可以用C来实现。一个组也可以由多个类来实现。
接口并非总是继承的
COM没有要求实现某个接口的类必须从那个接口继承,这是客户并不需要了解COM组件的继承关系。对接口的继承只不过是一种实现细节而已。
多重接口及多重继承
一个接口是一个函数集合,一个组件则是一个接口集,而一个系统则是一系列组件的集合。
接口不变性
一旦分布了一个接口,那么它将永远保持不变。当对组件进行升级时,一般不会修改已有的接口,面是加入一些新接口。
对于一个支持多个接口的组件,接口函数的名字出现冲突是经常会遇到的。这些种情况下,改变某个发生冲突的函数名称即可。COM对此不关心。COM接口是一个二进制标准,客户同接口的连接并不是通过其名称或其成员函数的名称完成的,而是通过它在表示它的内存块的位完成的。
解决命名冲突的另外一种 方法是不使用多重继承。
实现组件的类并不需要继承每一个接口,而可以使用指向实现某些接口的类的指针。
接口名称之间出现冲突的情况也是可能的。如果在接口和函数名称的前面加上公司名称或产品名称可以减少此种 可能性。
多态指的是可以按同一种方式来处理不同的对象。若两个不同的组件支持同一接口,那么客户将可以使用相同的代码一处理其中的任何一个组件。就是说,客户可以按照相同的方式来处理不同的组件。
虚拟函数表
当定义一个纯抽象类时,所定义的实际上是一个内存块的结构.纯抽象类所有实现都是一些具有相同的基本结构的内存.
如下定义一个抽象基类。内存结构如图2-4所示:
interface IX
virtual void __stdcall Fx1() = 0 ;
virtual void __stdcall Fx2() = 0 ;
virtual void __stdcall Fx3() = 0 ;
virtual void __stdcall Fx4() = 0 ;
定义一个抽象基类也就是定义了相应的内存结构。但些内存只在派生在中实现些抽象基类时才会被分配。当派生类继承一个抽象基类时,它将继承此内存结构。
似乎是一个的偶然的巧合,COM接口的内存结构同C++编译器为抽象基类所生成的内存结构是相同的.因此可以使用抽象基类来定义COM接口.
对于一个COM接口还有其他一些需求.例如,所有的COM接口都必须继承一个名为Iunknown的接口.
Vtbl指针及实例数据
Vtbl指针在由抽象基类函数指针到函数的过程中增加了一个额外的级别。这带了很大的灵活性。
实现抽象基类的类可能会将特定于实例的信息同vtbl一块保存。如下IX的实现类CA:
class CA : public IX
virtual void __stdcall Fx1(){cout && "CA::Fx1" &&}
virtual void __stdcall Fx2(){cout && m_Fx2 &&}
virtual void __stdcall Fx3(){cout && m_Fx3 &&}
virtual void __stdcall Fx4(){cout && m_Fx4 &&}
CA(double d):
m_Fx2(d*d),m_Fx3(d*d*d), m_Fx4(d*d*d*d)
double m_Fx2;
double m_Fx3;
double m_Fx4;
在C++中同一个类的不同实例可以共享同一个vtbl。如下:
int main()
CA* pA1 = new CA(4.3);
CA* pA2 = new CA(5.1);
虽然COM组件可以使用vtbl指针来共享vtbl,但这一点并不是必需的。COM组件的每个实例中已有一个不同的vtbl
不同的类,相同的vtbl
接口的真正威力在于继承此接口的所有类均可以被客户按同一方式进行处理。
class CB : public IX
// implementatio inerface IX.
virtual void __stdcall Fx1(){cout && "CB::Fx1" &&}
virtual void __stdcall Fx2(){cout && "CB::Fx2" &&}
virtual void __stdcall Fx3(){cout && "CB::Fx3" &&}
virtual void __stdcall Fx4(){cout && "CB::Fx4" &&}
void foo(IX* pIX)
pIX-&Fx1();
pIX-&Fx2();
int main()
CA* pA = new CA(4.3);
CB* pB = new CB;
IX* pIX = pA;
从上例中,我们将CA和CB都当成是IX接口来作用。这也是多态的一个例子。
从上图可以看出,CA 和 CB 分别具有不同的实例数据、vtbl以及实现。但是因其具有相同的而可以按相同的方式来访问。
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!

我要回帖

更多关于 支付宝接口参数无效 的文章

 

随机推荐