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 ?
插入
ActiveX
控件對(duì)話(huà)框
?
插入控件后,點(diǎn)擊控件可以在控件的屬性窗口設(shè)置控件的屬性。如圖
1-18
所示。
?
圖
1-18
控件屬性對(duì)話(huà)框
?
在屬性對(duì)話(huà)框的工具欄上點(diǎn)擊控件事件按鈕,還可以選擇處理控件的事件,如圖
1-19
所示。
?
圖
1-19
選擇處理的控件事件
?
容納對(duì)話(huà)框運(yùn)行顯示時(shí),控件被創(chuàng)建,同時(shí)根據(jù)開(kāi)發(fā)階段設(shè)置的屬性初始化控件。圖
1-20
顯示了容納了一個(gè)控件的對(duì)話(huà)框。
?
圖
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 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
基本的
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 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? 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? 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
顯示
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é)。