欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
COM組件設計與應用(十三)

COM組件設計與應用(十三)
事件和通知(VC6.0)

作者:
楊老師

下載源代碼

一、前言

  我的 COM 組件運行時(shí)產(chǎn)生一個(gè)窗口,當用戶(hù)雙擊該窗口的時(shí)候,我需要通知調用者;
  我的 COM 組件用線(xiàn)程方式下載網(wǎng)絡(luò )上的一個(gè)文件,當我完成任務(wù)后,需要通知調用者;
  我的 COM 組件完成一個(gè)鐘表的功能,當預定時(shí)間到達的時(shí)候,我需要通知調用者;
  ... ... ... ...
  本回書(shū)開(kāi)始話(huà)說(shuō) COM 的事件、通知、連接點(diǎn)......這些內容比較多,我分兩次(共四回)來(lái)介紹。

二、通知的方法
  當程序甲方內部發(fā)生了某個(gè)事件的時(shí)候,需要通知乙方,無(wú)非使用幾個(gè)方法:
 

通知方式 簡(jiǎn)單說(shuō)明 評論
直接消息 PostMessage()
PostThreadMessage()
向窗口或線(xiàn)程發(fā)個(gè)消息 你什么時(shí)候執行我就不管啦
SendMessage() 馬上執行消息響應函數 不執行完消息處理函數不會(huì )返回
SendMessage(WM_COPYDATA...) 發(fā)消息的同時(shí),還可以帶過(guò)去一些自定義的數據 比較常用,所以單獨列了出來(lái)
間接消息 InvalidateRect()
SetTimer()
......
被調用的函數會(huì )發(fā)送相關(guān)的一些消息 這樣的函數太多了
回調函數 GetOpenFileName()...... 當用戶(hù)改變文件選擇的時(shí)候,執行回調函數 嗨!哥們,這是我的電話(huà),有事就言語(yǔ)一聲。

  在 COM 的時(shí)代,以上這些方法就基本上不能玩轉了,因為...您想呀 COM 組件是運行在分布式環(huán)境中的,地球另一邊計算機上運行的組件,怎么可能給你的窗口發(fā)消息那?當然不能?。ǖ?huà)又說(shuō)回來(lái),對于 ActiveX 這樣只能在本地運行的組件,當然也可以發(fā)送窗口消息的啦。)
  回調函數的方式,是設計 COM 通知方法的基礎?;卣{函數,本質(zhì)上是預先把某一函數的指針告訴我,當我有必要的時(shí)候,就直接呼叫該函數了,而這個(gè)回調函數做了什么,怎么做的,我是根本不關(guān)心的。好了,問(wèn)你個(gè)問(wèn)題:啥是 COM 的接口?接口其實(shí)就是一組相關(guān)函數的集合(這個(gè)定義不嚴謹,但你可以這么理解哈)。因此,在COM中不使用“回調函數”而是使用“回調接口”(說(shuō)的再清楚一些,就是使用一大堆包裝好的“回調函數”集) ,回調接口,我們也叫“接收器接口”。


圖一、客戶(hù)端傳遞接收器接口指針給COM。當發(fā)生事件時(shí),COM調用接收器接口函數完成通知

本回示例程序完成的功能是:
  客戶(hù)端啟動(dòng)組件(Simple11.IEvent1.1)并得到接口指針 IEvent1 *;
  調用接口方法 IEvent1::Advise() 把客戶(hù)端內部的一個(gè)接收器(sink)接口指針(ICallBack *)傳遞到組件服務(wù)器中;
  調用 IEvent1::Add() 去計算兩個(gè)整數的和;
  但是計算結果并不通過(guò)該函數返回,而是通過(guò) ICallBack::Fire_Result() 返回給客戶(hù)端;
  當客戶(hù)端不再需要接受事件的時(shí)候,調用 IEvent1::Unadvise() 斷開(kāi)和組件的聯(lián)系。

三、組件實(shí)現步驟
1、建立一個(gè)工作區(WorkSpace)
2、在工作區中,建立一個(gè) ATL 工程(Project)。示例程序中工程名稱(chēng)叫 Simple11,接受全部默認選項。
3、ClassView 中,執行鼠標右鍵菜單命令 New Atl Object...,添加 ALT 類(lèi)。
   3-1、左側分類(lèi) Category 選擇 Objects,右側 Objects 選擇 SimpleObject(其實(shí)就是默認項目)
   3-2、名稱(chēng) Name 卡片中,輸入組件名稱(chēng)。示例程序中是 Event1(注1)
   3-3、屬性 Attributes 卡片中,修改接口類(lèi)型 Interface 為定制的 Custom(注2)
4、ClassView 中,選擇接口(IEvent1),鼠標右鍵菜單添加函數 Add Method...


圖二、增加接口函數 Add([in] long n1,[in] long n2)


圖三、增加接口函數 Advise([in] ICallBack *pCallBack,[out] long *pdwCookie)


圖四、增加接口函數 Unadvise([in] long dwCookie)

  你應該注意到了,在A(yíng)dd()函數中,并沒(méi)有[out]、[retval] 這樣的 IDL 屬性,嘿嘿,因為我們本來(lái)就不打算通過(guò) Add() 函數直接得到計算結果。不然怎么演示回調接口呀:-) 另外,在函數 Advise()中,需要返回一個(gè)整數 dwCookie,這是干什么?道理很簡(jiǎn)單,因為我們的組件想同時(shí)支持多個(gè)對象的回調連接。因此當客戶(hù)端傳遞一個(gè)接口給我們組件的時(shí)候,我返回給它唯一的一個(gè) cookie 號碼來(lái)表示身份,將來(lái)斷開(kāi)連接的時(shí)候 Unadvise(),它需要把這個(gè) cookie 身份號再給我,這樣我就知道是誰(shuí)想斷開(kāi)了。
