1.11 ? 容納控件

?

1.11.1????? 容納控件

利用 ATL 所支持的控件容納,可實(shí)現(xiàn)容納控件。比如, CAxDialogImpl 中的 Ax 兩字就表示 ActiveX 控件,表示對(duì)話(huà)框具有容納控件的能力。在對(duì)話(huà)框中實(shí)現(xiàn)容納控件,只需在對(duì)話(huà)框資源上點(diǎn)擊右鍵,從彈出菜單選擇 Insert ActiveX Control ,然后彈出一個(gè)對(duì)話(huà)框,列舉了系統(tǒng)安裝的所有控件,如圖 1-17 所示。

?

1-17.JPG
1-17 ? 插入 ActiveX 控件對(duì)話(huà)框

?

插入控件后,點(diǎn)擊控件可以在控件的屬性窗口設(shè)置控件的屬性。如圖 1-18 所示。

?

1-18.JPG
1-18 控件屬性對(duì)話(huà)框

?

在屬性對(duì)話(huà)框的工具欄上點(diǎn)擊控件事件按鈕,還可以選擇處理控件的事件,如圖 1-19 所示。

?

1-19.JPG
1-19 選擇處理的控件事件

?

容納對(duì)話(huà)框運(yùn)行顯示時(shí),控件被創(chuàng)建,同時(shí)根據(jù)開(kāi)發(fā)階段設(shè)置的屬性初始化控件。圖 1-20 顯示了容納了一個(gè)控件的對(duì)話(huà)框。

?

1-20.JPG
1-20 容納 COM 控件的對(duì)話(huà)框

?

ATL 不但提供了對(duì)話(huà)框的容納控件功能,其他窗口也同樣支持:聲明為對(duì)話(huà)框資源的 UI 控件(稱(chēng)為復(fù)合控件);聲明為 HTML 資源的 UI 控件(稱(chēng)為 HTML 控件)。關(guān)于控件容器的更多信息請(qǐng)參考第十二章“控件容器”。

?

1.11.2 C++ COM 客戶(hù)端

?

至少在理論上, COM C++ 是一致的。一個(gè) COM 接口直接映射為一個(gè) C++ 的抽象類(lèi)。使用 COM 對(duì)象,僅僅需要使用 MIDL 編譯器運(yùn)行 IDL 文件,就可以生成一個(gè)頭文件,里面包含有所有需要的信息。

?

所有的這一切都運(yùn)行正常,直到 VB 團(tuán)隊(duì)詢(xún)問(wèn)他們也是否可以使用 COM 技術(shù)。

?

VB 開(kāi)發(fā)人員通常不知道,也不想知道 C++ 語(yǔ)言。 IDL 也是一個(gè)與 C++ 傳統(tǒng)語(yǔ)言相似的語(yǔ)言,其中也支持許多 C/C++ 的特性(比如數(shù)組和指針)。 VB 需要一種方法來(lái)存儲(chǔ)這些 COM 對(duì)象的類(lèi)型信息,以方便 VB 開(kāi)發(fā)人員使用和理解它們。

?

因此類(lèi)型庫(kù)誕生了(也稱(chēng)為 typelib )。類(lèi)型庫(kù)存儲(chǔ) COM 對(duì)象的信息:對(duì)象支持的接口 classid ;接口的方法; IDL 文件中看到的所有信息,等等 ( 除了一些不合宜的、大部分必須等同 C 數(shù)組處理內(nèi)容 ) COM 系統(tǒng)包含一系列可以根據(jù) typelib 內(nèi)容編程訪(fǎng)問(wèn)的 COM 對(duì)象。最好的就是類(lèi)型庫(kù)可以直接嵌入到 DLL 或者 EXE ,因此不必?fù)?dān)心類(lèi)型庫(kù)信息的丟失。

?

