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 來查詢接口,并使用其中的函數。