• 《COM原理与应用》学习笔记——一个简单的COM组件的实现


      今天带来一个简单的COM组件的实现,非常的简单。这个组件只是简单的完成了整数的加减乘除~

    首先,先罗列需要的COM接口,这里需要的接口非常简单,就是加减乘除的接口。所以定义一个ICalc类,当然这个类继承于IUnknown。

    1 class ICalc : public IUnknown
    2 {
    3 public:
    4     virtual long __stdcall add(long a, long b) = 0;
    5     virtual long __stdcall minus(long a, long b) = 0;
    6     virtual long __stdcall times(long a, long b) = 0;
    7     virtual long __stdcall devide(long a, long b) = 0;
    8 };

    这只是定义了一个接口,接着我们要定义COM对象类,COM对象类理所当然的要继承自ICalc类。其中override是C++11提供的新关键字,表示明确的覆盖父类的某个函数。

     1 class CCalc : public ICalc
     2 {
     3 public:
     4     CCalc();
     5     ~CCalc() = default;
     6 
     7 public:
     8     //IUnknown interface:
     9     virtual HRESULT __stdcall QueryInterface(const IID &iid, void **ppv) override;
    10     virtual ULONG __stdcall AddRef() override;
    11     virtual ULONG __stdcall Release() override;
    12 
    13     //ICalc interface:
    14     virtual long __stdcall add(long a, long b) override;
    15     virtual long __stdcall minus(long a, long b) override;
    16     virtual long __stdcall times(long a, long b) override;
    17     virtual long __stdcall devide(long a, long b) override;
    18 
    19 private:
    20     long m_lRef;//用于计数的变量
    21 };

    接着是类厂的定义,定义如下:

    class CCalcFactory : public IClassFactory
    {
    public:
        CCalcFactory();
        ~CCalcFactory() = default;
    
    public:
        //STDMETHODCALLTYPE = __stdcall
        //IUnknown interface:
        virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID &iid, void **ppv) override;
        virtual ULONG STDMETHODCALLTYPE AddRef() override;
        virtual ULONG STDMETHODCALLTYPE Release() override;
    
        //IClassFactory interface:
        virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, const IID &iid, void **ppv) override;
        virtual HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) override;
    
    protected:
        long m_lRef;
    };

     接下来讲解以上各个类的具体实现:

    首先是Ccalc的实现,那几个加减乘除的接口我就不写了。

    HRESULT CCalc::QueryInterface(const IID &iid, void **ppv)
    {
        if (iid == IID_Calc)
        {
            *ppv = (ICalc *) this;
            ((ICalc *)(*ppv))->AddRef();
        } 
        else if (iid == IID_IUnknown)
        {
            *ppv = (ICalc *) this;
            ((ICalc *)(*ppv))->AddRef();
        }
        else
        {
            *ppv = NULL;
            return E_NOINTERFACE;
        }
    
        return S_OK;
    }
    
    ULONG CCalc::AddRef()
    {
        ++m_lRef;
        return (ULONG)m_lRef;
    }
    
    ULONG CCalc::Release()
    {
        --m_lRef;
        //当引用计数变为0的时候就将COM对象删除,并将COM对象的引用减一以便COM库知道能否释放资源
        if (m_lRef == 0)
        {
            --g_ulCalcNumber;
            delete this;
            return 0;
    
        }
        return (ULONG)m_lRef;
    }

    接下来是类厂的实现:

     1 extern ULONG g_ulCalcNumber;
     2 extern ULONG g_ulLockNumber;
     3 
     4 CCalcFactory::CCalcFactory()
     5 {
     6     m_lRef = 0;
     7 }
     8 
     9 HRESULT CCalcFactory::QueryInterface(const IID &iid, void **ppv)
    10 { 
    11     if (iid == IID_IUnknown)
    12     {//返回自己的IUnknown指针
    13         *ppv = (IUnknown *)this;
    14         ((IUnknown *)(*ppv))->AddRef();
    15     }
    16     else if (iid == IID_IClassFactory)
    17     {//如果IID是类厂的IID就返回自己的接口指针以便客户程序能够用该指针创建COM对象
    18         *ppv = (IClassFactory *)this;
    19         ((IClassFactory *)(*ppv))->AddRef();
    20     }
    21     else
    22     {
    23         *ppv = NULL;
    24         return E_NOINTERFACE;
    25     }
    26 
    27     return S_OK;
    28 }
    29 
    30 ULONG CCalcFactory::AddRef()
    31 {
    32     ++m_lRef;
    33     return (ULONG)m_lRef;
    34 }
    35 
    36 ULONG CCalcFactory::Release()
    37 {
    38     --m_lRef;
    39     if (m_lRef == 0)
    40     {
    41         delete this;
    42         return 0;
    43     }
    44     return (ULONG)m_lRef;
    45 }
    46 
    47 HRESULT CCalcFactory::CreateInstance(IUnknown *pUnkOuter, const IID &iid, void **ppv)
    48 {
    49     CCalc *pObj;
    50     HRESULT result;
    51     
    52     if (NULL != pUnkOuter)
    53     {
    54         return CLASS_E_NOAGGREGATION;
    55     }
    56 
    57     pObj = new (std::nothrow) CCalc;
    58     if (pObj == NULL)
    59     {
    60         return E_OUTOFMEMORY;
    61     }
    62 
    63     result = pObj->QueryInterface(iid, ppv);
    64     if (result != S_OK)
    65     {
    66         --g_ulCalcNumber;
    67         delete pObj;
    68     }
    69 
    70     return result;
    71 }
    72 
    73 HRESULT CCalcFactory::LockServer(BOOL fLock)
    74 {
    75     if (fLock)
    76     {
    77         ++g_ulLockNumber;
    78     } 
    79     else
    80     {
    81         --g_ulLockNumber;
    82     }
    83     return NOERROR;
    84 }

    其他重要函数的实现:

     1 //这个导出函数是COM库用来创建类厂对象的函数,函数原型必须这样写。
     2 extern "C" HRESULT __stdcall DllGetClassObject(const CLSID &clsid, const IID &iid, LPVOID *ppv)
     3 {
     4     if (clsid == CLSID_CCalc)
     5     {
     6         //创建类厂对象
     7         CCalcFactory *pCCalcFactory = new (std::nothrow)CCalcFactory;
     8 
     9         if (pCCalcFactory == NULL)
    10         {
    11             return E_OUTOFMEMORY;
    12         }
    13         else
    14         {
    15             //返回类厂对象的指针
    16             HRESULT result = pCCalcFactory->QueryInterface(iid, ppv);
    17             return result;
    18         }
    19     } 
    20     else
    21     {
    22         return CLASS_E_CLASSNOTAVAILABLE;
    23     }
    24 }
    25     
     1 //COM库用来查看是否可以卸载COM对象的函数
     2 extern "C" HRESULT __stdcall DllCanUnloadNow()
     3 {
     4     //当COM对象的引用计数为0,类厂没有被锁,那么就可以卸载
     5     if (g_ulCalcNumber == 0 && g_ulLockNumber == 0)
     6     {
     7         return S_OK;
     8     } 
     9     else
    10     {
    11         return S_FALSE;
    12     }
    13 }
     1 //注册函数,将COM插件注册到注册表中
     2 extern "C" HRESULT __stdcall DllRegisterServer()
     3 {
     4     char szModule[1024];
     5     DWORD dwResult = ::GetModuleFileName((HMODULE)g_hModule, (LPWSTR)szModule, 1024);
     6     if (dwResult == 0)
     7         return SELFREG_E_CLASS;
     8     return RegisterServer(CLSID_CCalc,
     9         szModule,
    10         "Calc.Object",
    11         "Calc Component",
    12         NULL);
    13 }
    1 //反注册函数,也可以说是注销函数吧。
    2 extern "C" HRESULT __stdcall DllUnregisterServer()
    3 {
    4     return UnregisterServer(CLSID_CCalc,
    5         "Calc.Object", NULL);
    6 }

    里面的具体注册过程什么的我也是拷贝的其他人的代码。具体请参见附件中的代码。

    不太会用博客园的文件系统,先发个百度网盘的链接吧:http://pan.baidu.com/s/1sjPmLKp

  • 相关阅读:
    携程的 Dubbo 之路
    应用上云新模式,Aliware 全家桶亮相杭州云栖大会
    重构:改善饿了么交易系统的设计思路
    Arthas 3.1.2 版本发布 | 增加 logger/heapdump/vmoption 命令
    如何检测 Web 服务请求丢失问题
    VPGAME的Kubernetes迁移实践
    Flink SQL 系列 | 5 个 TableEnvironment 我该用哪个?
    如何构建批流一体数据融合平台的一致性语义保证?
    Flink on YARN(下):常见问题与排查思路
    愚蠢的操作
  • 原文地址:https://www.cnblogs.com/DennisXie/p/3970710.html
Copyright © 2020-2023  润新知