現(xiàn)在,當(dāng)一些 COM 組件沒(méi)有打包 IDL 文件時(shí),類(lèi)型庫(kù)對(duì) VB 開(kāi)發(fā)人員具有非常的意義;類(lèi)型庫(kù)包含有使用組件需要的所有信息?,F(xiàn)在只缺少一樣:如何在 C++ 語(yǔ)言中使用類(lèi)型庫(kù)?

?

C++ 語(yǔ)言并不能理解類(lèi)型庫(kù),它需要頭文件。這就引發(fā)了一系列的問(wèn)題。從 Visual Studio 6 開(kāi)始,微軟擴(kuò)展了編譯器,使你可以像使用頭文件一樣使用類(lèi)型庫(kù)。這種擴(kuò)展使通過(guò)語(yǔ)句 #import 實(shí)現(xiàn)的。

?

#import 可以像 #include 一樣使用,一般使用形式如下:

?

#import “pisvr.dll” <options>

?

#import 語(yǔ)句根據(jù)選項(xiàng)的不同,生成一個(gè)或者兩個(gè) C++ 頭文件。這些頭文件的擴(kuò)展名是 .tlh (用于類(lèi)型庫(kù)頭文件)和 .tli (用于類(lèi)型庫(kù)內(nèi)聯(lián))。都生成在工程的輸出目錄( debug 版默認(rèn)在 Debug 目錄, release 版默認(rèn)在 Release 目錄)。

?

#import 語(yǔ)句提供了很多的選項(xiàng)來(lái)控制生成的文件內(nèi)容??梢栽?/span> Visual Studio 文檔中查看所有的選項(xiàng)列表。此處只介紹一些比較常用的控制項(xiàng)。

?

選項(xiàng) no_namespace 告訴編譯器我們不希望生成的文件內(nèi)容放入一個(gè) C++ 名字空間內(nèi)。默認(rèn)情況下,生成文件的內(nèi)容被放入按類(lèi)型庫(kù)命名的 C++ 名字空間內(nèi)。

?

選項(xiàng) name_guids 告訴編譯器我們希望類(lèi)型庫(kù)中的 GUID 都有一個(gè)命名符號(hào)。默認(rèn)情況下,因?yàn)槊?/span> CLSID_PISvr 沒(méi)有定義,下面的語(yǔ)句不能被編譯:

?

::CoCreateInstance( CLSID_PISvr, … );

?

相反,應(yīng)該使用下面的語(yǔ)句形式:

?

::CoCreateInstance( __uuidof ( PISvr), … );

?

我們同樣需要使用 __uuidof() 來(lái)獲取接口的 IID 。

?

選項(xiàng) raw_interfaces_only 應(yīng)該是最復(fù)雜的。默認(rèn)情況下,當(dāng) #import 生成頭文件時(shí),它不僅僅是生成接口類(lèi)定義。實(shí)際上,生成包裝類(lèi)使得 COM 接口盡可能便于使用。比如,考慮下面的接口定義:

?
interface ICalcPi : IDispatch {
? [propget, id(1), helpstring("property Digits")]
? HRESULT Digits([out, retval] LONG* pVal);
? [propput, id(1), helpstring("property Digits")]
? HRESULT Digits([in] LONG newVal);
? [id(2), helpstring("method CalcPi")]
? HRESULT CalcPi([out,retval] BSTR* pbstrPi);
};

通常情況下,可以如下使用這個(gè)接口:

?

HRESULT DoStuff( long nDigits, ICalcPi *pCalc ) {

??? HRESULT hr = pCalc->put_Digits( nDigits );

??? if( FAILED( hr ) ) return hr;

?

??? BSTR bstrResult;

??? hr = pCalc->CalcPi( &bstrResult );

??? if( FAILED( hr ) ) return hr;

?

??? std::cout << "PI to " << nDigits << " digits is "

??????? << CW2A( bstrResult );

?

??? ::SysFreeString( bstrResult );

??? return S_OK;

}

?

另外一種方法是使用 #import 語(yǔ)句,可以如下使用接口:

