COM组件学习笔记--COM组件示例

创建Visual C++工程.

启动Visual C++并创建一个新工程,选择Win32 Dynamic-Link Library,工程命名为”Server”。

创建IMATH.H文件

创建了两个抽象类Imath和IAdvancedMath。

//
//imath.h
//
// {03030C27-753F-4374-9A0B-C190D11F56C1} 由GUIDGEN.EXE创建
DEFINE_GUID(CLSID_Math,
      0x3030c27, 0x753f, 0x4374, 0x9a, 0xb, 0xc1, 0x90, 0xd1, 0x1f, 0x56, 0xc1);
// {D7AB8963-4081-42cb-96B1-4441140B3D37}
DEFINE_GUID(IID_IMath,
      0xd7ab8963, 0x4081, 0x42cb, 0x96, 0xb1, 0x44, 0x41, 0x14, 0xb, 0x3d, 0x37);
// {0249DE54-6989-47ec-8071-C3B4DFBFE1D3}
DEFINE_GUID(IID_IAdvancedMath,
      0x249de54, 0x6989, 0x47ec, 0x80, 0x71, 0xc3, 0xb4, 0xdf, 0xbf, 0xe1, 0xd3);

class IMath : public IUnknown
{
public:
    STDMETHOD(Add)(long , long , long * ) PURE;//PURE 相当于 "=0"
    STDMETHOD(Subtract)(long , long , long * ) PURE;
    STDMETHOD(Multiply)(long , long , long * ) PURE;
    STDMETHOD(Divide)(long , long , long * ) PURE;
};
class IAdvancedMath : public IUnknown
{
public:
    STDMETHOD(Factorial)( short , long * ) PURE;
    STDMETHOD(Fibonacci)( short , long * ) PURE;
};

声明组件和类工厂:

//
//math.h
//
#include "imath.h"
extern long g_lObjs;
extern long g_lLocks;
//组件类的声明
class Math : public IMath , public IAdvancedMath { public: Math(); ~Math(); //IUnknown STDMETHOD(QueryInterface( REFIID , void ** )); STDMETHOD_(ULONG , AddRef()); STDMETHOD_(ULONG , Release()); //IMath STDMETHOD(Add)(long , long , long * ); STDMETHOD(Subtract)(long , long , long * ); STDMETHOD(Multiply)(long , long , long * ); STDMETHOD(Divide)(long , long , long * ); //IAdvancedMath STDMETHOD(Factorial)( short , long * ); STDMETHOD(Fibonacci)( short , long * ); protected: long m_lRef; }; //类工厂的声明 class MathClassFactory : public IClassFactory { public: MathClassFactory(); ~MathClassFactory(); //IUnknown STDMETHOD(QueryInterface( REFIID , void ** )); STDMETHOD_(ULONG , AddRef()); STDMETHOD)(ULONG , Release()); //IClassFactory STDMETHOD(CreateInstance)(LPUNKNOWN , REFIID , void ** ); STDMETHOD(LockServer)(BOOL); protected: long m_lRef; };

组件类和类工厂类的实现:

//
//Math.cpp
//
#include
#include "math.h"
//
//Math class implenmentation
//
Math::Math()
{
    m_lRef = 0;
    InterlockedIncrement(&g_lObjs);
}
Math::~Math()
{
    InterlockedDecrement(&g_lObjs);
}
STDMETHODIMP Math::QueryInterface( REFIID riid, void ** ppv)
{
    *ppv = 0;
    if(riid == IID_IUnknown )
    *ppv = (IMath * )this;
    else if( riid == IID_IMath )
    *ppv = (IMath * )this;
    else if( riid == IID_IAdvancedMath )
    *ppv = (IAdvancedMath *)this;
    if( *ppv )
    {
        AddRef();
        return(S_OK);
    }
    return(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG)Math::AddRef()
{
    return InterlockedIncrement( &m_lRef);
}
STDMETHODIMP_(ULONG)Math::Release()
{
    if (InterlockedDecrement(&m_lRef) == 0 )
    {
        delete this;
        return 0;
    }
    return m_lRef;
}
STDMETHODIMP Math::Add( long lOp1 , long lOp2 , long *pResult )
{
    *pResult = lOp1 + lOp2;
    return S_OK;
}
STDMETHODIMP Math::Subtract( long lOp1 , long lOp2 , long *pResult )
{
    *pResult = lOp1 - lOp2;
    return S_OK;
}
STDMETHODIMP Math::Multiply( long lOp1 , long lOp2 , long *pResult )
{
    *pResult = lOp1 * lOp2;
    return S_OK;
}
STDMETHODIMP Math::Divide( long lOp1 , long lOp2 , long *pResult )
{
    *pResult = lOp1 / lOp2;
    return S_OK;
}
static long calcFactorial( short n)
{
    if ( n <= 1 )
    {
        return 1;
    }
    return n * calcFactorial( n - 1 );
}
STDMETHODIMP Math::Factorial( short sOp , long * pResult )
{
    *pResult = calcFactorial( sOp );
    return S_OK;
}
static long calcFibonacci( short n )
{
    if ( n <= 1 )
    {
        return 1;
    }
    return calcFibonacci(n-1) + calcFibonacci(n-2);
}
STDMETHODIMP Math::Fibonacci( short sOp , long * pResult )
{
    *pResult = calcFibonacci(sOp);
    return S_OK;
}
MathClassFactory::MathClassFactory()
{
    m_lRef = 0;
}
MathClassFactory::~MathClassFactory()
{
}
STDMETHODIMP MathClassFactory::QueryInterface( REFIID riid , void ** ppv )
{
    *ppv = 0;
    if ( riid == IID_IUnknown || riid == IID_IClassFactory )
    *ppv = this;
    if ( *ppv )
    {
        AddRef();
        return S_OK;
    }
    return(E_NOINTERFACE);
}

STDMETHODIMP_(ULONG)MathClassFactory::AddRef()
{
    return InterlockedIncrement(&m_lRef);
}
STDMETHODIMP_(ULONG)MathClassFactory::Release()
{
    if ( InterlockedDecrement(&m_lRef) == 0 )
    {
        delete this;
        return 0;
    }
    return m_lRef;
}
STDMETHODIMP MathClassFactory::CreateInstance( LPUNKNOWN pUnkOuter , REFIID riid , void ** ppvObj )
{
    Math * pMath;
    HRESULT hr;
    *ppvObj = 0;
    pMath = new Math;
    if ( pMath == 0 )
        return(E_OUTOFMEMORY);
    hr = pMath->QueryInterface( riid , ppvObj);
    if( FAILED(hr) )
        delete pMath;
    return hr;
}
STDMETHODIMP MathClassFactory::LockServer(BOOL fLock)
{
    if(fLock)
        InterlockedIncrement(&g_lLocks);
    else
        InterlockedDecrement(&g_lLocks);
    return S_OK;
}

创建组件的宿主(Server.cpp)

//
//server.cpp
//
//
#include
#include
#include "math.h"
long g_lObjs = 0;
long g_lLocks = 0;
STDAPI DllGetClassObject( REFCLSID rclsid , REFIID riid , void ** ppv )
{
    HRESULT hr;
    MathClassFactory * pCF;
    if( rclsid != CLSID_Math )
        return(E_FAIL);
    pCF = new MathClassFactory;
    if( pCF == 0 )
        return(E_OUTOFMEMORY);
    hr = pCF->QueryInterface( riid , ppv );
    if(FAILED(hr))
        delete pCF;
    return hr;
}
STDAPI DllCanUnloadNow(void)
{
    if( g_lObjs || g_lLocks)
        return(S_FALSE);
    else
        return(S_OK);
}

添加对自注册和组件类别的支持

//
//server.cpp
//
//
#include
//Component category support
#include
#include
#include "math.h"
//Our component category GUID
#include "ATLDevGuide.h"
//Used to store the instance handle
//We need this to call the GetModuleFileName API
HINSTANCE g_hinstDLL = 0;
long g_lObjs = 0;
long g_lLocks = 0;
//DLLMain
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason , LPVOID lpvReserved )
{
    if( fdwReason == DLL_PROCESS_ATTACH )
        g_hinstDLL = hinstDLL;
    return TRUE;
}

static BOOL SetRegKeyValue(
    LPTSTR pszKey,
    LPTSTR pszSubkey,
    LPTSTR pszValue)
{
    BOOL bOk = FALSE;
    LONG ec;
    HKEY hKey;
    TCHAR szKey[128];
    lstrcpy( szKey , pszKey);
    if( NULL != pszSubkey )
    {
        lstrcat( szKey , "\\" );
        lstrcat( szKey , pszSubkey );
    }
    ec = RegCreateKeyEx(
        HKEY_CLASSES_ROOT,
        szKey,
        0,
        NULL,
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        NULL,
        &hKey,
        NULL);
    if(ERROR_SUCCESS == ec)
    {
        if(NULL != pszValue )
        {
        ec = RegSetValueEx(
            hKey,
            NULL,
            0,
            REG_SZ,
            (BYTE*) pszValue,
            (lstrlen(pszValue)+1) * sizeof(TCHAR));
        }
        if(ERROR_SUCCESS == ec )
            bOk = TRUE;
            RegCloseKey(hKey);
    }
    return bOk;
}
HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)
{
    ICatRegister* pcr = 0;
    HRESULT hr;
    hr = CoCreateInstance( CLSID_StdComponentCategoriesMgr,
            NULL,
            CLSCTX_INPROC_SERVER,
            IID_ICatRegister,
            (void**)&pcr );
    if (FAILED(hr))
        return hr;
    CATEGORYINFO catinfo;
    catinfo.catid = catid;
    catinfo.lcid = 0x0409;
    int len = wcslen( catDescription );
    wcsncpy( catinfo.szDescription, catDescription, wcslen( catDescription ));
    catinfo.szDescription[len] = '\0';
    hr = pcr->RegisterCategories( 1, &catinfo );
    pcr->Release();
    return hr;
}

HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
// Register your component categories information.
    ICatRegister* pcr = 0;
    HRESULT hr;
    hr = CoCreateInstance( CLSID_StdComponentCategoriesMgr,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_ICatRegister,
        (void**)&pcr );
    if (SUCCEEDED(hr))
    {
        CATID rgcatid[1] ;
        rgcatid[0] = catid;
        hr = pcr->RegisterClassImplCategories( clsid, 1, rgcatid );
        pcr->Release();
    }
    return hr;
}

STDAPI DllRegisterServer(void)
{
    HRESULT hr = NOERROR;
    CHAR szModulePath[MAX_PATH];
    CHAR szID[128];
    CHAR szCLSID[128];
    WCHAR wszID[128];
    WCHAR wszCLSID[128];
    GetModuleFileName(
        g_hinstDLL,
        szModulePath,
        sizeof(szModulePath) / sizeof(CHAR) );

    StringFromGUID2(CLSID_Math ,wszID , sizeof(wszID));
    wcscpy(wszCLSID,L"CLSID\\");
    wcscat(wszCLSID,wszID);
    wcstombs(szID ,wszID , sizeof(szID));
    wcstombs(szCLSID,wszCLSID, sizeof(szID));
    //Create the ProgID keys
    SetRegKeyValue(
        "Chapter2.Math.1",
        NULL,
        "Chapter2 Math Component");
    SetRegKeyValue(
        "Chapter2.Math.1",
        "CLSID",
        szID);
    //Create version independent ProgID keys
    SetRegKeyValue(
        "Chapter2.Math",
        NULL,
        "Chapter2 Math Component");
    SetRegKeyValue(
        "Chapter2.Math",
        "CurVer",
        "Chapter2.Math.1");
    SetRegKeyValue(
        "Chapter2.Math",
        "CLSID",
        szID);
    //Create entries under CLSID
    SetRegKeyValue(
        szCLSID,
        NULL,
        "Chapter 2 Math Component");
    SetRegKeyValue(
        szCLSID,
        "ProgID",
        "Chapter2.Math.1");
    SetRegKeyValue(
        szCLSID,
        "VersionIndependentProgID",
        "Chapter2.Math");
    SetRegKeyValue(
        szCLSID,
        "InprocServer32",
        szModulePath);
    //Register our component category
    CreateComponentCategory(CATID_ATLDevGuide,
        L"ATL Developer's Guide Examples");
    RegisterCLSIDInCategory( CLSID_Math , CATID_ATLDevGuide);
    return S_OK;
}

STDAPI DllGetClassObject( REFCLSID rclsid , REFIID riid , void ** ppv )
{
    HRESULT hr;
    MathClassFactory * pCF;
    if( rclsid != CLSID_Math )
        return(E_FAIL);
    pCF = new MathClassFactory;
    if( pCF == 0 )
        return(E_OUTOFMEMORY);
    hr = pCF->QueryInterface( riid , ppv );
    if(FAILED(hr))
        delete pCF;
    return hr;
}

STDAPI DllCanUnloadNow(void)
{
    if( g_lObjs || g_lLocks)
        return(S_FALSE);
    else
        return(S_OK);
}

标准入口点的导出

;
;Server.def:Declares the module parameters for the DLL.
;
LIBRARY "SERVER"
DESCRIPTION 'SERVER Windows Dynamic Link Library'
EXPORTS
;Explicit exports can go here
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
; DllUnregiesterServer PRIVATE

注册DLL:使用Regsvr32命令注册

使用OLEVIEW测试Math组件

建立一个简单的COM客户端:

// COMClient.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include
#include
#include
#include
#include "..\server\imath.h"
int main(int argc, char* argv[])
{
    cout << "Initializing COM" << endl;
    if( FAILED(CoInitialize(NULL)))
    {
        cout << "Unable to initialize COM" << endl;
        return -1;
    }
    //Get the unique CLSID from the ProgID
    CLSID clsid;
    HRESULT hr = ::CLSIDFromProgID(L"Chapter2.Math.1" , &clsid );
    if( FAILED(hr))
    {
        cout.setf( ios::hex , ios::basefield);
        cout << "Unable to get CLSID from ProgID. HR = " << hr << endl;
        return -1;
    }
    //Get the class factory for the Math class
    IClassFactory * pCF;
    hr = CoGetClassObject(clsid,
        CLSCTX_INPROC,
        NULL,
        IID_IClassFactory,
        (void **) &pCF);
    if( FAILED(hr) )
    {
        cout.setf(ios::hex,ios::basefield);
        cout << "Failed to GetClassObject server instance.HR ="
<< hr << endl;
        return -1;
}
    //Using the class factory interface create an instance of the
    //Component and return the IUnknown interface
    IUnknown * pUnk;
    hr = pCF->CreateInstance( NULL , IID_IUnknown , (void**) &pUnk);
    //Release the class factory
    pCF->Release();
    if(FAILED(hr))
    {
        cout.setf( ios::hex , ios::basefield);
        cout << "Failed to create server instance.HR = " << hr << endl;
        return -1;
    }
    cout << "Instance created" << endl;
    IMath * pMath = NULL;
    hr = pUnk->QueryInterface(IID_IMath , (void **) &pMath);
    pUnk->Release();
    if( FAILED(hr))
    {
        cout << "QueryInterface() for IMath failed" << endl;
        CoUninitialize();
        return -1;
    }
    long result;
    pMath->Multiply( 100 , 8 , &result);
    cout << "100 * 8 is " << result << endl;
    pMath->Subtract( 1000, 333 , &result);
    cout << "10000 - 333 is " << result << endl;
    //Try IAdvancedMath
    IAdvancedMath* pAdvMath = NULL;
    hr = pMath->QueryInterface( IID_IAdvancedMath , (void **) & pAdvMath);
    if( FAILED(hr))
    {
        cout << "QueryInterface() for IAdvancedMath failed" << endl;
        pMath->Release();
        CoUninitialize();
        return -1;
    }
    pAdvMath->Factorial(10, &result);
    cout << "10! is " << result << endl;
    pAdvMath->Fibonacci( 10 , &result);
    cout << "The Fibonacci of 10 is " << result << endl;
    cout << "Releasing IMath interface " << endl;
    pMath->Release();
    cout << "Shutting down COM" << endl;
    CoUninitialize();
    return 0;
}

你可能感兴趣的:(COM组件学习笔记--COM组件示例)