青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

旅途

如果想飛得高,就該把地平線忘掉

Windows區(qū)對(duì)象(Bands)的創(chuàng)建與定制

 

Windows區(qū)對(duì)象(Bands)的創(chuàng)建與定制
編譯/趙湘寧

本文例子代碼

1 簡(jiǎn)介
  1.1 瀏覽欄區(qū)對(duì)象
  1.2 工具欄區(qū)對(duì)象

  1.3 桌面區(qū)對(duì)象

2 實(shí)現(xiàn)區(qū)對(duì)象
  2.1 注冊(cè)

3 一個(gè)簡(jiǎn)單的例子
  3.1 DLL函數(shù)
  3.2 注冊(cè)定制的瀏覽欄
  3.3 必須實(shí)現(xiàn)的接口
    3.3.1 IUnknown
    3.3.2 IObjectWithSite
    3.3.3 IPersistStream
    3.3.4 IDeskBand
  3.4 可選擇的接口實(shí)現(xiàn)
    3.4.1 IInputObject
  3.5 窗口過程
4 總結(jié)

一、 簡(jiǎn)介
Windows的區(qū)(Bands)對(duì)象有三種:既瀏覽欄(Explorer Bar)區(qū)對(duì)象,工具欄(Tools Bands)區(qū)對(duì)象,和桌面區(qū)對(duì)象(Desk Bands)。

瀏覽欄區(qū)對(duì)象
瀏覽欄區(qū)對(duì)象簡(jiǎn)稱瀏覽欄,它是從IE4.0引入的,它是鄰近瀏覽器窗格的一個(gè)顯示區(qū)域。實(shí)際上它是IE窗口中的一個(gè)子窗口,可以用它來顯示信息及與用戶交互。瀏覽欄即可以是以垂直方式定位在瀏覽器窗格的左邊。也可以水平方式定位在瀏覽器窗格下面。(如圖一)

圖一
在瀏覽欄中可以創(chuàng)建很多子菜單或選項(xiàng),用戶能以不同方式選擇這些子菜單或選項(xiàng)提供的功能,打開IE或者資源管理器,從“查看”菜單中選擇“瀏覽欄”,可以看到Windows提供了幾種標(biāo)準(zhǔn)的瀏覽欄菜單,如“搜索(Search)”,“收藏夾(Favorites)”, 和“歷史記錄(History)”,以及“文件夾(All Folders)”。(如圖二)

圖二
為了創(chuàng)建定制的瀏覽欄,必須編程實(shí)現(xiàn),然后注冊(cè)它們。Windows在外殼(Shell)4.71中引入了區(qū)對(duì)象。它提供與普通窗口一樣的功能。但因?yàn)樗且訧E或外殼為容器的COM對(duì)象,所以實(shí)現(xiàn)起來就與普通窗口有所不同。圖一中顯示的就是一個(gè)簡(jiǎn)單的瀏覽欄例子。圖中有一個(gè)垂直的瀏覽欄和一個(gè)水平的瀏覽欄。

工具欄區(qū)對(duì)象
工具欄區(qū)對(duì)象簡(jiǎn)稱工具欄,它是在IE5.0中引入用以支持單選工具欄(radio toolbar)特性的。IE工具欄實(shí)際上是一個(gè)Rebar控件,它包含了幾個(gè)工具欄(toolbar)控件。通過創(chuàng)建工具欄,你可以將某個(gè)區(qū)對(duì)象功能添加到Rebar控件中。不論是在IE中還是在資源管理器中,區(qū)對(duì)象都是一樣的,所以工具欄也是一個(gè)通用窗口。(如圖三)

圖三

用戶可以從“查看”菜單中的“工具欄”子菜單中選擇顯示單選工具欄,也可以在工具欄區(qū)域單擊鼠標(biāo)右鍵從它的上下文菜單中選擇顯示單選工具欄。

桌面區(qū)對(duì)象
區(qū)對(duì)象也可以用在桌面,也就是創(chuàng)建桌面區(qū)對(duì)象。雖然它們的基本實(shí)現(xiàn)與瀏覽欄類似,但桌面區(qū)與IE沒有關(guān)系,它不用IE作為容器。它主要用來創(chuàng)建桌面浮動(dòng)窗口。通過在任務(wù)欄上單擊右鍵,然后在彈出的菜單中選擇“工具欄”的子菜單選項(xiàng)。(如圖四)

圖四