void DoStuff( long nDigits, ICalcPiPtr spCalc ) {
  spCalc->Digits = nDigits;
  _bstr_t bstrResults = spCalc->CalcPi();
  std::cout << "PI to " << spCalc->Digits << " digits is "
    << ( char * )bstrResults;
}

?

ICalcPiPtr 類(lèi)型是一種智能指針,它由 _com_ptr_t 類(lèi)用 typedef 定義得到。這個(gè)類(lèi)本身并不屬于 ATL ,而是直接屬于 COM 編譯器的擴(kuò)展部分,定義在系統(tǒng)的 comdef.h 頭文件中(封裝類(lèi)使用的一些其他類(lèi)型也同屬此文件)。智能指針自動(dòng)管理引用計(jì)數(shù), _bstr_t 類(lèi)型管理 BSTR 的內(nèi)存(第二章的“字符串和文本”討論)。

?

包裝類(lèi)中最值得注意的就是后面的 HRESULT 試驗(yàn)。作為替換,包裝類(lèi)把所有的 HRESULT 錯(cuò)誤都翻譯為 C++ 異常(更精確的 _com_error 類(lèi))。這樣就允許生成的代碼用方法的 [retval] 變量作為實(shí)際的返回值,排除了很多的臨時(shí)變量和輸出參數(shù)。

?

包裝類(lèi)可以大大的簡(jiǎn)化編寫(xiě) COM 客戶(hù)端,當(dāng)然他們也有缺點(diǎn)( downside )。最大的缺點(diǎn)是需要使用 C++ 異常。在一些工程中我們不愿意為使用異常處理而帶來(lái)的效率代價(jià),拋出異常就意味著要求開(kāi)發(fā)人員在安全處理異常時(shí)必須非常小心。

?

對(duì) ATL 開(kāi)發(fā)人員來(lái)說(shuō),包裝類(lèi)的另一個(gè)缺點(diǎn)是 ATL 對(duì) COM 接口(參考第三章“ ATL 智能類(lèi)型”)和 BSTR (參考第二章)。 ATL 包裝類(lèi)比 comdef.h 文件所定義的功能更好已是無(wú)可爭(zhēng)辯。比如,我們可以偶然地調(diào)用 ICalcPiPtr Release 方法,但是如果使用 ATL 包裝類(lèi),調(diào)用將產(chǎn)生編譯錯(cuò)誤。

?

默認(rèn)情況下,使用 #import 可以生成這些包裝類(lèi)。如果決定不使用它們,或者因?yàn)槟承┰虿荒芫幾g(我們已經(jīng)知道,在處理一些復(fù)雜、生疏的類(lèi)型庫(kù),至少有一個(gè)謙虛的程序員偶然遇到這種編譯問(wèn)題,),我們可以關(guān)閉這些包裝類(lèi),而使用 raw_interfaces_only 選項(xiàng)僅僅得到接口的直接定義。

?

1.12 ?ATL Server Web 工程

?

毫無(wú)疑問(wèn), ATL 庫(kù)最近所添加的最激動(dòng)人心的就是:一組稱(chēng)為術(shù)語(yǔ) ATL Server 的類(lèi)和工具集合。 ATL8.0 ATL3.0 大小增加近四倍,其中 ATL Server 占據(jù)了幾乎所有的增長(zhǎng)空間。這些擴(kuò)展類(lèi)庫(kù)對(duì)建立 WEB 應(yīng)用程序、 XML Web Servers 提供了非常全面的支持。雖然傳統(tǒng)的 ASP ASP.NET 平臺(tái)提供的基于 WEB 開(kāi)發(fā)的易用框架具有很強(qiáng)的吸引力,但是仍然有很多應(yīng)用程序開(kāi)發(fā)人員在編寫(xiě)應(yīng)用程序需要利用原始的 ISAPI 編程,以獲得最底層的控制和最大的效率。 ATL Server 設(shè)計(jì)用來(lái)提供和 ISAPI 相近的性能和控制力,以及和 ASP 一樣的生產(chǎn)力。最后, ATL Server 也采用之前的設(shè)計(jì)模式,它使得 ATL 開(kāi)發(fā)更方便,如過(guò)去一樣的高效:名字短小、快速、彈性的代碼。

