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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
组件基础 1 软件开发的阶段 1.1 结构化编程 采用自顶向下的编程方式,划分模块 和功能的一种编程方式。 1.2 面向对象编程 采用对象的方式,将程序抽象成类, 模拟现实世界,采用继承、多态的方式 设计软件的一种编程方式。 1.3 面向组件编程 将功能和数据封装成二进制代码,采用 搭积木的方式实现软件的一种编程方式。 2 组件和优点 2.1 组件 - 实际是一些可以执行的二进 制程序,它可以给其他的应用程序、操 作系统或其他组件提供功能 2.2 优点 2.2.1 可以方便的提供软件定制机制 2.2.2 可以很灵活的提供功能 2.2.3 可以很方便的实现程序的分布式 开发。 3 组件的标准 - COMComponent Object Model ) 3.1 COM是一种编程规范,不论任何开发语言 要实现组件都必须按照这种规范来实现。 组件和开发语言无关。 这些编程规范定义了组件的操作、接口的 访问等等。 3.2 COM接口 COM接口是组件的核心,从一定程度上 讲"COM接口是组件的一切". COM接口给用户提供了访问组件的方式. 通过COM接口提供的函数,可以使用组件 的功能. 4 COM组件 4.1 COM组件-就是在Windows平台下, 封装在动态库(DLL)或者可执行文件(EXE) 中的一段代码,这些代码是按照COM的 规范实现. 4.2 COM组件的特点 4.2.1 动态链接 4.2.2 与编程语言无关 4.2.3 以二进制方式发布 二 COM接口 1 接口的理解 DLL的接口 - DLL导出的函数 类的接口 - 类的成员函数 COM接口 - 是一个包含了一组函数指针 的数据结构,这些函数是由组件实现的 2 C++的接口实现 2.1 C++实现接口的方式,使用抽象类 定义接口. 2.2 基于抽象类,派生出子类并实现 功能. 2.3 使用 interface 定义接口 interface ClassA { }; 目前VC中,interface其实就是struct 3 接口的动态导出 3.1 DLL的实现 3.1.1 接口的的定义 3.1.2 接口的实现 3.1.3 创建接口的函数 3.2 DLL的使用 3.2.1 加载DLL和获取创建接口的函数 3.2.2 创建接口 3.2.3 使用接口的函数 4 接口的生命期 4.1 问题 在DLL中使用new创建接口后,在用户 程序使用完该接口后,如果使用delete 直接删除,会出现内存异常. 每个模块有自己的内存堆(crtheap) EXE - crtheap DLL - crtheap new/delete/malloc/free默认情况 下都是从自己所在模块内存堆(crtheap) 中分配和施放内存.而各个模块的 这个内存堆是各自独立.所以在DLL中 使用new分配内存,不能在EXE中delete. 4.2 引用计数和AddRef/Release函数 引用计数 - 就是一个整数,作用是 表示接口的使用次数 AddRef - 增加引用计数 +1 Release - 减少引用计数 -1, 如果 当引用计数为0,接口被删除 4.3 使用 4.3.1 创建接口 4.3.2 调用AddRef,增加引用计数 4.3.3 使用接口 4.3.4 调用Release,减少引用计数 4.4 注意 4.4.1 在调用Release之后,接口指针 不能再使用 4.4.2 多线程情况下,接口引用计数 要使用原子锁的方式进行加减 5 接口的查询 5.1 每个接口都具有唯一标识 GUID 5.2 实现接口查询函数 QueryInterface 6 IUnknown 接口 6.1 IUnknown是微软定义的标准接口 我们实现所有接口就是继承这个接口 6.2 IUnknown定义了三个函数 QueryInterface 接口查询函数 AddRef 增加引用计数 Release 减少引用计数 7 接口定义语言 - IDL(Interface Definition Language ) 7.1 IDL和MIDL IDL - 定义接口的一种语言,与开发 语言无关. MIDL.EXE - 可以将IDL语言定义接口, 编译成C++语言的接口定义 7.2 IDL的基础 import "XXXX.idl" [ attribute ] interface A : interface_base { } 7.2.1 Import 导入,相当于C++的 #include 7.2.2 使用"[]"定义区域,属性描述 关键字 1) object - 后续是对象 2) uuid - 定义对象GUID 3) helpstring - 帮助信息 4) version - 版本 5) point_default - 后续对象 中指针的默认使用方式 比如: uniqune - 表示指针可以 为空,但是不能修改 7.2.3 对象定义 1) 父接口是IUnknown接口 2) 在对象内添加函数,函数定义必须 是返回 HRESULT. HRESULT是32位整数,返回函数是否 执行成功,需要使用 SUCCESSED和 FAILED宏来判断返回值.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值