桌面區(qū)的初始浮動(dòng)位置在任務(wù)欄:(如圖五

圖五

用戶可以將桌面區(qū)拖到桌面上,這時(shí)它就成了一個(gè)普通窗口:(如圖六)

圖六
二、實(shí)現(xiàn)區(qū)對(duì)象
盡管可以像使用普通窗口一樣使用區(qū)對(duì)象,但它們畢竟是COM對(duì)象,存在于某個(gè)容器之中。如瀏覽欄和工具欄位于IE之中,桌面區(qū)位于外殼之中。雖然它們的功能不同,但其基本實(shí)現(xiàn)非常相似。一個(gè)主要的差別是它們的注冊(cè)方式不同,而注冊(cè)方式的不同又決定了對(duì)象的類型及其容器。這一部分我們先討論所有區(qū)對(duì)象實(shí)現(xiàn)的共性。其它的實(shí)現(xiàn)細(xì)節(jié)可參考垂直瀏覽欄例子程序
區(qū)對(duì)象除了要實(shí)現(xiàn) IUnknown 和 IClassFactory 兩個(gè)接口之外,所有的區(qū)對(duì)象還必須實(shí)現(xiàn)以下這幾個(gè)接口:
  •  IDeskBand 
  •  IObjectWithSite 
  •  IPersistStream
另外,在注冊(cè)時(shí)除了注冊(cè)它們的CLSID之外,瀏覽欄和桌面區(qū)對(duì)象還必須進(jìn)行組件類別(category)的注冊(cè)。它決定了對(duì)象的類型及其容器。工具欄不需要進(jìn)行種類注冊(cè)。歸納起來,需要進(jìn)行CATID注冊(cè)的三種區(qū)對(duì)象是:
區(qū)對(duì)象類型 組件類型
垂直瀏覽欄 CATID_InfoBand
水平瀏覽欄 CATID_CommBand
桌面區(qū) CATID_DeskBand

對(duì)于如何注冊(cè)區(qū)對(duì)象的進(jìn)一步討論請(qǐng)參見注冊(cè)部分
如果某個(gè)區(qū)對(duì)象接受用戶輸入,它還必須實(shí)現(xiàn)IInputObject接口。如果要往上下文菜單中添加菜單項(xiàng)目,還必須實(shí)現(xiàn)IContextMenu接口。注意:工具欄區(qū)對(duì)象不支持上下文菜單。
    因?yàn)閰^(qū)對(duì)象實(shí)現(xiàn)的是子窗口,所以它們還必須有窗口過程來處理Windows的消息。
    區(qū)對(duì)象可以通過其IOleCommandTarget接口發(fā)送命令到它的容器。為了得到這個(gè)接口的指針,必須調(diào)用容器的IInputObjectSite::QueryInterface方法請(qǐng)求IID_IoleCommandTarget。然后用IOleCommandTarget::Exec把命令發(fā)送到容器。命令組是CGID_DeskBand。當(dāng)某個(gè)區(qū)對(duì)象的IDeskBand::GetBandInfo方法被調(diào)用時(shí),容器用dwBandID參數(shù)將一個(gè)標(biāo)示符賦給這個(gè)對(duì)象。這個(gè)標(biāo)示符被用于IOleCommandTarget::Exec方法調(diào)用時(shí)所用命令組中的三個(gè)命令。目前命令組共支持四個(gè)IOleCommandTarget::Exec命令I(lǐng)Ds。這四個(gè)命令的解釋如下:
DBID_BANDINFOCHANGED——Band的信息已改變。參數(shù)pvaIn的值應(yīng)該是最近一次調(diào)用所用的band標(biāo)示符。容器將調(diào)用這個(gè)標(biāo)示符所指的band對(duì)象的IDeskBand::GetBandInfo方法請(qǐng)求更新的信息。
DBID_MAXIMIZEBAND——容器將最大化band。參數(shù)pvaIn的值應(yīng)該是最近一次調(diào)用所用的band標(biāo)示符。
DBID_SHOWONLY——關(guān)閉或打開容器中其它band。參數(shù)pvaIn的值為VT_UNKNOWN類型,可以取下列值之一:
描述
pUnk 這個(gè)對(duì)象IUnknown接口的指針。所有其它的桌面band將被隱藏。
0 隱藏所有桌面band。
1 顯示所有桌面band。
DBID_PUSHCHEVRON——目前沒有實(shí)現(xiàn)。

注冊(cè)
區(qū)對(duì)象必須作為進(jìn)程內(nèi)服務(wù)器(in-process)注冊(cè)。其線程模型必須為“Apartment”。也就是說區(qū)對(duì)象必須以DLL的形式來實(shí)現(xiàn)。用來描述服務(wù)器注冊(cè)條目的缺省值是一個(gè)菜單文本串。就拿瀏覽欄來說。這個(gè)菜單出現(xiàn)在資源管理器或IE “查看(View)”菜單的“瀏覽欄(Explorer Bar)”子菜單中。而工具欄的菜單則出現(xiàn)在資源管理器或IE “查看(View)”菜單的“工具欄(Toolbars)”子菜單中。桌面區(qū)出現(xiàn)在任務(wù)欄上下文菜單的“工具欄(Toolbars)”子菜單中。作為菜單資源,提供鍵盤快捷的方法與一般菜單快捷鍵相同。也就是將“&”字符放在某個(gè)單詞字母前表示這個(gè)字母顯示下劃線來指示快捷鍵。
通常區(qū)對(duì)象的注冊(cè)條目如下:
HKEY_CLASSES_ROOT
                        ...
                        CLSID
                        ...
                        {Band 對(duì)象的 CLSID GUID} = "菜單文本串"
                        InProcServer32 = "DLL 路徑名"
                        ThreadingModel = "Apartment"
工具欄區(qū)對(duì)象必須還要注冊(cè)對(duì)象的CLSID。為此必須在HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Toolbar下創(chuàng)建一個(gè)REG_SZ值,用工具欄區(qū)對(duì)象的CLSID GUID串命名。如:
HKEY_LOCAL_MACHINE
                        Software
                        Microsoft
                        Internet Explorer
                        Toolbar
                        { Band 對(duì)象的 CLSID GUID }

