12.1.10 使用ATL建立進程外組件
1.問題闡述
在前面建立的組件均屬於進程內組件,即組件對象和客戶進程在同一個進程,客戶進程在同一進程內調用組件對象提供的服務;進程外組件,組件對象和客戶進程分屬不同的進程,客戶進程可以跨進程調用組件對象提供的服務。如何建立一個進程外的組件呢?
2.實現技巧
使用ATL建立組件嚮導建立一個進程外組件,首先使用ATL COM AppWizard建立一個工程,12-11所示。
單擊【OK】按鈕,選擇組件提供服務時所用的類型。在此因為是進程外組件,故選用Executable類型,12-12所示。
|
(點擊查看大圖)圖12-12 選擇組件提供伺服器的類型 |
最後添加組件提供的介面,和前面介紹的就基本一致了。
3.執行個體代碼
本例的消費者和生產者的簡單模型由COM來實現。
元件伺服器具體建立步驟如下。
(1)用ATL COM Appwzard建立一個新的工程,工程名為ProcOut。
(2)選擇組件提供服務時所用的類型(.dll或.exe)。
(3)在工程中插入一個對象。在ClassView選項頁面,用滑鼠右鍵單擊工程名,在彈出的右鍵菜單中選擇【New ATL Object】,在開啟的對話方塊中選中Simple Object,12-13所示。
(4)單擊【Next】按鈕,在開啟對話方塊的ShortName中輸入 Modu,其他的按預設設定,12-14所示。
(5)定義介面函數。在介面IModu上面點擊滑鼠右鍵,在彈出的捷徑功能表中選擇【Add Method】命令。出現添加生產函數對話方塊,添加介面函數HRESULT,參數Produce([in]long nProduce),12-15所示。
(6)添加消費函數HRESULT Customer([in]long nProduce),12-16所示。
(7)添加屬性,在ClassView頁中用滑鼠右鍵單擊介面,選擇【Add Property】命令,開啟的對話方塊12-17所示。
(8)元件服務的代碼,元件服務提供了生產和消費函數及改變屬性的兩個函數,其代碼參考如下。
在類Cobject的標頭檔Object.h中新增成員變數:
int m_lNum;//表示當前的數量
生產函數的參考代碼如下:
STDMETHODIMP CObject::Produce(long nProduce) { m_lNum += nProduce; return S_OK; } |
消費函數的參考代碼如下:
STDMETHODIMP CObject::Customer(long nCustomer) { m_lNum -= nCustomer; if(m_lNum<0) { MessageBox(NULL,"消耗沒了","提示",MB_OK); m_lNum = 0; } return S_OK; } |
介面屬性函數的參考代碼如下:
STDMETHODIMP CObject::get_CurrentNum(long *pVal) { *pVal = m_lNum; return S_OK; } STDMETHODIMP CObject::put_CurrentNum(long newVal) { m_lNum = newVal; return S_OK; } |
(9)在用戶端建立一個基於對話方塊的工程ProcOutTest,放置兩個文字框分別表示生產或消耗的數量和當前現存的數量。放置兩個按鈕,用於響應生產和消費事件。參考代碼如下。
在ProcOutTest的InitInstance中添加AfxOleInit( )初始化應用程式COM環境。
在stdafx.h中引入ProcOut.tlb庫:
#import "ProcOut.tlb" no_namespace |
在ProcOutTestDlg.h中聲明介面的智能指標:
在ProcOutTest.cpp中的OinitDialog添加建立介面執行個體的代碼:
HRESULT hr = m_IObject.CreateInstance(L"ProcOut.Object"); if(FAILED(hr)) { MessageBox("建立介面執行個體失敗!"); return FALSE; } m_IObject->put_CurrentNum(100);//初始化數量為100 m_IObject->get_CurrentNum(&m_Cur); |
響應生產和消費兩個按鈕事件的代碼:
void CProcOutTestDlg::OnProduceBtn() { UpdateData(TRUE); m_IObject->Produce(m_Num); m_IObject->get_CurrentNum(&m_Cur); UpdateData(FALSE); } void CProcOutTestDlg::OnCustomerBtn() { UpdateData(TRUE); m_IObject->Customer(m_Num); m_IObject->get_CurrentNum(&m_Cur); UpdateData(FALSE); } |
運行效果12-18所示。