?

VS 提供出色的向?qū)?lái)支持建立 WEB 應(yīng)用程序和服務(wù)。實(shí)際上,縱覽 ATL Server 工程提供的大量可用選項(xiàng),能幫助我們非常深刻的理解其結(jié)構(gòu),也是了解其支持提供功能的決好機(jī)會(huì)。 VS 提供了一個(gè)向?qū)椭覀冇?/span> ATL Server 建立 Web 應(yīng)用程序。從新建工程對(duì)話(huà)框的 Visual C++ 文件夾下選擇 ATL Server 工程可以打開(kāi)此向?qū)А?/span>

?

1-21 所示的工程設(shè)置頁(yè)顯示了生成、部署我們的 WEB 應(yīng)用程序所選項(xiàng)的選項(xiàng)。

?

1-21.JPG
1-21 ATL Server 工程的工程設(shè)置

?

默認(rèn)情況下, ATL Servre 在解決方案中生成兩個(gè)工程:一個(gè) Web 應(yīng)用程序 DLL 和一個(gè) ISAPI 擴(kuò)展 DLL 。 ISAPI 擴(kuò)展 DLL 被加載到 IIS 進(jìn)程中( inerinfo.exe ),邏輯結(jié)構(gòu)上位于 IIS Web 應(yīng)用程序 DLL 之間。盡管 ISAPI 擴(kuò)展可以自己處理 HTTP 請(qǐng)求,更普通的做法是讓其提供通用的基礎(chǔ)結(jié)構(gòu)服務(wù),比如線(xiàn)程池和緩沖,而讓 Web 應(yīng)用程序 DLL 提供真正的 HTTP 響應(yīng)邏輯。 ATL Server 工程向?qū)梢粋€(gè) ISAPI 擴(kuò)展實(shí)現(xiàn)了 Web 應(yīng)用程序調(diào)用處理函數(shù)中的特殊函數(shù)通信。圖 1-22 描述了這種關(guān)系。

?

1-22.JPG
1-22 基本的 ISAPI 結(jié)構(gòu)

?

在圖 1-21 的工程設(shè)置對(duì)話(huà)框中, Generate Combined DLL 選擇框允許我們把所有的內(nèi)容都合成到一個(gè) DLL 當(dāng)中。當(dāng) ISAPI 擴(kuò)展不打算在其他的 Web 應(yīng)用程序使用時(shí),選擇它比較合適。相反如果不選擇它,開(kāi)發(fā)人員就可以創(chuàng)建特殊的 ISAPI 擴(kuò)展,利用自定義線(xiàn)程池、高速的緩存調(diào)整機(jī)制,提高 ATL Server 的擴(kuò)展性特征。這些 ISAPI 擴(kuò)展很可能會(huì)在多個(gè) Web 應(yīng)用程序之間交互運(yùn)用。而且,讓 ISAPI 擴(kuò)展保存在單獨(dú)的 DLL 當(dāng)中,在我們向 Web 應(yīng)用程序添加處理函數(shù)的時(shí)候有更大的彈性,不需要重新啟動(dòng) Web 服務(wù)(稍后討論處理類(lèi))。在我們的第一個(gè) Web 應(yīng)用程序中沒(méi)有選中此項(xiàng),讓 VS 生成一個(gè)單獨(dú)的 DLL 。

?

Deployment Support 選擇框可以啟用 VS 網(wǎng)頁(yè)部署工具。選中此選項(xiàng)后, Visual Studio  編譯進(jìn)程會(huì)自動(dòng)執(zhí)行一些步驟,以適當(dāng)?shù)牟渴鹞覀兊?/span> WEB 應(yīng)用程序使它利用 IIS 提供的服務(wù)。稍后就會(huì)看到這種集成部署的功能使多么的方便,