除此之外,還有幾個(gè)可選的注冊(cè)值可以加到注冊(cè)表中,本文的例子中未使用這些值。
  • HKEY_CLASSES_ROOT\CLSID\{Band 對(duì)象的 CLSID GUID}\Instance\CLSID, 它應(yīng)該被設(shè)置為 "{4D5C8C2A-D075-11D0-B416-00C04FB90376}". 
  • HKEY_CLASSES_ROOT\CLSID\{Band對(duì)象的CLSID GUID}\Instance\InitPropertyBag\Url 它應(yīng)該被設(shè)置為要在瀏覽欄顯示的包含HTML內(nèi)容的文件位置。
  • \HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Explorer Bars\{Band 對(duì)象的 CLSID GUID}\BarSize 它應(yīng)該被設(shè)置為欄目的高和寬,它需要八個(gè)字節(jié)才能作為串放入注冊(cè)表,字節(jié)之間用逗號(hào)分開。開始的四個(gè)字節(jié)一像素為單位指定大小,格式要用十六進(jìn)制,從最左邊字節(jié)開始。最后四個(gè)字節(jié)是保留字節(jié),應(yīng)該將它置為零。例如,垂直瀏覽欄的缺省寬度為291(0x123)像素,則BarSize 的值應(yīng)該是"23,01,00,00,00,00,00,00" 
如果要用瀏覽欄顯示HTML,則前兩個(gè)注冊(cè)項(xiàng)是必須的。最后一個(gè)注冊(cè)項(xiàng)則根據(jù)垂直的或者水平的瀏覽欄定義相應(yīng)的缺省寬度和高度。
能顯示HTML的瀏覽欄(缺省寬度為291各像素單位)注冊(cè)表?xiàng)l目的形式如下:
HKEY_CLASSES_ROOT
                        ...
                        CLSID
                        ...
                        {Band 對(duì)象的 CLSID GUID} = "菜單文本串"
                        InProcServer32 = "DLL 路徑名"
                        ThreadingModel = "Apartment"
                        Instance
                        CLSID = "{4D5C8C2A-D075-11D0-B416-00C04FB90376}"
                        InitPropertyBag
                        Url = "HTML文件"
                        ...
                        HKEY_CURRENT_USER
                        ...
                        Software
                        ...
                        Microsoft
                        ...
                        Internet Explorer
                        ...
                        Explorer Bars
                        { Band 對(duì)象的 CLSID GUID }
                        BarSize = "23,01,00,00,00,00,00,00"

你可以通過編程的方式來處理區(qū)對(duì)象類別 CATID 的注冊(cè)。創(chuàng)建一個(gè)組件類別管理器對(duì)象(CLSID_StdComponentCategoriesMgr)并請(qǐng)求一個(gè)指向ICatRegister接口的指針。將區(qū)對(duì)象的CLSID和CATID傳遞到ICatRegister::RegisterClassImplCategories。
三、定制瀏覽欄的一個(gè)簡(jiǎn)單例子
這個(gè)例子展示了前面所介紹過的垂直瀏覽欄的整個(gè)實(shí)現(xiàn)過程。它借助了平臺(tái)SDK(Platform SDK——在msdn中可以找到)中關(guān)于band對(duì)象示范代碼。其中還包括了水平瀏覽欄和桌面band的實(shí)現(xiàn)代碼。詳細(xì)實(shí)現(xiàn)細(xì)節(jié)請(qǐng)參見:CommBand.cpp和DeskBand.cpp。
創(chuàng)建定制瀏覽欄的基本過程是這樣的:
  1. 實(shí)現(xiàn)DLL需要的函數(shù)。
  2. 實(shí)現(xiàn)必須的COM接口。
  3. 實(shí)現(xiàn)任何想要的可選接口。
  4. 注冊(cè)對(duì)象的CLSID。
  5. 進(jìn)行恰當(dāng)?shù)慕M件種類注冊(cè)。
  6. 創(chuàng)建IE子窗口,調(diào)整窗口大小適合瀏覽欄的顯示區(qū)域。
  7. 使用子窗口顯示信息并與用戶交互。
實(shí)際上,只要通過恰當(dāng)?shù)慕M件種類注冊(cè),瀏覽欄例子代碼便既可用于瀏覽欄的實(shí)現(xiàn),也能用于桌面band實(shí)現(xiàn)。更加復(fù)雜的實(shí)現(xiàn)將需要定制每種對(duì)象類型的顯示區(qū)域和容器。但大多數(shù)的定制工作都能通過范例代碼以及Windows子窗口的編程技術(shù)來完成。例如,你可以添加用戶交互控制或者進(jìn)行色彩豐富的圖形顯示處理。

DLL函數(shù)
所有三種區(qū)對(duì)象被打包在一個(gè)DLL中,它輸出以下的函數(shù):
  • DllMain
  • DllCanUnloadNow 
  • DllGetClassObject 
  • DllRegisterServer 
這些函數(shù)可以在BandObjs.cpp中找到,它們服務(wù)于所有三種區(qū)對(duì)象。前三個(gè)函數(shù)乃標(biāo)準(zhǔn)的實(shí)現(xiàn),我們不再本文中討論。類工廠也是標(biāo)準(zhǔn)實(shí)現(xiàn),代碼可以在ClsFact.cpp中找到

注冊(cè)定制的瀏覽欄

