COM组件应用(2)——IUnknown
1.组件中必须有3个函数,QueryInterface、AddRef、Release,它们3个函数也组成一个接口,叫"IUnknown"。
2.组件API及接口指针中,除了IUnknown::AddRef()和IUnknown::Release()两个函数外,其它所有的函数,都以 HRESULT 作为返回值。
3.原则:COM 组件是运行在分布式环境中的。通俗地说,你不能直接把一个内存指针直接作为参数传递给COM函数。
4.结果判断一般用VC提供的宏:
HRESULT hr = 调用组件函数;
if( SUCCEEDED( hr ) ){...} // 如果成功
if( FAILED( hr ) ){...} // 如果失败
5.Browser Helper Objects,我译为"浏览器帮助者对象",以下皆简称BHO
==================================
如果感觉不清楚,请先参看com组件应用(1),因为范例是从上例中改造过来的。
还是用具体范例来讲:computer_def.h
#include
<
Unknwn.h
>
#define UUID_ICOMPUTER __declspec( uuid( "9DC95DDC-FF98-4afe-B17E-42F028E34F68" ) )
class UUID_ICOMPUTER Icomputer: public IUnknown
{
public :
virtual int add( int a, int b ) = 0 ;
};
#define UUID_ICOMPUTEREX __declspec( uuid( "3B8BF613-7AF1-4672-9EC3-E5DC49A6E8D9" ) )
class UUID_ICOMPUTEREX IcomputerEx: public IUnknown
{
public :
virtual int sub( int a, int b ) = 0 ;
};
#define UUID_ICOMPUTER __declspec( uuid( "9DC95DDC-FF98-4afe-B17E-42F028E34F68" ) )
class UUID_ICOMPUTER Icomputer: public IUnknown
{
public :
virtual int add( int a, int b ) = 0 ;
};
#define UUID_ICOMPUTEREX __declspec( uuid( "3B8BF613-7AF1-4672-9EC3-E5DC49A6E8D9" ) )
class UUID_ICOMPUTEREX IcomputerEx: public IUnknown
{
public :
virtual int sub( int a, int b ) = 0 ;
};
实现类:
class
Ccomputer :
public Icomputer,
public IcomputerEx
{
public :
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR * __RPC_FAR * ppvObject)
{
if (riid == __uuidof(Icomputer))
{
* ppvObject = (Icomputer * )( this );
}
else if (riid == __uuidof(IcomputerEx))
{
* ppvObject = (IcomputerEx * )( this );
}
return S_OK;
}
virtual ULONG STDMETHODCALLTYPE AddRef( void )
{
m_nRef ++ ;
return m_nRef;
}
virtual ULONG STDMETHODCALLTYPE Release( void )
{
m_nRef -- ;
if ( 0 == m_nRef)
{
delete this ;
}
return 0 ;
}
virtual int add( int a, int b)
{
return a + b;
}
virtual int sub( int a, int b)
{
return a - b;
}
private :
ULONG m_nRef;
};
public Icomputer,
public IcomputerEx
{
public :
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR * __RPC_FAR * ppvObject)
{
if (riid == __uuidof(Icomputer))
{
* ppvObject = (Icomputer * )( this );
}
else if (riid == __uuidof(IcomputerEx))
{
* ppvObject = (IcomputerEx * )( this );
}
return S_OK;
}
virtual ULONG STDMETHODCALLTYPE AddRef( void )
{
m_nRef ++ ;
return m_nRef;
}
virtual ULONG STDMETHODCALLTYPE Release( void )
{
m_nRef -- ;
if ( 0 == m_nRef)
{
delete this ;
}
return 0 ;
}
virtual int add( int a, int b)
{
return a + b;
}
virtual int sub( int a, int b)
{
return a - b;
}
private :
ULONG m_nRef;
};
使用上:
Icomputer
*
pComputer;
IcomputerEx * pComputerEx;
HMODULE hDll = ::LoadLibrary(TEXT( " computer.dll " ));
typedef HRESULT (__stdcall * PFN_DllGetClassObject)(Icomputer ** ppv);
PFN_DllGetClassObject pDllGetClassObject = (PFN_DllGetClassObject)::GetProcAddress(hDll, " DllGetClassObject " );
if (NULL == pDllGetClassObject)
{
// nRet = STATUS_SEVERITY_ERROR;
}
// 创建接口
HRESULT hRet = pDllGetClassObject( & pComputer);
if (FAILED(hRet))
{
// nRet = STATUS_SEVERITY_ERROR;
}
……
int iRet = pComputer -> add(iNum_1,iNum_2);
pComputer -> QueryInterface(__uuidof(IcomputerEx),( void ** ) & pComputerEx);
// pComputerEx = (pComputerEx)(pC);
iRet = pComputerEx -> sub(iNum_1,iNum_2);
IcomputerEx * pComputerEx;
HMODULE hDll = ::LoadLibrary(TEXT( " computer.dll " ));
typedef HRESULT (__stdcall * PFN_DllGetClassObject)(Icomputer ** ppv);
PFN_DllGetClassObject pDllGetClassObject = (PFN_DllGetClassObject)::GetProcAddress(hDll, " DllGetClassObject " );
if (NULL == pDllGetClassObject)
{
// nRet = STATUS_SEVERITY_ERROR;
}
// 创建接口
HRESULT hRet = pDllGetClassObject( & pComputer);
if (FAILED(hRet))
{
// nRet = STATUS_SEVERITY_ERROR;
}
……
int iRet = pComputer -> add(iNum_1,iNum_2);
pComputer -> QueryInterface(__uuidof(IcomputerEx),( void ** ) & pComputerEx);
// pComputerEx = (pComputerEx)(pC);
iRet = pComputerEx -> sub(iNum_1,iNum_2);
阐述总结:继承IUnknown 接口,实现其中方法。 这样就可以通过QueryInterface 来查询接口,并使用其中的函数。