?

1-23 所示的 Server Options 選項(xiàng)中,可以選擇各種 Web 應(yīng)用程序效率相關(guān)的選項(xiàng)。支持多種緩存類(lèi)型,包括支持任意的二進(jìn)制數(shù)據(jù)( Blob 緩存),文件緩存,數(shù)據(jù)庫(kù)連接緩存(數(shù)據(jù)源緩存)。此外,高效性站點(diǎn)是依賴(lài)于健壯的 Session 狀態(tài)管理。 ATL Server 提供了兩種機(jī)制持續(xù)化 Session 狀態(tài)。 OLE DB-backed session-state services 按鈕支持把 Session 狀態(tài)持續(xù)到數(shù)據(jù)庫(kù)(或者其他的 OLE DB 數(shù)據(jù)源),此選項(xiàng)對(duì)于運(yùn)行在 Web Farms 上的應(yīng)用程序非常有用。

?

1-23.JPG
1-23 ATL Server 工程的 Server Options 頁(yè)

?

1-24 顯示在 Application Options 頁(yè)可用的選擇項(xiàng)。 Validation Support 項(xiàng)生成一些代碼對(duì)客戶(hù)的 HTTP 請(qǐng)求的項(xiàng)目進(jìn)行驗(yàn)證,比如請(qǐng)求參數(shù)和表單變量。 Stencil Processing Support 生成框架代碼以使用稱(chēng)為服務(wù)響應(yīng)文件( Server response files , SRF )的 HTML 代碼模板。這些文本文件(也稱(chēng)為模板)以 .srf 為擴(kuò)展名,含有帶特殊替代標(biāo)簽的靜態(tài) HTML 內(nèi)容,這些內(nèi)容經(jīng)過(guò)我們的代碼處理后可以在運(yùn)行時(shí)生成動(dòng)態(tài)內(nèi)容。啟用 Stencil Processin 后,向?qū)г试S我們選擇響應(yīng)的適當(dāng)?shù)攸c(diǎn)和代碼頁(yè)。 Create as Web Service 會(huì)在后續(xù)章節(jié)做進(jìn)一步的討論。因?yàn)槲覀儸F(xiàn)在開(kāi)發(fā)的是 Web 應(yīng)用程序,現(xiàn)在我們不選擇此項(xiàng)。

?

1-24.JPG
1-24? ATL Server Application Options 頁(yè)

?

ATL Server 工程中可以設(shè)置的其他項(xiàng)都在 Developer Support Options 頁(yè),如圖 1-25 所示。 Generating TODO comments 簡(jiǎn)單的提醒開(kāi)發(fā)人員注意附加實(shí)現(xiàn)應(yīng)該提供的區(qū)域。如果我們選中 Custom Assert and Trace Handling Support ,調(diào)試編譯時(shí)會(huì)包含一個(gè) CDebugReportHook 類(lèi)的實(shí)例,它能大大的簡(jiǎn)化從遠(yuǎn)程機(jī)器上調(diào)試 Web 應(yīng)用程序的過(guò)程。

?

1-25.JPG
1-25? ATL Server Developer Support Options 頁(yè)

?

點(diǎn)擊圖 1 25 Finish 按鈕,向?qū)?huì)生成一個(gè)解決方案,其中包含兩個(gè)工程:一個(gè)是 Web 應(yīng)用程序 DLL (名稱(chēng)與我們?cè)?/span> New Project 對(duì)話(huà)框中輸入的工程名一樣);一個(gè)是 ISAPI 擴(kuò)展(名稱(chēng)是工程名加上 Isapi )。我們先看看在 ISAPI 擴(kuò)展工程中生成的代碼。生成的 ISAPI 擴(kuò)展 .cpp 文件內(nèi)容如下:

?

class CPiSvrWebAppModule :