有了COM對(duì)象后,必須對(duì)瀏覽欄的CLSID進(jìn)行注冊(cè)。另外如果要與IE或資源管理器
協(xié)調(diào)運(yùn)行,還必須進(jìn)行的恰當(dāng)?shù)慕M件種類(CATID_InfoBand)注冊(cè)。這個(gè)工作由DllRegisterServer處理。瀏覽欄例子代碼有關(guān)的處理部分如下:
...
                        //注冊(cè)瀏覽欄對(duì)象
                        if(!RegisterServer(CLSID_SampleExplorerBar, TEXT("垂直瀏覽欄例子")))
                        return SELFREG_E_CLASS;
                        //注冊(cè)瀏覽欄的對(duì)象組件種類
                        if(!RegisterComCat(CLSID_SampleExplorerBar, CATID_InfoBand))
                        return SELFREG_E_CLASS;
                        ...
區(qū)對(duì)象的注冊(cè)使用通常的COM過程,它由私有函數(shù)RegisterServer處理。
除了CLSID之外,這個(gè)區(qū)對(duì)象服務(wù)器還必須注冊(cè)一個(gè)以上的組件種類。這實(shí)際上是垂直瀏覽欄和水平瀏覽欄實(shí)現(xiàn)之間的主要差別。這個(gè)過程的處理是通過創(chuàng)建一個(gè)組件種類管理器對(duì)象(CLSID_StdComponentCategoriesMgr),并用ICatRegister::RegisterClassImplCategories方法來注冊(cè)區(qū)對(duì)象服務(wù)器。在這個(gè)例子中,組件種類注冊(cè)的處理是通過將瀏覽欄的CLSID和CATID傳遞到私有函數(shù)RegisterComCat完成的:
BOOL RegisterComCat(CLSID clsid, CATID CatID)
                        {
                        ICatRegister   *pcr;
                        HRESULT        hr = S_OK ;
                        CoInitialize(NULL);
                        hr = CoCreateInstance(  CLSID_StdComponentCategoriesMgr,
                        NULL,
                        CLSCTX_INPROC_SERVER,
                        IID_ICatRegister,
                        (LPVOID*)&pcr);
                        if(SUCCEEDED(hr))
                        {
                        hr = pcr->RegisterClassImplCategories(clsid, 1, &CatID);
                        pcr->Release();
                        }
                        CoUninitialize();
                        return SUCCEEDED(hr);
                        }

必須實(shí)現(xiàn)的接口
垂直瀏覽欄例子實(shí)現(xiàn)了四個(gè)必須的接口:IUnknown, IObjectWithSite, IPersistStream, 和IDeskBand,它們都在CExplorerBar類中實(shí)現(xiàn)。
IUnknown
構(gòu)造函數(shù),析構(gòu)函數(shù)和IUnknown實(shí)現(xiàn)比較簡(jiǎn)單,本文在此不討論。細(xì)節(jié)請(qǐng)參見源代碼。
IObjectWithSite接口
當(dāng)用戶選擇某個(gè)瀏覽欄時(shí),容器調(diào)用相應(yīng)band對(duì)象的IObjectWithSite::SetSite方法。參數(shù)將被設(shè)置成這個(gè)現(xiàn)場(chǎng)(Site)的IUnknown指針。
通常,SetSite實(shí)現(xiàn)應(yīng)該完成下列步驟:
  1. 釋放當(dāng)前所把持的任何現(xiàn)場(chǎng)指針。
  2. 如果傳遞到SetSite的指針被置為NULL,此則區(qū)對(duì)象被刪除。SetSite可以返回S_OK。
  3. 如果傳遞到SetSite的指針被置為非NULL,則建立新的現(xiàn)場(chǎng)。SetSite應(yīng)該做以下的事情:
  1. 調(diào)用現(xiàn)場(chǎng)QueryInterface方法請(qǐng)求IOleWindow接口。
  2. 調(diào)用IOleWindow::GetWindow獲取父窗口句柄,并存儲(chǔ)它,以便以后使用。如果不再使用的話,就釋放IOleWindow接口。
  3. 創(chuàng)建此band對(duì)象的窗口為一個(gè)子窗口,其父窗口就是上一步獲得的那個(gè)窗口。注意在此不能將它創(chuàng)建成可見窗口。
  4. 如果此band對(duì)象實(shí)現(xiàn)IInputObject,調(diào)用現(xiàn)場(chǎng)QueryInterface方法請(qǐng)求IInputObjectSite接口,存儲(chǔ)這個(gè)接口的指針以備后用。
  5. 如果所有步驟都成功,則返回S_OK,否則返回OLE定義的錯(cuò)誤代碼以指示錯(cuò)誤類型。
以下是瀏覽欄實(shí)現(xiàn)SetSite的方法。m_pSite是私有成員變量,用它來保存IInputObjectSite指針,而m_hwndParent保存父窗口句柄。
STDMETHODIMP CExplorerBar::SetSite(IUnknown* punkSite)
                        {
                        //如果某個(gè)現(xiàn)場(chǎng)被把持,則釋放它
                        if(m_pSite)
                        {
                        m_pSite->Release();
                        m_pSite = NULL;
                        }
                        //如果punkSite 不為NULL, 建立一個(gè)新的現(xiàn)場(chǎng)
                        if(punkSite)
                        {
                        //獲取父窗口
                        IOleWindow  *pOleWindow;
                        m_hwndParent = NULL;
                        if(SUCCEEDED(punkSite->QueryInterface(IID_IOleWindow, (LPVOID*)&pOleWindow)))
                        {
                        pOleWindow->GetWindow(&m_hwndParent);
                        pOleWindow->Release();
                        }
                        if(!m_hwndParent)
                        return E_FAIL;
                        if(!RegisterAndCreateWindow())
                        return E_FAIL;
                        //獲取柄保存IInputObjectSite指針
                        if(SUCCEEDED(punkSite->QueryInterface(IID_IInputObjectSite, (LPVOID*)&m_pSite)))
                        {
                        return S_OK;
                        }
                        return E_FAIL;
                        }
                        return S_OK;
                        }