5、增加回調接口 ICallBack 的 IDL 定義。打開(kāi) IDL 文件并手工輸入(黑體字部分為手工輸入的) ,然后保存:

import "oaidl.idl";import "ocidl.idl";[object,uuid(7E659BB1-FB79-4188-9661-65CA22B6A3E6),	// 這個(gè) IID 可以用 GUDIGEN.EXE 產(chǎn)生helpstring("ICallBack Interface"),pointer_default(unique)]interface ICallBack : IUnknown{};[object,		// 以下內容同示例程序,當然如果是你自己生成的程序就肯定有差別的啦uuid(7E659BB0-FB79-4188-9661-65CA22B6A3E6),helpstring("IEvent1 Interface"),pointer_default(unique)]interface IEvent1 : IUnknown{[helpstring("method Add")] HRESULT Add([in] long n1, [in] long n2);[helpstring("method Advise")] HRESULT Advise([in] ICallBack * pCallBack, [out] long * pdwCookie);[helpstring("method Unadvise")] HRESULT Unadvise([in] long dwCookie);};[uuid(695C9BB2-2AE9-4232-8225-17AB8BD3BABC),version(1.0),helpstring("Simple11 1.0 Type Library")]library SIMPLE11Lib{importlib("stdole32.tlb");importlib("stdole2.tlb");[uuid(6FCF997C-C811-49DB-9D16-46FAF8D24822),helpstring("Event1 Class")]coclass Event1{[default] interface IEvent1;// 需要手工輸入,據說(shuō) VB 使用的話(huà),不能有 [source,default] 屬性[source, default] interface ICallBack;};};
6、增加回調接口函數


圖五、增加回調接口函數

其實(shí)和以前的方法一樣,只要注意別選錯了接口就好。


圖六、增加接口函數 Fire_Result([in] long nResult)

我們計算整數和,得到結果后,就是要靠這個(gè)回調接口函數去反饋給客戶(hù)端呀。

7、添加組件內部保存回調接口指針的數組
  剛才已經(jīng)說(shuō)過(guò),我們這個(gè)組件打算支持多個(gè)對象的回調連接,因此我們要使用一個(gè)數組來(lái)保存。在 ClassView 中,選擇 CEvent1 類(lèi),增加成員變量 Add Member Variable...


圖七、增加保存 ICallBack * 的數組

  當然,保存一個(gè)數組可以有多種方式。示例程序比較簡(jiǎn)單,定義了一個(gè)10個(gè)元素空間的成員數組變量。如果你已經(jīng)學(xué)會(huì )了使用 STL,那么你也可以用 vector 等容器來(lái)實(shí)現。注意!注意!注意!在構造函數中別忘了初始化數組元素為 NULL。

8、好了,下面開(kāi)始完成所有代碼
STDMETHODIMP CEvent1::Add(long n1, long n2){long nResult = n1 + n2;for( int i=0; i<10; i++){if( m_pCallBack[i] )  // 如果回調接口有效m_pCallBack[i]->Fire_Result( nResult );	// 則發(fā)出事件/通知}return S_OK;}STDMETHODIMP CEvent1::Advise(ICallBack *pCallBack, long *pdwCookie){if( NULL == pCallBack )	// 居然給我一個(gè)空指針?!return E_INVALIDARG;for( int i=0; i<10; i++)	// 尋找一個(gè)保存該接口指針的位置{if( NULL == m_pCallBack[i] )	// 找到了{m_pCallBack[i] = pCallBack;	// 保存到數組中m_pCallBack[i]->AddRef();	// 指針計數器 +1*pdwCookie = i + 1;	// cookie 就是數組下標  		// +1 的目的是避免使用0,因為0表示無(wú)效return S_OK;}}return E_OUTOFMEMORY;	// 超過(guò)10個(gè)連接,內存不夠用啦}STDMETHODIMP CEvent1::Unadvise(long dwCookie){if( dwCookie<1 || dwCookie>10 )	// 這是誰(shuí)干的呀?亂給參數return E_INVALIDARG;if( NULL == m_pCallBack[ dwCookie - 1 ] )	// 參數錯誤,或該接口指針已經(jīng)無(wú)效了return E_INVALIDARG;m_pCallBack[ dwCookie -1 ]->Release();	// 指針計數器 -1m_pCallBack[ dwCookie -1 ] = NULL;		// 空出該下標的數組元素return S_OK;}
四、客戶(hù)端實(shí)現步驟
  大家下載示例程序后,去瀏覽客戶(hù)端的實(shí)現程序吧。這里我只說(shuō)明一下關(guān)于接收器是如何構造的:


圖八、從 ICallBack 派生接收器類(lèi) CSink

  從 ICallBack 派生一個(gè)類(lèi) CSink。確認后 IDE 會(huì )有一個(gè)警告,說(shuō)它找不到 ICallBack 的頭文件,不用理它,因為只有當編譯的時(shí)候,#import 才會(huì )為我們生成 xxxx.tlh、xxxx.tli 文件,這些文件就有 ICallBack 的聲明啦。
  這里 ICallBack 是 COM 接口,因此 CSink 是不能事例化的,如果你去編譯,會(huì )得到一坨一坨(注3)的錯誤,報告說(shuō)你沒(méi)有實(shí)現 virtual 函數。然后,我們可以按照錯誤報告,去實(shí)現所有的虛函數:
// STDMETHODIMP 是宏,等價(jià)于 long __stdcallSTDMETHODIMP CSink::QueryInterface(const struct _GUID &iid,void ** ppv){*ppv=this;	// 不管想得到什么接口,其實(shí)都是對象本身return S_OK;}ULONG __stdcall CSink::AddRef(void){	return 1;	}// 做個(gè)假的就可以,因為反正這個(gè)對象在程序結束前是不會(huì )退出的ULONG __stdcall CSink::Release(void){	return 0;	}// 做個(gè)假的就可以,因為反正這個(gè)對象在程序結束前是不會(huì )退出的STDMETHODIMP CSink::raw_Fire_Result(long nResult){... ...	// 把計算結果顯示在窗口中return S_OK;}
、小結
  COM 組件實(shí)現事件、通知這樣的功能有兩個(gè)基本方法。今天介紹的回調接口方式非常好,速度快、結構清晰、實(shí)現也不復雜;下回書(shū)介紹連接點(diǎn)方式(Support Connection Points),連接點(diǎn)方法其實(shí)并不太好,速度慢(如果是遠程DCOM方式,要謹慎選擇它)、結構復雜、唯一的好處就是 ATL 對它進(jìn)行了包裝,所以實(shí)現起來(lái)反而比較簡(jiǎn)單。不介紹又不行,因為微軟絕大數支持事件的組件都是用連接點(diǎn)實(shí)現的,咳......討厭的微軟(注4)。
注1:本來(lái)設想多舉幾個(gè)例子,因此第一個(gè)叫 Event1,可寫(xiě)完后,感覺(jué)程序已經(jīng)比較復雜了,就沒(méi)繼續再做了。
注2:當然,你選擇使用雙接口 Dual 也沒(méi)有問(wèn)題。但要注意到在下面的步驟,增加回調接口修改 IDL 文件的時(shí)候,我們是要使用 Custom(從IUnknown派生,而不是從IDispatch派生)的。
注3:一坨一坨經(jīng)常用來(lái)形容一堆一堆的狗屎。
注4:微軟的同志們,玩笑話(huà)不要當真呀!我還靠著(zhù)你來(lái)吃飯那。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
COM/ATL通信原理
【轉】java回調函數
COM對象與連接點(diǎn)機制及其MFC程序實(shí)現
Java中的回調函數學(xué)習
轉帖————關(guān)于怎么做matlab的com組件,被vc調用的例子
《COM技術(shù)內幕》FAQ
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久