COM組件(ATL篇)


1創建進程內組件    1

1.1 目標    1

1.2 創建項目    3

1.2.1 VC++6.0    3

1.2.2 VC++2010    5

1.3 增加COM    6

1.3.1 VC++6.0    6

1.3.2 VC++2010    8

1.3.3 項目結構    12

1.4 增加方法    13

1.4.1 VC++6.0    13

1.4.2 VC++2010    14

1.5 增加屬性    16

1.5.1 VC++6.0    16

1.5.2 VC++2010    17

1.6 刪除方法、屬性    17

1.7 編碼    17

1.7.1 增加成員變量    17

1.7.2 初始化成員變量    18

1.7.3 實現Add    18

1.7.4 實現Reset    18

1.7.5 實現get_Count    18

1.7.6 實現get_Average    19

1.7.7 實現get_StdDev    19

1.8 注冊、注銷    19

2 VC++使用組件    21

2.1 #import    21

2.2 MFC包裝類    21

2.3 C語言調用    21

 

 

1創建進程內組件

1.1 目標

本章的目標是使用ATL創建一個進程內COM組件。在此組件里,將實現COMCStatisticCOM接口IStatistic,用來進行統計計算。IStatistic的詳細信息如下:

1、方法

void Reset();                //重新開始統計計算

void Add(double dVal);        //增加一個數據

2、屬性

long    Count;                //返回數據個數

double    Average;            //返回平均值

double    StdDev;            //返回標准差

CStatisticVC++代碼如下:

#include <MATH.H>

 

class CStatistic

{

public:

CStatistic()            {Reset();}

public:

void Reset()        {memset(this,0,sizeof(*this));}

void Add(double dVal)

{

++m_nCount;                         //樣本個數

m_dSum += dVal;             //所有樣本值的和

m_dSum2 += dVal * dVal;     //所有樣本值的平方和

}

public://屬性定義(VC++的語法)

__declspec(property(get=GetCount)) ULONG    Count;

__declspec(property(get=GetAverage))     double        Average;

__declspec(property(get=GetStdDev))     double        StdDev;

public:

ULONG GetCount() const        {return m_nCount;}

double GetAverage() const

{

if(m_nCount)

{

return m_dSum / m_nCount;

}

return 0.0;

}

double GetStdDev() const

{

double d = 0.0;

if(m_nCount > 1)

{

d = (m_nCount * m_dSum2 - m_dSum * m_dSum)

/ (m_nCount * (m_nCount - 1));

if(d > 0.0)

{

d = sqrt(d);

}

}

return d;

}

private:

ULONG    m_nCount;     //樣本個數

double        m_dSum;     //所有樣本值的和

double        m_dSum2;     //所有樣本值的平方和

};

測試代碼如下:

ULONG    n    =    0;

double        d    =    0.0;

CStatistic    s;

s.Reset();

s.Add(1.0);

s.Add(2.0);

s.Add(3.0);

s.Add(4.0);

n = s.Count; //(1,2,3,4)的個數

d = s.Average; //(1,2,3,4)的平均值

d = s.StdDev; //(1,2,3,4)的標准差

s.Add(5.0);

n = s.Count; //(1,2,3,4,5)的個數

d = s.Average; //(1,2,3,4,5)的平均值

d = s.StdDev; //(1,2,3,4,5)的標准差

這個類的優點在於:它能實時獲得樣本數據的平均值、標准差,且不用把樣本數據存入數組,因此可以連續的長時間工作。

1.2 創建項目

1.2.1 VC++6.0

運行VC++6.0,新建"ATL COM AppWizard"項目,如下圖所示。配置好項目名稱、項目目錄后,單擊"OK"按鈕。

圖1.1

顯示界面如下所示,直接單擊"Finish"按鈕。

圖1.2

顯示界面如下,單擊"OK"按鈕,完成項目創建。

圖1.3

1.2.2 VC++2010

運行VC++2010,新建"ATL Project"項目,如下圖所示。配置好項目名稱、項目目錄后,單擊"OK"按鈕。

圖1.4

顯示創建向導,界面如下面兩張圖所示:

圖1.5 創建向導——頁面一

圖1.6 創建向導——頁面二

單擊上圖的"Finish"按鈕,完成項目的創建。

1.3 增加COM

現在,往項目里增加COM類。

1.3.1 VC++6.0

單擊【Insert】【New ATL Object...】菜單項

圖1.7

顯示界面如下。請選中"Objects"里的"Simple Object",然后單擊"Next"按鈕。

圖1.8

顯示界面如下,一共有兩個頁面。

圖1.9 增加COM類——頁面一

下圖所示界面里,Interface有兩個選項:Dual表示雙接口(也叫自動化接口),它派生自IDispatchCustom表示自定義接口,它派生自IUnknown。自定義接口直接訪問虛函數表,其效率較高。自動化接口效率較低,但是它支持的語言較多。

圖1.10 增加COM類——頁面二

1.3.2 VC++2010

單擊【Project】【Add Class...】菜單項

圖1.11

選中"ATL Simple Object",然后單擊"Add"按鈕

圖1.12

顯示界面如下,一共有三個頁面

圖1.13 增加COM類——頁面一

圖1.14 增加COM類——頁面二

圖1.15 增加COM類——頁面三

1.3.3 項目結構

VC++6.0的類視圖里增加了"CStatistic"和"IStatistic"。

IStatisticCOM接口,客戶端程序通過它訪問COM組件。

CStatisticCOM類,真正的工作由它來完成。

圖1.16

同時,idl文件也發生了變化,如下表所示。增加了接口IStatistic,增加了COMStatistic,這個COM類實現了接口IStatistic

// comDLLatl.idl

import "oaidl.idl";

import "ocidl.idl";

[

    uuid(0FEBC618-38BC-4A5B-AE09-3C56635F4D73),

    version(1.0),

    helpstring("comDLLatl 1.0 Type Library")

]

library COMDLLATLLib

{

    importlib("stdole32.tlb");

    importlib("stdole2.tlb");

    [

        object,

        uuid(7FB59FA6-E715-4C23-9520-DE93293E0B5F),    

        helpstring("IStatistic Interface"),

        pointer_default(unique)

    ]

    interface IStatistic : IUnknown

    {

    };

    [

        uuid(471BF24D-B793-44A1-9205-7BF36A6EB698),

        helpstring("Statistic Class")

    ]

    coclass Statistic

    {

        [default] interface IStatistic;

    };

};

1.4 增加方法

1.4.1 VC++6.0

鼠標右鍵單擊接口IStatistic,彈出菜單中單擊【Add Method...】菜單項

圖1.17

下圖就是增加方法的界面。這里增加了方法void Add(double dVal)。單擊"OK"按鈕,完成方法的增加。注意:對於自動化接口,Return Type只能是HRESULT

圖1.18

可使用同樣的方法,增加方法void Reset()

1.4.2 VC++2010

鼠標右鍵單擊接口IStatistic,彈出菜單中單擊【Add】【Add Method...】。

圖1.19

增加方法的界面如下。與VC++6.0的大致相同。單擊"Finish"按鈕,完成方法void Add(DOUBLE dVal)的添加。

圖1.20

可使用同樣的方法,增加方法void Reset()

1.5 增加屬性

1.5.1 VC++6.0

在圖1.17中,單擊【Add Property...】菜單項。顯示界面如下:

這里增加了屬性long Count。注意:沒有設置"Put function",說明這個屬性是只讀屬性。

單擊"OK"按鈕,完成屬性的增加。

圖1.21

同樣方法,可以增加屬性double Averagedouble StdDev

1.5.2 VC++2010

在圖1.19中,單擊【Add Property...】菜單項。顯示界面如下:

這里增加了屬性ULONG Count。注意:沒有設置"Put function",說明這個屬性是只讀屬性。

單擊"Finish"按鈕,完成屬性的增加。

圖1.22

同樣方法,可以增加屬性double Averagedouble StdDev

1.6 刪除方法、屬性

使用ATL,刪除屬性、方法,似乎只能手動進行,相當的麻煩。

1.7 編碼