這個(gè)例子的GetSite只簡(jiǎn)單地用SetSite保存的現(xiàn)場(chǎng)指針實(shí)現(xiàn)了對(duì)現(xiàn)場(chǎng)QueryInterface方法的調(diào)用。
STDMETHODIMP CExplorerBar::GetSite(REFIID riid, LPVOID *ppvReturn)
                        {
                        *ppvReturn = NULL;
                        if(m_pSite)
                        return m_pSite->QueryInterface(riid, ppvReturn);
                        return E_FAIL;
                        }
窗口創(chuàng)建由私有方法RegisterAndCreateWindow負(fù)責(zé)。如果這個(gè)窗口不存在,此方法將瀏覽欄窗口創(chuàng)建成一個(gè)大小適當(dāng)?shù)淖哟翱冢母复翱诰褪怯蒘etSite獲得的那個(gè)窗口。子窗口的句柄存儲(chǔ)在m_hwnd變量中。
BOOL CExplorerBar::RegisterAndCreateWindow(void)
                        {
                        //如果這個(gè)窗口不存在,則創(chuàng)建它
                        if(!m_hWnd)
                        {
                        //子窗口不能沒有父窗口
                        if(!m_hwndParent)
                        {
                        return FALSE;
                        }
                        //如果窗口類沒有注冊(cè),則必須注冊(cè)
                        WNDCLASS wc;
                        if(!GetClassInfo(g_hInst, EB_CLASS_NAME, &wc))
                        {
                        ZeroMemory(&wc, sizeof(wc));
                        wc.style          = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
                        wc.lpfnWndProc    = (WNDPROC)WndProc;
                        wc.cbClsExtra     = 0;
                        wc.cbWndExtra     = 0;
                        wc.hInstance      = g_hInst;
                        wc.hIcon          = NULL;
                        wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
                        wc.hbrBackground  = (HBRUSH)CreateSolidBrush(RGB(0, 0, 192));
                        wc.lpszMenuName   = NULL;
                        wc.lpszClassName  = EB_CLASS_NAME;
                        if(!RegisterClass(&wc))
                        {
                        //如果注冊(cè)失敗,下面的CreateWindow函數(shù)將失敗
                        }
                        }
                        RECT  rc;
                        GetClientRect(m_hwndParent, &rc);
                        //創(chuàng)建這個(gè)窗口。WndProc 將建立m_hWnd變量
                        CreateWindowEx(   0,
                        EB_CLASS_NAME,
                        NULL,
                        WS_CHILD | WS_CLIPSIBLINGS | WS_BORDER,
                        rc.left,
                        rc.top,
                        rc.right - rc.left,
                        rc.bottom - rc.top,
                        m_hwndParent,
                        NULL,
                        g_hInst,
                        (LPVOID)this);
                        }
                        return (NULL != m_hWnd);
                        }
IPersistStream接口
IE將調(diào)用瀏覽欄的IPersistStream接口,以便允許這個(gè)瀏覽欄加載或存儲(chǔ)持久性數(shù)據(jù)。如果沒有持久性數(shù)據(jù),這個(gè)方法仍然必須返回一個(gè)成功代碼。IPersistStream接口從IPersist繼承而來,所以要實(shí)現(xiàn)五個(gè)方法:
GetClassID, IsDirty, Load, Save, GetSizeMax。
本文的這個(gè)瀏覽欄例子不使用持久性數(shù)據(jù),并且只有IPersistStream的最小實(shí)現(xiàn)。GetClassID返回對(duì)象的CLSID(CLSID_SampleExplorerBar),其余的方法返回S_OK, 或者S_FALSE, 或者 E_NOTIMPL。有關(guān)細(xì)節(jié)請(qǐng)參見IPersistStream的實(shí)現(xiàn)。

IDeskBand接口
IDeskBand接口是區(qū)對(duì)象專用接口。它只有一個(gè)方法。IDeskBand接口從IDockingWindow繼承而來,而IDockingWindow又從IOleWindow繼承而來。
IOleWindow有兩個(gè)方法:GetWindow 和 ContextSensitiveHelp。瀏覽欄例子的GetWindow實(shí)現(xiàn)返回瀏覽欄的子窗口句柄m_hwnd。因?yàn)椴粚?shí)現(xiàn)上下文敏感幫助,所以ContextSensitiveHelp返回E_NOTIMPL。
IDockingWindow接口有三個(gè)方法:ShowDW, CloseDW, 和 ResizeBorder。ResizeBorder不在任何區(qū)對(duì)象中使用,應(yīng)該返回E_NOTIMPL。ShowDW方法根據(jù)其不同的參數(shù)值控制瀏覽欄窗口的顯示或隱藏:
STDMETHODIMP CExplorerBar::ShowDW(BOOL fShow)
                        {
                        if(m_hWnd)
                        {
                        if(fShow)
                        {
                        //顯示窗口
                        ShowWindow(m_hWnd, SW_SHOW);
                        }
                        else
                        {
                        //隱藏窗口
                        ShowWindow(m_hWnd, SW_HIDE);
                        }
                        }
                        return S_OK;
                        }
                        CloseDW方法摧毀瀏覽欄窗口:
                        STDMETHODIMP CExplorerBar::CloseDW(DWORD dwReserved)
                        {
                        ShowDW(FALSE);
                        if(IsWindow(m_hWnd))
                        DestroyWindow(m_hWnd);
                        m_hWnd = NULL;
                        return S_OK;
                        }
