1.11
?
容納控件
?
1.11.1?????
容納控件
利用
ATL
所支持的控件容納,可實現(xiàn)容納控件。比如,
CAxDialogImpl
中的
Ax
兩字就表示
ActiveX
控件,表示對話框具有容納控件的能力。在對話框中實現(xiàn)容納控件,只需在對話框資源上點擊右鍵,從彈出菜單選擇
Insert ActiveX Control
,然后彈出一個對話框,列舉了系統(tǒng)安裝的所有控件,如圖
1-17
所示。
?
圖
1-17 ?
插入
ActiveX
控件對話框
?
插入控件后,點擊控件可以在控件的屬性窗口設(shè)置控件的屬性。如圖
1-18
所示。
?
圖
1-18
控件屬性對話框
?
在屬性對話框的工具欄上點擊控件事件按鈕,還可以選擇處理控件的事件,如圖
1-19
所示。
?
圖
1-19
選擇處理的控件事件
?
容納對話框運行顯示時,控件被創(chuàng)建,同時根據(jù)開發(fā)階段設(shè)置的屬性初始化控件。圖
1-20
顯示了容納了一個控件的對話框。
?
圖
1-20
容納
COM
控件的對話框
?
ATL
不但提供了對話框的容納控件功能,其他窗口也同樣支持:聲明為對話框資源的
UI
控件(稱為復(fù)合控件);聲明為
HTML
資源的
UI
控件(稱為
HTML
控件)。關(guān)于控件容器的更多信息請參考第十二章“控件容器”。
?
1.11.2 C++ COM
客戶端
?
至少在理論上,
COM
與
C++
是一致的。一個
COM
接口直接映射為一個
C++
的抽象類。使用
COM
對象,僅僅需要使用
MIDL
編譯器運行
IDL
文件,就可以生成一個頭文件,里面包含有所有需要的信息。
?
所有的這一切都運行正常,直到
VB
團隊詢問他們也是否可以使用
COM
技術(shù)。
?
VB
開發(fā)人員通常不知道,也不想知道
C++
語言。
IDL
也是一個與
C++
傳統(tǒng)語言相似的語言,其中也支持許多
C/C++
的特性(比如數(shù)組和指針)。
VB
需要一種方法來存儲這些
COM
對象的類型信息,以方便
VB
開發(fā)人員使用和理解它們。
?
因此類型庫誕生了(也稱為
typelib
)。類型庫存儲
COM
對象的信息:對象支持的接口
classid
;接口的方法;
IDL
文件中看到的所有信息,等等
(
除了一些不合宜的、大部分必須等同
C
數(shù)組處理內(nèi)容
)
。
COM
系統(tǒng)包含一系列可以根據(jù)
typelib
內(nèi)容編程訪問的
COM
對象。最好的就是類型庫可以直接嵌入到
DLL
或者
EXE
,因此不必擔心類型庫信息的丟失。
?
現(xiàn)在,當一些
COM
組件沒有打包
IDL
文件時,類型庫對
VB
開發(fā)人員具有非常的意義;類型庫包含有使用組件需要的所有信息。現(xiàn)在只缺少一樣:如何在
C++
語言中使用類型庫?
?
C++
語言并不能理解類型庫,它需要頭文件。這就引發(fā)了一系列的問題。從
Visual Studio 6
開始,微軟擴展了編譯器,使你可以像使用頭文件一樣使用類型庫。這種擴展使通過語句
#import
實現(xiàn)的。
?
#import
可以像
#include
一樣使用,一般使用形式如下:
?
#import “pisvr.dll” <options>
?
#import
語句根據(jù)選項的不同,生成一個或者兩個
C++
頭文件。這些頭文件的擴展名是
.tlh
(用于類型庫頭文件)和
.tli
(用于類型庫內(nèi)聯(lián))。都生成在工程的輸出目錄(
debug
版默認在
Debug
目錄,
release
版默認在
Release
目錄)。
?
#import
語句提供了很多的選項來控制生成的文件內(nèi)容。可以在
Visual Studio
文檔中查看所有的選項列表。此處只介紹一些比較常用的控制項。
?
選項
no_namespace
告訴編譯器我們不希望生成的文件內(nèi)容放入一個
C++
名字空間內(nèi)。默認情況下,生成文件的內(nèi)容被放入按類型庫命名的
C++
名字空間內(nèi)。
?
選項
name_guids
告訴編譯器我們希望類型庫中的
GUID
都有一個命名符號。默認情況下,因為名字
CLSID_PISvr
沒有定義,下面的語句不能被編譯:
?
::CoCreateInstance( CLSID_PISvr, … );
?
相反,應(yīng)該使用下面的語句形式:
?
::CoCreateInstance( __uuidof ( PISvr), … );
?
我們同樣需要使用
__uuidof()
來獲取接口的
IID
。
?
選項
raw_interfaces_only
應(yīng)該是最復(fù)雜的。默認情況下,當
#import
生成頭文件時,它不僅僅是生成接口類定義。實際上,生成包裝類使得
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);
};
通常情況下,可以如下使用這個接口:
?
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
語句,可以如下使用接口:
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
類型是一種智能指針,它由
_com_ptr_t
類用
typedef
定義得到。這個類本身并不屬于
ATL
,而是直接屬于
COM
編譯器的擴展部分,定義在系統(tǒng)的
comdef.h
頭文件中(封裝類使用的一些其他類型也同屬此文件)。智能指針自動管理引用計數(shù),
_bstr_t
類型管理
BSTR
的內(nèi)存(第二章的“字符串和文本”討論)。
?
包裝類中最值得注意的就是后面的
HRESULT
試驗。作為替換,包裝類把所有的
HRESULT
錯誤都翻譯為
C++
異常(更精確的
_com_error
類)。這樣就允許生成的代碼用方法的
[retval]
變量作為實際的返回值,排除了很多的臨時變量和輸出參數(shù)。
?
包裝類可以大大的簡化編寫
COM
客戶端,當然他們也有缺點(
downside
)。最大的缺點是需要使用
C++
異常。在一些工程中我們不愿意為使用異常處理而帶來的效率代價,拋出異常就意味著要求開發(fā)人員在安全處理異常時必須非常小心。
?
對
ATL
開發(fā)人員來說,包裝類的另一個缺點是
ATL
對
COM
接口(參考第三章“
ATL
智能類型”)和
BSTR
(參考第二章)。
ATL
包裝類比
comdef.h
文件所定義的功能更好已是無可爭辯。比如,我們可以偶然地調(diào)用
ICalcPiPtr
的
Release
方法,但是如果使用
ATL
包裝類,調(diào)用將產(chǎn)生編譯錯誤。
?
默認情況下,使用
#import
可以生成這些包裝類。如果決定不使用它們,或者因為某些原因不能編譯(我們已經(jīng)知道,在處理一些復(fù)雜、生疏的類型庫,至少有一個謙虛的程序員偶然遇到這種編譯問題,),我們可以關(guān)閉這些包裝類,而使用
raw_interfaces_only
選項僅僅得到接口的直接定義。
?
1.12
?ATL Server
的
Web
工程
?
毫無疑問,
ATL
庫最近所添加的最激動人心的就是:一組稱為術(shù)語
ATL Server
的類和工具集合。
ATL8.0
比
ATL3.0
大小增加近四倍,其中
ATL Server
占據(jù)了幾乎所有的增長空間。這些擴展類庫對建立
WEB
應(yīng)用程序、
XML Web Servers
提供了非常全面的支持。雖然傳統(tǒng)的
ASP
和
ASP.NET
平臺提供的基于
WEB
開發(fā)的易用框架具有很強的吸引力,但是仍然有很多應(yīng)用程序開發(fā)人員在編寫應(yīng)用程序需要利用原始的
ISAPI
編程,以獲得最底層的控制和最大的效率。
ATL Server
設(shè)計用來提供和
ISAPI
相近的性能和控制力,以及和
ASP
一樣的生產(chǎn)力。最后,
ATL Server
也采用之前的設(shè)計模式,它使得
ATL
開發(fā)更方便,如過去一樣的高效:名字短小、快速、彈性的代碼。
?
VS
提供出色的向?qū)碇С纸?/span>
WEB
應(yīng)用程序和服務(wù)。實際上,縱覽
ATL Server
工程提供的大量可用選項,能幫助我們非常深刻的理解其結(jié)構(gòu),也是了解其支持提供功能的決好機會。
VS
提供了一個向?qū)椭覀冇?/span>
ATL Server
建立
Web
應(yīng)用程序。從新建工程對話框的
Visual C++
文件夾下選擇
ATL Server
工程可以打開此向?qū)А?/span>
?
圖
1-21
所示的工程設(shè)置頁顯示了生成、部署我們的
WEB
應(yīng)用程序所選項的選項。
?
圖
1-21 ATL Server
工程的工程設(shè)置
?
默認情況下,
ATL Servre
在解決方案中生成兩個工程:一個
Web
應(yīng)用程序
DLL
和一個
ISAPI
擴展
DLL
。
ISAPI
擴展
DLL
被加載到
IIS
進程中(
inerinfo.exe
),邏輯結(jié)構(gòu)上位于
IIS
和
Web
應(yīng)用程序
DLL
之間。盡管
ISAPI
擴展可以自己處理
HTTP
請求,更普通的做法是讓其提供通用的基礎(chǔ)結(jié)構(gòu)服務(wù),比如線程池和緩沖,而讓
Web
應(yīng)用程序
DLL
提供真正的
HTTP
響應(yīng)邏輯。
ATL Server
工程向?qū)梢粋€
ISAPI
擴展實現(xiàn)了
Web
應(yīng)用程序調(diào)用處理函數(shù)中的特殊函數(shù)通信。圖
1-22
描述了這種關(guān)系。
?
圖
1-22
基本的
ISAPI
結(jié)構(gòu)
?
在圖
1-21
的工程設(shè)置對話框中,
Generate Combined DLL
選擇框允許我們把所有的內(nèi)容都合成到一個
DLL
當中。當
ISAPI
擴展不打算在其他的
Web
應(yīng)用程序使用時,選擇它比較合適。相反如果不選擇它,開發(fā)人員就可以創(chuàng)建特殊的
ISAPI
擴展,利用自定義線程池、高速的緩存調(diào)整機制,提高
ATL Server
的擴展性特征。這些
ISAPI
擴展很可能會在多個
Web
應(yīng)用程序之間交互運用。而且,讓
ISAPI
擴展保存在單獨的
DLL
當中,在我們向
Web
應(yīng)用程序添加處理函數(shù)的時候有更大的彈性,不需要重新啟動
Web
服務(wù)(稍后討論處理類)。在我們的第一個
Web
應(yīng)用程序中沒有選中此項,讓
VS
生成一個單獨的
DLL
。
?
Deployment Support
選擇框可以啟用
VS
網(wǎng)頁部署工具。選中此選項后,
Visual Studio
編譯進程會自動執(zhí)行一些步驟,以適當?shù)牟渴鹞覀兊?/span>
WEB
應(yīng)用程序使它利用
IIS
提供的服務(wù)。稍后就會看到這種集成部署的功能使多么的方便,
?
圖
1-23
所示的
Server Options
選項中,可以選擇各種
Web
應(yīng)用程序效率相關(guān)的選項。支持多種緩存類型,包括支持任意的二進制數(shù)據(jù)(
Blob
緩存),文件緩存,數(shù)據(jù)庫連接緩存(數(shù)據(jù)源緩存)。此外,高效性站點是依賴于健壯的
Session
狀態(tài)管理。
ATL Server
提供了兩種機制持續(xù)化
Session
狀態(tài)。
OLE DB-backed session-state services
按鈕支持把
Session
狀態(tài)持續(xù)到數(shù)據(jù)庫(或者其他的
OLE DB
數(shù)據(jù)源),此選項對于運行在
Web Farms
上的應(yīng)用程序非常有用。
?
圖
1-23 ATL Server
工程的
Server Options
頁
?
圖
1-24
顯示在
Application Options
頁可用的選擇項。
Validation Support
項生成一些代碼對客戶的
HTTP
請求的項目進行驗證,比如請求參數(shù)和表單變量。
Stencil Processing Support
生成框架代碼以使用稱為服務(wù)響應(yīng)文件(
Server response files
,
SRF
)的
HTML
代碼模板。這些文本文件(也稱為模板)以
.srf
為擴展名,含有帶特殊替代標簽的靜態(tài)
HTML
內(nèi)容,這些內(nèi)容經(jīng)過我們的代碼處理后可以在運行時生成動態(tài)內(nèi)容。啟用
Stencil Processin
后,向?qū)г试S我們選擇響應(yīng)的適當?shù)攸c和代碼頁。
Create as Web Service
會在后續(xù)章節(jié)做進一步的討論。因為我們現(xiàn)在開發(fā)的是
Web
應(yīng)用程序,現(xiàn)在我們不選擇此項。
?
圖
1-24? ATL Server
的
Application Options
頁
?
ATL Server
工程中可以設(shè)置的其他項都在
Developer Support Options
頁,如圖
1-25
所示。
Generating TODO comments
簡單的提醒開發(fā)人員注意附加實現(xiàn)應(yīng)該提供的區(qū)域。如果我們選中
Custom Assert and Trace Handling Support
,調(diào)試編譯時會包含一個
CDebugReportHook
類的實例,它能大大的簡化從遠程機器上調(diào)試
Web
應(yīng)用程序的過程。
?
圖
1-25? ATL Server
的
Developer Support Options
頁
?
點擊圖
1
-
25
的
Finish
按鈕,向?qū)梢粋€解決方案,其中包含兩個工程:一個是
Web
應(yīng)用程序
DLL
(名稱與我們在
New Project
對話框中輸入的工程名一樣);一個是
ISAPI
擴展(名稱是工程名加上
Isapi
)。我們先看看在
ISAPI
擴展工程中生成的代碼。生成的
ISAPI
擴展
.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);
}
?
因為
ISAPI
擴展使用了
ATL
的對象創(chuàng)建功能,它也需要一個
ATL
模塊對象。同樣,在其生成的代碼中也實現(xiàn)了三個非常有名的入口點:
HttpExtensionProc
,
GetExtensionVersion
和
TerminateExtension
。
IIS
正是用它們與
ISAPI
擴展進行通信,處理
HTTP
請求信息。這些實現(xiàn)都被簡單的委派到
CIsapiExtension
的全局實例,其定義如下:
?
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????????????????????????????????
{... }>?????????????????????? ????????????????????????
?
此類提供了實現(xiàn)
ISAPI
擴展的樣板函數(shù)。類中的模板參數(shù)提供了某些功能的插件實現(xiàn),比如線程池管理、錯誤報告和靜態(tài)緩沖。在類的
.CPP
文件中,替換為我們自己從
CIsapiExtension
派生的類作為模板參數(shù),這樣就可以高度自定義
ISAPI
擴展的行為。具體的實現(xiàn)技術(shù)在第十三章“你好,
ATL Server
”講述。
ISAPI
擴展的默認實現(xiàn)對現(xiàn)在的演示目的已經(jīng)比較適用。
?
大多數(shù)的編碼都是在
Web
應(yīng)用程序工程中進行的。向?qū)槲覀兩梢粋€
SRF
文件框架并加入到工程中。集成到
VS
中的
HTML
編輯器使我們能非常方便的查看、操縱文件內(nèi)容。
<html>
{{ handler PiSvrWebApp.dll/Default }}
??? <head>
??? </head>
??? <body>
??????? This is a test: {{Hello}}<br>
??? </body>
</html>
?
在雙大括號之間的命令項將被傳遞給模板處理器。
{{handler}}
命令指定了響應(yīng)類的宿主
DLL
名稱,而類用來處理出現(xiàn)在
SRF
文件標簽替換。其中的
/Default
參數(shù)能確保在處理標簽替換時使用默認的請求處理類。一般來說,應(yīng)用程序
DLL
可以包含多個處理
SRF
命令的處理類,甚至這些類可以存在于多個
DLL
中。我們在單個的
DLL
中僅僅使用一個處理類,因此流向處理類的所有命令都將被路由到同一處理類。在早期向?qū)傻目蚣苤校?/span>
{{Hello}}
標簽將傳遞到一個處理類,被類實現(xiàn)方法中生成的
HTML
所替換。
?
在我們的應(yīng)用程序
DLL
中,
ATL Server
通過幾個宏把
SRF
文件的命名映射到處理類。向?qū)傻?/span>
<projectname>.h
定義中,說明了這些宏是怎樣使用的:
?
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;
??? }
};
基類
CRequestHandlerT
提供了一個請求處理類的實現(xiàn)。用
REPLACEMENT_METHOD_MAP
把
SRF
文件中的字符串映射到中適當?shù)奶幚砗瘮?shù)。
在處理器
DLL
的
.CPP
文件,除了請求處理類本身,還有一些其他分全局宏:
BEGIN_HANDLER_MAP()
??? HANDLER_ENTRY("Default", CPiSvrWebAppHandler)
END_HANDLER_MAP()
HANDLER_MAP
宏被用來判斷使用哪個類處理帶特殊名稱的替換。在這種情況下,
”Default”
字符串,同
SRF
文件中的處理標簽一樣,被映射到
CPiSvrWebAppHandler
類。當在
SRF
文件中遇到
{{Hello}}
標簽時,
OnHello
方法被調(diào)用(通過
REPLACEMENT_METHOD_MAP
)。它用聲明在
CRequestHandlerT
中的一個
CHttpReponse
成員變量實例去生成標簽的替換代碼。
讓我們修改向?qū)傻拇a,以根據(jù)
HTTP
請求字符串中指定的小數(shù)位數(shù)顯示
PI
結(jié)果。首先,把
SRF
文件按照如下修改:
<html>
{{ handler PiSvrWebApp.dll/Default }}
??? <head>
??? </head>
??? <body>
??????? PI = {{Pi}}<br>
??? </body>
</html>
然后,我們添加一個稱為
OnPi
的替換方法到處理類,再用
[tag_name]
屬性把此方法與
{{Pi}}
替換標簽關(guān)聯(lián)起來。在
OnPi
方法的實現(xiàn)中,我們從查詢字符串取得請求的小數(shù)位數(shù)。存儲在
m_HttpRequest
成員變量中的
CHttpRequest
類暴露一個
CHttpRequestParams
實例。此類提供一個簡單的
Lookup
方法從查詢字符串取得單獨的查詢參數(shù),作為名稱值對。因此處理類似下面的請求就非常簡單:
http://localhost/PiSvrWebApp/PiSvrWebApp.srf?digits=6
當我們編譯解決方案時,
VS
根據(jù)我們的行為執(zhí)行一些方便的任務(wù)。因此它是
Web
應(yīng)用程序,不能簡單的把代碼編譯入
DLL
就算結(jié)束。應(yīng)用程序必須被適當?shù)牟渴鸬?/span>
Web
服務(wù)器上,并在
IIS
注冊。我們需要創(chuàng)建一個虛擬目錄,指定一個合適的隔離處理級別,把
.srf
后綴的文件映射到我們的
ISAPI
擴展
DLL
。回想一下,創(chuàng)建工程的時候,我們在
ATL Server
工程向?qū)У?/span>
Project Settings
頁選擇了
deployment support
項,參考前圖
1-21
。因此,
VS
會自動調(diào)用工具
VCDeploy.exe
為我們執(zhí)行所有的部署步驟。簡單的用普通方式編譯解決方案,把我們的應(yīng)用程序
DLL
、
ISAPI
擴展
DLL
、
SRF
文件都放到默認
Web
站點下的一個目錄。通常是位于目錄
<drive>:\inetpub\wwwroot\<projectName>
。
VS
使用我們的
Web
應(yī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
的更多信息,請參考第十三章“你好
, ATL Server
”。
?
1.13
?
總結(jié)
?
在本章,我們?nèi)胄L般的瀏覽了
ATL
向?qū)岣叩囊恍┕δ埽ㄒ恍┗镜慕涌趯崿F(xiàn)。即使有豐富的向?qū)Чδ埽?/span>
ATL
也不是牢固的
COM
知識的替代品,這一點勿庸置疑。我們?nèi)孕枰莆杖绾卧O(shè)計、實現(xiàn)自定義接口。在本書的剩余部分你將看到,我們?nèi)孕枰煜そ涌谥羔槨⒁糜嫈?shù)、運行時類型發(fā)現(xiàn)、線程、持續(xù)化等等。
ATL
能幫助我們,當我們?nèi)孕枰煜?/span>
COM
。
?
我們必須知道:向?qū)Р⒉荒苁刮覀冇H密接觸
ATL
或者
Web
應(yīng)用程序開發(fā)。在本章看到的
ATL
信息的精選功能,都有不止
10
個突出的細節(jié)、擴展和缺點。盡管向?qū)Э梢怨?jié)省我們很多時間,它并不能完成所有的工作。它不能確保設(shè)計和實現(xiàn)目標滿足我們的要求,那是我們的職責。