實現COM消息廣播

 

大家都知道,爲ActiveX控件添加事件處理函數是件容易的事情,IDE已經提供相應的Wizard,爲ActiveX控件添加事件處理函數和爲一般控件添加事件處理函數沒有什麼兩樣。而爲普通COM組件添加事件處理函數,就沒有這麼直觀了,必須手工編寫相關代碼。

 

如果完全手工去編寫這些代碼,可以說是相當的麻煩,實際上相當編寫另外一個COM組件給原組件調用,至少要實現IDispatch接口才行。不過在ATL的幫助下,事情簡化了很多。

 

另外一方面,一個組件的事件,只有對應的客戶端才能收到,如何把事件變爲廣播消息,讓所有的客戶端都知道呢?這個問題容易解決:組件端記錄所有的客戶端,把事件發給每一個客戶端就行了。下面我們看一個簡單的例子。

 

一、實現COM組件服務端

(COM組件作爲一個服務器在一個單獨的EXE內部運行。)

l         VC6新建一個ATL項目server,服務器類型爲Executable

l         Insert à New ATL ObjectàObjectsàSimple Object

l         名稱爲Chat,在屬性中選中Support Connection Points(即支持事件)

l         IChat增加接口函數:HRESULT Send(BSTR str);

l         _IchatEvents增加事件:HRESULT OnMessage(BSTR str);

l         ReBuild All

l         右鍵點擊類Cchat, Implement Connection Points

l         Cchat增加一個靜態成員,記錄所有Cchat對象實例。static std::list<CChat*> s_AllInstances;

l         實現Send函數,該函數中對所有Cchat對象實例觸發OnMessage事件。

STDMETHODIMP CChat::Send(BSTR str)

{

         // TODO: Add your implementation code here

         for(std::list<CChat*>::iterator iter = s_AllInstances.begin(); iter != s_AllInstances.end(); iter++)

         {

                   CChat* obj = *iter;

 

                   obj->Fire_OnMessage(str);

         }

        

         return S_OK;

}

二、實現客戶端

VC6創建ATL/WTL項目,應用程序類型爲Dialog based

CmainDlg繼承IdispEventImpl接口。

class CMainDlg : public CAxDialogImpl<CMainDlg>, public CUpdateUI<CMainDlg>,

                   public CMessageFilter, public CIdleHandler,

                   public IDispEventImpl<0, CMainDlg, &DIID__IChatEvents, &LIBID_SERVERLib>

 

增加事件函數描述信息。

_ATL_FUNC_INFO g_OnMessageInfo = {CC_STDCALL, VT_EMPTY, 1, {VT_BSTR} };

 

實現消息處理函數,不要忘了加_stdcall修飾。

void _stdcall OnRecv(BSTR str)

         {

                   USES_CONVERSION;

                   CListBox lb(GetDlgItem(IDC_LIST_ALL_MESSAGE));

                   lb.InsertString(-1, OLE2A(str));

 

                   return ;

         }

增加事件映射。SINK_ENTRY_INFO 的第一個參數要與IdispEventImpl的第一個參數一致,其取值沒有限制。

         BEGIN_SINK_MAP(CMainDlg)

                   SINK_ENTRY_INFO(0, DIID__IChatEvents, 1, OnRecv, &g_OnMessageInfo)

         END_SINK_MAP()

 

調用組件函數。

         LRESULT OnSend(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)

         {

                   char szBuff[1024] = {0};

                   sprintf(szBuff, "(%d):", GetCurrentProcessId());

 

                   this->GetDlgItemText(IDC_EDIT_MESSAGE, szBuff+strlen(szBuff), 1000);

 

                   m_ichat->Send(CComBSTR(szBuff));

                   // TODO : Add Code for control notification handler.

                   return 0;

         }

 

OnInitDialog中增加初始化代碼。

                   if(SUCCEEDED(m_ichat.CoCreateInstance(CComBSTR(L"Server.Chat"))))

                   {

                            if(FAILED(DispEventAdvise(m_ichat, &DIID__IChatEvents)))

                            {

                                     MessageBox("DispEventAdvise failed!");

                            }

                   }

                   else

                   {

                            MessageBox("CoCreateInstance failed!");

                   }

CloseDialog中增加~初始化代碼。

if(FAILED(DispEventUnadvise(m_ichat, &DIID__IChatEvents)))

                   {

                            MessageBox("DispEventUnadvise failed!");

                   }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章