《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

原文地址:https://www.cnblogs.com/DennisXie/p/3970710.html