其余的方法,如GetBandInfo是IDeskBand專用的。IE使用它來指定瀏覽欄的標(biāo)示符以及視圖模式。IE還可能填寫DESKBANDINFO結(jié)構(gòu)的dwMask成員從瀏覽欄請(qǐng)求更多的信息,這個(gè)結(jié)構(gòu)用第三個(gè)參數(shù)傳遞。GetBandInfo應(yīng)該存儲(chǔ)這個(gè)標(biāo)示符和視圖模式并用所請(qǐng)求的數(shù)據(jù)填寫DESKBANDINFO結(jié)構(gòu)。下面是本文瀏覽欄例子所實(shí)現(xiàn)GetBandInfo:
STDMETHODIMP CExplorerBar::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO* pdbi)
                        {
                        if(pdbi)
                        {
                        m_dwBandID = dwBandID;
                        m_dwViewMode = dwViewMode;
                        if(pdbi->dwMask & DBIM_MINSIZE)
                        {
                        pdbi->ptMinSize.x = MIN_SIZE_X;
                        pdbi->ptMinSize.y = MIN_SIZE_Y;
                        }
                        if(pdbi->dwMask & DBIM_MAXSIZE)
                        {
                        pdbi->ptMaxSize.x = -1;
                        pdbi->ptMaxSize.y = -1;
                        }
                        if(pdbi->dwMask & DBIM_INTEGRAL)
                        {
                        pdbi->ptIntegral.x = 1;
                        pdbi->ptIntegral.y = 1;
                        }
                        if(pdbi->dwMask & DBIM_ACTUAL)
                        {
                        pdbi->ptActual.x = 0;
                        pdbi->ptActual.y = 0;
                        }
                        if(pdbi->dwMask & DBIM_TITLE)
                        {
                        lstrcpyW(pdbi->wszTitle, L"瀏覽欄例子");
                        }
                        if(pdbi->dwMask & DBIM_MODEFLAGS)
                        {
                        pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT;
                        }
                        if(pdbi->dwMask & DBIM_BKCOLOR)
                        {
                        //通過移開這個(gè)標(biāo)志來使用默認(rèn)的背景顏色
                        pdbi->dwMask &= ~DBIM_BKCOLOR;
                        }
                        return S_OK;
                        }
                        return E_INVALIDARG;
                        }
可選擇的接口實(shí)現(xiàn)
由兩個(gè)接口的實(shí)現(xiàn)是可選擇的,一個(gè)是IInputObject,另一個(gè)是 IContextMenu。本文的瀏覽欄例子實(shí)現(xiàn)了IInputObject。對(duì)于IContextMenu的實(shí)現(xiàn)細(xì)節(jié)請(qǐng)參考有關(guān)文檔。

IInputObject接口
如果某個(gè)band對(duì)象要接受用戶輸入。那就必須實(shí)現(xiàn)IInputObject接口。IE實(shí)現(xiàn)IInputObjectSite并用IInputObject維護(hù)用戶的輸入焦點(diǎn)。瀏覽欄需要實(shí)現(xiàn)三個(gè)方法:UIActivateIO, HasFocusIO, 和 TranslateAcceleratorIO。
IE調(diào)用UIActivateIO通知瀏覽欄它以被激活或者被置灰。當(dāng)被激活時(shí),瀏覽欄例子調(diào)用SetFocus來設(shè)置窗口輸入焦點(diǎn)。
當(dāng)要確定哪個(gè)窗口有輸入焦點(diǎn)時(shí),IE調(diào)用HasFocusIO。如果瀏覽欄的窗口或它的子窗口之一有輸入焦點(diǎn),HasFocusIO返回S_OK。否則,它返回S_FALSE。
TranslateAcceleratorIO允許對(duì)象處理鍵盤加速鍵。本文瀏覽欄例子沒有實(shí)現(xiàn)這個(gè)方法,所以它返回S_FALSE。
瀏覽欄例子實(shí)現(xiàn)IInputObjectSite的細(xì)節(jié)如下:
STDMETHODIMP CExplorerBar::UIActivateIO(BOOL fActivate, LPMSG pMsg)
                        {
                        if(fActivate)
                        SetFocus(m_hWnd);
                        return S_OK;
                        }
                        STDMETHODIMP CExplorerBar::HasFocusIO(void)
                        {
                        if(m_bFocus)
                        return S_OK;
                        return S_FALSE;
                        }
                        STDMETHODIMP CExplorerBar::TranslateAcceleratorIO(LPMSG pMsg)
                        {
                        return S_FALSE;
                        }