1.7.1 增加成員變量

請給CStatistic增加三個成員變量

private:

ULONG    m_nCount;

double        m_dSum;

double        m_dSum2;

1.7.2 初始化成員變量

CStatistic的構造函數里,初始化這三個成員變量

CStatistic()

{

m_nCount        =    0;

m_dSum        =    0.0;

m_dSum2        =    0.0;

}

1.7.3 實現Add

STDMETHODIMP CStatistic::Add(double dVal)

{

++m_nCount;             //樣本個數

m_dSum += dVal;         //所有樣本值的和

m_dSum2 += dVal * dVal;     //所有樣本值的平方和

return S_OK;

}

1.7.4 實現Reset

STDMETHODIMP CStatistic::Reset()

{

m_nCount = 0;

m_dSum = 0.0;

m_dSum2 = 0.0;

return S_OK;

}

1.7.5 實現get_Count

STDMETHODIMP CStatistic::get_Count(long *pVal)

{

*pVal = m_nCount;

return S_OK;

}

1.7.6 實現get_Average

STDMETHODIMP CStatistic::get_Average(double *pVal)

{

if(m_nCount)

{

*pVal = m_dSum / m_nCount;

}

else

{

*pVal = 0.0;

}

return S_OK;

}

1.7.7 實現get_StdDev

STDMETHODIMP CStatistic::get_StdDev(double *pVal)

{

*pVal = 0.0;

if(m_nCount > 1)

{

*pVal = (m_nCount * m_dSum2 - m_dSum * m_dSum)

/ (m_nCount * (m_nCount - 1));

if(*pVal > 0.0)

{

*pVal = sqrt(*pVal);

}

}

return S_OK;

}

1.8 注冊、注銷

編譯comDLLatl,即可得到進程內COM組件comDLLatl.dll。使用它之前,需要注冊。

注冊組件可使用如下任意一條命令。它們原理相同:都是載入comDLLatl.dll,然后調用DllRegisterServer函數

regsvr32 comDLLatl.dll

Rundll32 comDLLatl.dll,DllRegisterServer

注銷組件可使用如下任意一條命令。它們原理相同:都是載入comDLLatl.dll,然后調用DllUnregisterServer函數

regsvr32 /u comDLLatl.dll

Rundll32 comDLLatl.dll,DllUnregisterServer

注意:VC++2010可以編譯生成64位的COM組件。在64位操作系統上,regsvr32.exeRundll32.exe將自動識別COM組件是32位的還是64位的。注冊信息會寫入注冊表的如下幾個位置。注意這里的<ProgID>其實就是comDLLatl.Statistic

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib\

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\<ProgID>

對於64位組件,注冊程序直接訪問上述注冊表項;對於32位組件,注冊程序會將上述注冊表項映射至32位的注冊表項。如此一來,同一個組件的32位、64位是可以同時注冊在64Windows上的,它們互不干涉。

 

 

2 VC++使用組件

2.1 #import

請參考《COM組件(MFC)》。需要注意的是:MFC創建的COM組件,其接口必定是Dual接口(圖1.10、圖1.15中的Interface選項),也就是派生自IDispatch的自動化接口。ATL可以創建Custom接口,這種接口將派生自IUnknowntli文件里的函數通過虛函數實現,效率較高。Custom接口的不足之處在於:它可能不能被某些腳本語言(如:VBS)調用。

2.2 MFC包裝類

如果接口是Dual接口,就可以生成MFC包裝類。具體操作請參考《COM組件(MFC)》。

2.3 C語言調用

使用C語言也可以訪問COM組件。

如果接口是Dual接口,請參考《COM組件(MFC)》。

如果接口是Custom接口,則可以使用編譯類型庫時產生的C/C++頭文件。如下面這段代碼:(節選自comDLLatl_i.h

#define IStatistic_Add(This,dVal)          ((This)->lpVtbl->Add(This,dVal))

#define IStatistic_get_Count(This,pVal)    ((This)->lpVtbl->get_Count(This,pVal))

亦即:可以通過宏IStatistic_AddIStatistic_get_Count去訪問方法、屬性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM