1.組件中必須有3個(gè)函數(shù),QueryInterface、AddRef、Release,它們3個(gè)函數(shù)也組成一個(gè)接口,叫"IUnknown"。
2.組件API及接口指針中,除了IUnknown::AddRef()和IUnknown::Release()兩個(gè)函數(shù)外,其它所有的函數(shù),都以 HRESULT 作為返回值。
3.原則:COM 組件是運(yùn)行在分布式環(huán)境中的。通俗地說,你不能直接把一個(gè)內(nèi)存指針直接作為參數(shù)傳遞給COM函數(shù)。
4.結(jié)果判斷一般用VC提供的宏:
HRESULT hr = 調(diào)用組件函數(shù);
if( SUCCEEDED( hr ) ){...} // 如果成功
if( FAILED( hr ) ){...} // 如果失敗
5.Browser Helper Objects,我譯為"瀏覽器幫助者對象",以下皆簡稱BHO
==================================
如果感覺不清楚,請先參看com組件應(yīng)用(1),因?yàn)榉独菑纳侠懈脑爝^來的。
還是用具體范例來講: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;
};
實(shí)現(xiàn)類:
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;
}
// 創(chuàng)建接口
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;
}
// 創(chuàng)建接口
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);
闡述總結(jié):繼承IUnknown 接口,實(shí)現(xiàn)其中方法。 這樣就可以通過QueryInterface 來查詢接口,并使用其中的函數(shù)。