窗口過程
因?yàn)閰^(qū)對(duì)象的顯示用的是子窗口,所以它必須實(shí)現(xiàn)窗口過程來處理Windows消息。瀏覽欄例子實(shí)現(xiàn)了一個(gè)最簡(jiǎn)單的版本,它的窗口過程只處理了五個(gè)消息:WM_NCCREATE, WM_PAINT, WM_COMMAND, WM_SETFOCUS, 和 WM_KILLFOCUS。如果要實(shí)現(xiàn)更多的功能,很容易擴(kuò)充使它處理其它的消息。
LRESULT CALLBACK CExplorerBar::WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
                        {
                        CExplorerBar  *pThis = (CExplorerBar*)GetWindowLong(hWnd, GWL_USERDATA);
                        switch (uMessage)
                        {
                        case WM_NCCREATE:
                        {
                        LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
                        pThis = (CExplorerBar*)(lpcs->lpCreateParams);
                        SetWindowLong(hWnd, GWL_USERDATA, (LONG)pThis);
                        //設(shè)置窗口句柄
                        pThis->m_hWnd = hWnd;
                        }
                        break;
                        case WM_PAINT:
                        return pThis->OnPaint();
                        case WM_COMMAND:
                        return pThis->OnCommand(wParam, lParam);
                        case WM_SETFOCUS:
                        return pThis->OnSetFocus();
                        case WM_KILLFOCUS:
                        return pThis->OnKillFocus();
                        }
                        return DefWindowProc(hWnd, uMessage, wParam, lParam);
                        }
