編寫可複用性更好的C++代碼——Band對象和COMToys(三)

來源:互聯網
上載者:User

編譯/趙湘寧

原著:Paul Dilascia

MSJ November 1999 & December 1999

關鍵字:Bands 對象,Desk Bands,Info/Comm Bands,Explorer Bar,Tool Bands。

本文假設你熟悉C++,COM,IE。

下載本文原始碼: MyBands.zip (128KB)
                TestEditSrch.zip (75KB)

第一部分:Band 對象介紹
第二部分:BandObj的類層次和MyBands服務程式的註冊

第三部分 深入Band內部,揭開Band的面紗

    前面兩個部分討論了 MyBands 對象的建立和註冊,現在MyBands已經註冊妥當並且也具備了類工廠來建立它們,是揭穿Band對象真正面目的時候了。
    Band對象是一個坐落在工作列或IE中的視窗。但同時我還希望你認識到band對象也是一個必須實現如下三個介面的COM對象:IDeskBand, IObjectWithSite 和 IPersistStream。如果要接受使用者輸入,可選擇實現IInputObject介面,如果下想要操作功能表,可選擇實現IContextMenu介面。圖十展示了band對象的所有介面,包括必須實現的和可選擇實現的介面。

圖十

    在Band對象的這些介面中,最重要的是IDeskBand介面,它派生於IDockingWindow,,而IDockingWindow又派生於IOleWindow。這兩個介面是必須實現的介面。它們的作用是什麼呢?
    理解Band對象或任何諸如此類的COM對象的最好方法是檢查對象存在時的一系列事件--如監測使用者從工具列中選擇Band直到關閉Band期間的活動。為此最好的方法是用能啟動並執行例子代碼並在代碼中加上TRACE診斷。BandObj具備有內建的診斷功能,它是通過使用一個我自己編寫的診斷工具實現的,這個診斷工具叫TRACEFN。TRACEFN中用一個專門的類以及一個AfxTrace的自定製版本來產生期望的診斷輸出,利用它可以看到堆棧的內容,圖十一顯示的就是MyBands運行時的診斷輸出,從使用者在工具列菜單中選擇Web搜尋方塊開始一步一步往下走。
    Windows(案頭band用於資源管理員,瀏覽欄用於IE)通過尋找實現了CATID_DeskBand,,CATID_InfoBand,或 CATID_CommBand的COM對象來發現band對象,並將band的名字添加到工具列菜單(四)。
當使用者從菜單選中band時,Windows調用CoCreateInstance或它的同等函數。COM則調用DLL中的DllGetClassObject輸出函數,而DllGetClassObject又調用AfxDllGetClassObject。MFC用正確的ID搜尋到一個類工廠並將它返回。然後COM調用IClassFactory::CreateInstance進行一系列的COM常規處理。

    接著,Windows查詢IDeskBand 和IObjectWithSite介面。CBandObj以常用的MFC方式實現這些介面--使用嵌套類,介面映射,以及BEGIN/END_INTERFACE_PART,然後MFC返回正確的指標。
    Windows調用IObjectWithSite::SetSite給出一個(IUnknown*)類型的指標指向對象容器。CBandObj::XObjectWithSite::GetSite調用CBandObj::OnSetSite虛函數,將嵌套類方法轉換成父類的虛函數調用,以便你能輕鬆地重載。預設的實現將現場m_spSite儲存在中。你可以在m_spSite中查詢(QueryInterface)任何容器實現的介面。CBandObj使用它獲得其父視窗的HWND:

CComQIPtr spOleWin = m_spSite;if (!spOleWin)   return E_FAIL;HWND hwndParent = NULL;spOleWin->GetWindow(&hwndParent);if (!hwndParent)   return E_FAIL;      

    當Windows調用SetSite時,它希望你建立自己的視窗。從有關說明文檔中很難看出這一點來,我只是覺得很彆扭。CBandObj::OnSetSite調用虛函數OnCreateWindow來做這個工作。我的預設實現可以註冊並建立通用的不可見視窗。

BOOL CBandObj::OnCreateWindow(CWnd* pParent, const CRect& rc){   static BOOL bRegistered = FALSE;   static CCriticalSection cs; // protection   CTLockData lock(cs);   // 註冊視窗類別   if (!bRegistered) {     AfxRegisterClass(...);     bRegistered = TRUE;   }   return CWnd::Create(BANDOBJCLASS,...);}     

    Band對象的執行緒模式是"Apartment",所以對全程變數的保護很重要。最好是儘可能讓全程變數與使用它們的函數保持緊密聯絡。在例子中,OnCreateWindow是唯一使用bRegistered的函數,所以是一個靜態函數。你可以重載OnCreateWindow來建立自己的視窗類別,和/或者重載PreCreateWindow來改變視窗的某些屬性。只是要記住:你建立的視窗一定要是不可見的,既保證不要使用WS_VISIBLE來建立視窗。
    接下來,Windows調用IOleWindow::GetWindow來獲得視窗的HWND。(這就是為什麼你必須在SetSite中建立視窗的原因)。由CBandObj返回m_hWnd。
    接著,Windows調用IDeskBand::GetBandInfo請求關於band的資訊,如大小,可變高度或者定高,以及背景顏色和標題。CBandObj用預設值填充DESKBANDINFO結構--這些值都可以在band對象的建構函式中修改--有些資訊來自你的資源檔。例如,從資源串中獲得標題。下一步,Windows調用IDockingWindow:: ShowDW來顯示建立的視窗。CBandObj 調用CWnd:: ShowWindow完成顯示。
    如果使用者有輸入或者用右鍵訪問操作功能表,則Windows要分別查詢相應的IInputObject和IContextMenu介面。如果你實現了這些介面,Windows將使用它們。CBandObj的預設實現從資源檔中擷取鍵盤加速鍵和菜單資訊。你只要將資源添加到工程就可以了。菜單本身被存在一個資料成員m_contextMenu中,可以隨時取用。
CMyDeskBand沒有資源菜單,取而代之的是通過讀取使用者屬性設定檔案來動態建立菜單(十二)。

圖十二

    在向容器添加菜單之前(當容器調用IContextMenu::QueryContextMenu時),CBandObj通過MFC的ON_UPDATE_COMMAND_UI命令處理器來路由菜單。十二,CMyDeskBand就是通過這種方式實現了搜尋引擎旁邊的選中檢查標誌。
    如果使用者使用菜單加速鍵或者選中功能表項目來調用某個命令,Windows則會調用IContextMenu::InvokeCommand。CBandObj的做法與初始化這個菜單的做法一樣,所以這個命令通常都會到達ON_COMMAND命令處理器。
    當使用者關閉Band時,Windows調用IDockingWindow::CloseDW。CBandObj則發送WM_CLOSE訊息,這樣視窗便消失。但是CBandObj對象仍然活著,直到Windows釋放它。只要你用TRACE跟蹤一下就會明白以上所述的邏輯過程了。(待續)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.