public CAtlDllModuleT<CPiSvrWebAppModule> {

public:

};

?

CPiSvrWebAppModule _AtlModule;

?

typedef CIsapiExtension<> ExtensionType;

?

// The ATL Server ISAPI extension

ExtensionType theExtension;

?

// Delegate ISAPI exports to theExtension

extern "C"

DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) {

??? return theExtension.HttpExtensionProc(lpECB);

}

?

extern "C"

BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO* pVer) {

??? return theExtension.GetExtensionVersion(pVer);

}

?

extern "C" BOOL WINAPI TerminateExtension(DWORD dwFlags) {

??? return theExtension.TerminateExtension(dwFlags);

}

?

// DLL Entry Point

extern "C"

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason,

??? LPVOID lpReserved) {

??? hInstance;

??? return _AtlModule.DllMain(dwReason, lpReserved);

}

?

因?yàn)?/span> ISAPI 擴(kuò)展使用了 ATL 的對(duì)象創(chuàng)建功能,它也需要一個(gè) ATL 模塊對(duì)象。同樣,在其生成的代碼中也實(shí)現(xiàn)了三個(gè)非常有名的入口點(diǎn): HttpExtensionProc , GetExtensionVersion TerminateExtension 。 IIS 正是用它們與 ISAPI 擴(kuò)展進(jìn)行通信,處理 HTTP 請(qǐng)求信息。這些實(shí)現(xiàn)都被簡(jiǎn)單的委派到 CIsapiExtension 的全局實(shí)例,其定義如下:

?

template <????????????????????????????????????????? ??

? class ThreadPoolClass=CThreadPool<CIsapiWorker>,???? ??

? class CRequestStatClass=CNoRequestStats,???????????? ??

? class HttpUserErrorTextProvider=CDefaultErrorProvider,??????

? class WorkerThreadTraits=DefaultThreadTraits,???????? ???

? class CPageCacheStats=CNoStatClass,??????????????????

? class CStencilCacheStats=CNoStatClass?????????? ??????

>?????????????????????????????????????????????????? ???????????????

class CIsapiExtension :????????????????????????????????

? public IServiceProvider,????????????????????????????? ?

? public IIsapiExtension,????????????????????????????? ??

? public IRequestStats????????????????????????????????

{... }>?????????????????????? ????????????????????????

?

此類(lèi)提供了實(shí)現(xiàn) ISAPI 擴(kuò)展的樣板函數(shù)。類(lèi)中的模板參數(shù)提供了某些功能的插件實(shí)現(xiàn),比如線(xiàn)程池管理、錯(cuò)誤報(bào)告和靜態(tài)緩沖。在類(lèi)的 .CPP 文件中,替換為我們自己從 CIsapiExtension 派生的類(lèi)作為模板參數(shù),這樣就可以高度自定義 ISAPI 擴(kuò)展的行為。具體的實(shí)現(xiàn)技術(shù)在第十三章“你好, ATL Server ”講述。 ISAPI 擴(kuò)展的默認(rèn)實(shí)現(xiàn)對(duì)現(xiàn)在的演示目的已經(jīng)比較適用。

?

大多數(shù)的編碼都是在 Web 應(yīng)用程序工程中進(jìn)行的。向?qū)槲覀兩梢粋€(gè) SRF 文件框架并加入到工程中。集成到 VS 中的 HTML 編輯器使我們能非常方便的查看、操縱文件內(nèi)容。


<html>
{{ handler PiSvrWebApp.dll/Default }}
??? <head>
??? </head>
??? <body>
??????? This is a test: {{Hello}}<br>
??? </body>
</html>
?