這里WM_COMMAND消息處理器簡(jiǎn)單地返回零。WM_PAINT消息處理器創(chuàng)建文本并顯示在資源管理器或IE的區(qū)對(duì)象中。
LRESULT CExplorerBar::OnPaint(void)
                        {
                        PAINTSTRUCT ps;
                        RECT        rc;
                        BeginPaint(m_hWnd, &ps);
                        GetClientRect(m_hWnd, &rc);
                        SetTextColor(ps.hdc, RGB(255, 255, 255));
                        SetBkMode(ps.hdc, TRANSPARENT);
                        DrawText(ps.hdc, TEXT("瀏覽欄例子"), -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
                        EndPaint(m_hWnd, &ps);
                        return 0;
                        }
WM_SETFOCUS 和 WM_KILLFOCUS消息處理器通過調(diào)用本現(xiàn)場(chǎng)的IInputObjectSite::OnFocusChangeIS方法通知輸入焦點(diǎn)現(xiàn)場(chǎng)改變:
LRESULT CExplorerBar::OnSetFocus(void)
                        {
                        FocusChange(TRUE);
                        return 0;
                        }
                        LRESULT CExplorerBar::OnKillFocus(void)
                        {
                        FocusChange(FALSE);
                        return 0;
                        }
                        void CExplorerBar::FocusChange(BOOL bFocus)
                        {
                        m_bFocus = bFocus;
                        //通知焦點(diǎn)已改變的輸入對(duì)象現(xiàn)場(chǎng)
                        if(m_pSite)
                        {
                        m_pSite->OnFocusChangeIS((IDockingWindow*)this, bFocus);
                        }
                        }
四、總結(jié)

區(qū)對(duì)象提供了靈活和強(qiáng)大的擴(kuò)展方式,通過定制瀏覽欄使得IE的功能大為增強(qiáng)。桌面區(qū)的實(shí)現(xiàn)擴(kuò)展了普通窗口的能力。盡管需要一些對(duì)COM的編程,但終究以子窗口的形式提供了一種用戶界面。從而使今后的許多這種編程實(shí)現(xiàn)都能用類似的Windows編程技術(shù)。雖然本文所討論的例子只提供了有限的功能,但它示范了區(qū)對(duì)象全部的特性,并且可以在此基礎(chǔ)上進(jìn)行擴(kuò)充來創(chuàng)建獨(dú)特和功能強(qiáng)大的的用戶界面。




posted on 2007-07-30 16:20 旅途 閱讀(578) 評(píng)論(0)  編輯 收藏 引用 所屬分類: COM+/DCOM

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲国产高清在线观看视频| 一本色道久久综合亚洲精品高清 | 亚洲欧洲精品一区二区三区| 美女脱光内衣内裤视频久久网站| 久久露脸国产精品| 久久久久久九九九九| 久久人人爽爽爽人久久久| 久久综合图片| 亚洲精品女人| 99riav1国产精品视频| 亚洲午夜激情网站| 久久精品道一区二区三区| 欧美自拍丝袜亚洲| 午夜精品在线| 午夜精品www| 欧美在线视频二区| 久久久久久亚洲精品不卡4k岛国| 久久久国产午夜精品| 久久伊人免费视频| 欧美日韩亚洲一区二区三区在线观看 | 国产精品毛片高清在线完整版| 国产日韩精品在线观看| 亚洲国产影院| 性伦欧美刺激片在线观看| 狼人社综合社区| 99精品视频免费在线观看| 久久精品一区中文字幕| 欧美午夜电影完整版| 亚洲国产成人在线| 久久aⅴ国产紧身牛仔裤| 亚洲国产精品一区在线观看不卡| 亚洲永久免费精品| 欧美日本一道本| 在线成人国产| 欧美在线欧美在线| 一区二区三区精品在线| 六月婷婷久久| 国内精品伊人久久久久av影院| 亚洲视频免费在线观看| 亚洲第一级黄色片| 久久久久久自在自线| 国产欧美日韩不卡免费| 亚洲女性裸体视频| 亚洲精品日韩在线| 久久亚洲私人国产精品va| 一本色道久久综合| 欧美劲爆第一页| 亚洲日韩欧美一区二区在线| 久久免费国产精品| 欧美亚洲一区二区三区| 国产农村妇女毛片精品久久莱园子 | 欧美激情一区二区三级高清视频| 一区二区三欧美| 欧美大学生性色视频| 在线看视频不卡| 久久亚洲国产精品日日av夜夜| 一区二区日韩精品| 欧美三日本三级少妇三99| 亚洲精品国产精品国自产在线 | 在线观看日韩精品| 久久成人精品| 亚洲天堂成人在线观看| 国产精品高潮呻吟视频| 亚洲一区二区三区四区五区午夜 | 亚洲精品日韩精品| 欧美日韩精品一区二区在线播放| 在线精品国产成人综合| 欧美77777| 欧美成人免费在线观看| 亚洲激情另类| 亚洲精品字幕| 国产精品你懂得| 久久精品一级爱片| 久久免费国产精品| 亚洲欧洲在线一区| 亚洲精品日日夜夜| 国产精品久久久久久久久久久久久| 亚洲欧美精品suv| 欧美一区二区观看视频| 在线精品亚洲| 99国内精品久久久久久久软件| 欧美性天天影院| 久久久水蜜桃| 欧美3dxxxxhd| 亚洲影院免费| 久久精品国产一区二区三区免费看 | 蜜臀a∨国产成人精品| 牛牛影视久久网| 亚洲免费网址| 久久精品在线观看| av成人毛片| 欧美一区二区三区免费大片| 亚洲国产老妈| 亚洲欧美日韩精品一区二区| 一区精品在线播放| 99视频精品在线| 精品成人a区在线观看| aaa亚洲精品一二三区| 亚洲一区二区在线免费观看视频| 黄色在线一区| 一区二区三区精密机械公司 | 久久一区二区视频| 中文在线不卡| 久久米奇亚洲| 久久不见久久见免费视频1| 欧美高清视频在线播放| 久久精品亚洲国产奇米99| 欧美国产精品日韩| 老司机精品视频网站| 国产精品男人爽免费视频1| 亚洲高清影视| 尹人成人综合网| 亚洲欧美日韩精品一区二区| 一区二区三区成人精品| 久久午夜色播影院免费高清| 欧美一区免费视频| 欧美日韩视频在线第一区| 欧美成人蜜桃| 国精品一区二区| 亚洲欧美经典视频| 亚洲一区二区高清| 欧美激情一区| 欧美激情视频一区二区三区免费 | 99riav国产精品| 亚洲日韩中文字幕在线播放| 久久久福利视频| 久久青草欧美一区二区三区| 国产精品欧美日韩| 一本色道久久综合精品竹菊| 91久久国产精品91久久性色| 久久精品一区蜜桃臀影院| 久久免费国产| 狠狠干综合网| 久久久91精品| 老巨人导航500精品| 韩国精品主播一区二区在线观看| 午夜精品亚洲| 久久婷婷综合激情| 精品不卡一区二区三区| 久久免费午夜影院| 欧美成人网在线| 亚洲欧洲另类| 欧美日韩国产一区| 中文国产成人精品久久一| 亚洲伊人色欲综合网| 国产精品乱码一区二三区小蝌蚪| 亚洲少妇一区| 久久精品免费观看| 亚洲第一区在线| 欧美激情综合五月色丁香小说| 亚洲韩国一区二区三区| 夜夜爽99久久国产综合精品女不卡| 欧美精品在线观看| 亚洲视频你懂的| 久久―日本道色综合久久| 亚洲国产专区校园欧美| 欧美高清在线| 亚洲免费影视| 欧美高清视频www夜色资源网| 99ri日韩精品视频| 国产精品美腿一区在线看| 欧美日韩国产成人在线91| 一本久久综合亚洲鲁鲁五月天| 午夜亚洲福利| 亚洲国产高清高潮精品美女| 欧美日韩黄色大片| 欧美伊人久久| 亚洲精品一区二区三区在线观看 | 久久久国产亚洲精品| 伊人成人在线| 欧美日韩一区二区三区在线看 | 久久久青草青青国产亚洲免观| 亚洲国产欧美不卡在线观看| 欧美日韩一区免费| 久久国产夜色精品鲁鲁99| 亚洲精品美女91| 久久亚洲春色中文字幕| 亚洲图片你懂的| 在线观看一区视频| 国产精品久久久久999| 看欧美日韩国产| 亚洲欧美日韩精品久久| 亚洲精品免费一二三区| 欧美3dxxxxhd| 久久精品国产99国产精品澳门| 亚洲精品中文字幕在线| 国产亚洲午夜| 国产精品夫妻自拍| 欧美国产日本在线| 久久久久一区二区三区| 亚洲欧美国产va在线影院| 亚洲国产清纯| 麻豆成人精品| 久久国产福利国产秒拍| 亚洲视频在线一区| 亚洲老司机av| 亚洲激情社区| 亚洲国产毛片完整版| 一区精品久久| 激情综合色综合久久|