在雙大括號(hào)之間的命令項(xiàng)將被傳遞給模板處理器。 {{handler}} 命令指定了響應(yīng)類(lèi)的宿主 DLL 名稱(chēng),而類(lèi)用來(lái)處理出現(xiàn)在 SRF 文件標(biāo)簽替換。其中的 /Default 參數(shù)能確保在處理標(biāo)簽替換時(shí)使用默認(rèn)的請(qǐng)求處理類(lèi)。一般來(lái)說(shuō),應(yīng)用程序 DLL 可以包含多個(gè)處理 SRF 命令的處理類(lèi),甚至這些類(lèi)可以存在于多個(gè) DLL 中。我們?cè)趩蝹€(gè)的 DLL 中僅僅使用一個(gè)處理類(lèi),因此流向處理類(lèi)的所有命令都將被路由到同一處理類(lèi)。在早期向?qū)傻目蚣苤校?/span> {{Hello}} 標(biāo)簽將傳遞到一個(gè)處理類(lèi),被類(lèi)實(shí)現(xiàn)方法中生成的 HTML 所替換。

?

在我們的應(yīng)用程序 DLL 中, ATL Server 通過(guò)幾個(gè)宏把 SRF 文件的命名映射到處理類(lèi)。向?qū)傻?/span> <projectname>.h 定義中,說(shuō)明了這些宏是怎樣使用的:

?

class CPiSvrWebAppHandler
??? : public CRequestHandlerT<CPiSvrWebAppHandler>
{
public:
??? BEGIN_REPLACEMENT_METHOD_MAP(CPiSvrWebAppHandler)
??????? REPLACEMENT_METHOD_ENTRY("Hello", OnHello)
??? END_REPLACEMENT_METHOD_MAP()

??? HTTP_CODE ValidateAndExchange() {
??????? // Set the content-type
??????? m_HttpResponse.SetContentType("text/html");
??????? return HTTP_SUCCESS;
??? }

protected:
??? HTTP_CODE OnHello(void) {
??????? m_HttpResponse << "Hello World!";
??????? return HTTP_SUCCESS;
??? }
};

基類(lèi)
CRequestHandlerT 提供了一個(gè)請(qǐng)求處理類(lèi)的實(shí)現(xiàn)。用 REPLACEMENT_METHOD_MAP SRF 文件中的字符串映射到中適當(dāng)?shù)奶幚砗瘮?shù)。

在處理器
DLL .CPP 文件,除了請(qǐng)求處理類(lèi)本身,還有一些其他分全局宏:

BEGIN_HANDLER_MAP()
??? HANDLER_ENTRY("Default", CPiSvrWebAppHandler)
END_HANDLER_MAP()

HANDLER_MAP
宏被用來(lái)判斷使用哪個(gè)類(lèi)處理帶特殊名稱(chēng)的替換。在這種情況下, ”Default” 字符串,同 SRF 文件中的處理標(biāo)簽一樣,被映射到 CPiSvrWebAppHandler 類(lèi)。當(dāng)在 SRF 文件中遇到 {{Hello}} 標(biāo)簽時(shí), OnHello 方法被調(diào)用(通過(guò) REPLACEMENT_METHOD_MAP )。它用聲明在 CRequestHandlerT 中的一個(gè) CHttpReponse 成員變量實(shí)例去生成標(biāo)簽的替換代碼。

讓我們修改向?qū)傻拇a,以根據(jù)
HTTP 請(qǐng)求字符串中指定的小數(shù)位數(shù)顯示 PI 結(jié)果。首先,把 SRF 文件按照如下修改:

<html>
{{ handler PiSvrWebApp.dll/Default }}
??? <head>
??? </head>
??? <body>
??????? PI = {{Pi}}<br>
??? </body>
</html>

然后,我們添加一個(gè)稱(chēng)為
OnPi 的替換方法到處理類(lèi),再用 [tag_name] 屬性把此方法與 {{Pi}} 替換標(biāo)簽關(guān)聯(lián)起來(lái)。在 OnPi 方法的實(shí)現(xiàn)中,我們從查詢(xún)字符串取得請(qǐng)求的小數(shù)位數(shù)。存儲(chǔ)在 m_HttpRequest 成員變量中的 CHttpRequest 類(lèi)暴露一個(gè) CHttpRequestParams 實(shí)例。此類(lèi)提供一個(gè)簡(jiǎn)單的 Lookup 方法從查詢(xún)字符串取得單獨(dú)的查詢(xún)參數(shù),作為名稱(chēng)值對(duì)。因此處理類(lèi)似下面的請(qǐng)求就非常簡(jiǎn)單:


http://localhost/PiSvrWebApp/PiSvrWebApp.srf?digits=6

當(dāng)我們編譯解決方案時(shí),
VS 根據(jù)我們的行為執(zhí)行一些方便的任務(wù)。因此它是 Web 應(yīng)用程序,不能簡(jiǎn)單的把代碼編譯入 DLL 就算結(jié)束。應(yīng)用程序必須被適當(dāng)?shù)牟渴鸬?/span> Web 服務(wù)器上,并在 IIS 注冊(cè)。我們需要?jiǎng)?chuàng)建一個(gè)虛擬目錄,指定一個(gè)合適的隔離處理級(jí)別,把 .srf 后綴的文件映射到我們的 ISAPI 擴(kuò)展 DLL ?;叵胍幌拢瑒?chuàng)建工程的時(shí)候,我們?cè)?/span> ATL Server 工程向?qū)У?/span> Project Settings 頁(yè)選擇了 deployment support 項(xiàng),參考前圖 1-21 。因此, VS 會(huì)自動(dòng)調(diào)用工具 VCDeploy.exe 為我們執(zhí)行所有的部署步驟。簡(jiǎn)單的用普通方式編譯解決方案,把我們的應(yīng)用程序 DLL ISAPI 擴(kuò)展 DLL 、 SRF 文件都放到默認(rèn) Web 站點(diǎn)下的一個(gè)目錄。通常是位于目錄 <drive>:\inetpub\wwwroot\<projectName> VS 使用我們的 Web 應(yīng)用程序工程名稱(chēng)作為虛擬目錄名稱(chēng),因此瀏覽 http://localhost/PiSvrWebApp/PiSvrWebApp.srf?digits=50將產(chǎn)生圖1-26 所示的結(jié)果:

?

1-26.JPG
1-26 顯示 PI 50 小數(shù)的 Web 應(yīng)用程序

?

關(guān)于用 ATL Server 建立 ISAPI 應(yīng)用程序,包括 Web Services 的更多信息,請(qǐng)參考第十三章“你好 , ATL Server ”。

?

1.13 ? 總結(jié)

?

在本章,我們?nèi)胄L(fēng)般的瀏覽了 ATL 向?qū)岣叩囊恍┕δ埽ㄒ恍┗镜慕涌趯?shí)現(xiàn)。即使有豐富的向?qū)Чδ埽?/span> ATL 也不是牢固的 COM 知識(shí)的替代品,這一點(diǎn)勿庸置疑。我們?nèi)孕枰莆杖绾卧O(shè)計(jì)、實(shí)現(xiàn)自定義接口。在本書(shū)的剩余部分你將看到,我們?nèi)孕枰煜そ涌谥羔?、引用?jì)數(shù)、運(yùn)行時(shí)類(lèi)型發(fā)現(xiàn)、線(xiàn)程、持續(xù)化等等。 ATL 能幫助我們,當(dāng)我們?nèi)孕枰煜?/span> COM

?

我們必須知道:向?qū)Р⒉荒苁刮覀冇H密接觸 ATL 或者 Web 應(yīng)用程序開(kāi)發(fā)。在本章看到的 ATL 信息的精選功能,都有不止 10 個(gè)突出的細(xì)節(jié)、擴(kuò)展和缺點(diǎn)。盡管向?qū)Э梢怨?jié)省我們很多時(shí)間,它并不能完成所有的工作。它不能確保設(shè)計(jì)和實(shí)現(xiàn)目標(biāo)滿(mǎn)足我們的要求,那是我們的職責(zé)。