逐步解說:使用機器碼建立 Request-Level HTTP 模組
本逐步解說示範如何使用 C++ 來建立範例要求層級 HTTP 模組,以在 IIS 7 中實作新的要求處理架構。 當您在舊版 ASP.NET HTTP 模組和 ISAPI 篩選器或延伸模組上撰寫 IIS 應用程式時,這個新架構會擴充原生程式碼程式設計的功能。 如需使用新要求處理架構設計 HTTP 模組的詳細資訊,請參閱 設計Native-Code HTTP 模組。
在本逐步解說中,您將為 HTTP 模組建立 C++ 專案、新增 「Hello World」 專案所需的程式碼,然後編譯及測試模組。
必要條件
需要下列軟體才能完成範例中的步驟:
IIS 7。
Visual Studio 2005。
Windows 軟體發展工具組 (SDK) 。
注意 您可以使用 Visual Studio .NET 2003 或更早版本,雖然逐步解說步驟可能不相同。
建立模組
在本逐步解說的這個部分中,您將為 HTTP 模組建立空的 C++ DLL 專案。
若要建立新的 C++ DLL 專案
開啟 Visual Studio 2005。
確認全域選項具有 SDK 包含檔案的所有正確路徑:
在 [工具] 功能表上,按一下 [選項] 。
展開樹狀檢視中的 [ 專案和方案 ] 節點,然後按一下 [VC++ 目錄]。
在 [ 顯示目錄的 下拉式方塊] 中,選取 [包含檔案]。
確認您安裝 Windows SDK 包含檔案的路徑已列出。 如果未列出路徑,請按一下 [ 新增行 ] 圖示,然後新增您安裝 SDK 包含檔案的路徑。 預設安裝目錄為 $ (VCInstallDir) PlatformSDK\bin。
按一下 [確定]。
建立新的 C++ 專案:
在 [檔案] 功能表上,指向 [開新檔案] ,然後按一下 [專案] 。
此時會開啟 [新增專案] 對話方塊。
在 [ 專案類型] 窗格中,展開 [Visual C++ ] 節點,然後按一下 [ Win32]。
在 [ 範本] 窗格中,選取 [Win32 專案]。
在 [ 名稱] 方塊中,輸入 HelloWorld。
在 [ 位置] 方塊中,輸入範例的路徑。
按一下 [確定]。
Win32 應用程式精靈隨即開啟。
按一下 [應用程式設定]。
在 [應用程式類型]下,按一下 [DLL]。
在 [其他選項] 下,按一下 [ 空白專案]。
按一下 [完成] 。
新增程式碼和原始程式檔
下一個步驟是將必要的 C++ 和模組定義檔案新增至專案。
將來源檔案新增至專案
建立模組定義檔案以匯出 RegisterModule 函式:
在 [方案總管] 中,以滑鼠右鍵按一下 [來源檔案],指向 [新增],然後按一下 [新增專案]。
[新增項目] 對話方塊隨即開啟。
展開 [類別]窗格中的[Visual C++]節點,然後按一下 [程式碼]。
在 [ 範本] 窗格中,選取 [模組定義檔案] 範本。
在 [ 名稱] 方塊中,輸入 HelloWorld,並在 [ 位置 ] 方塊中保留檔案的預設路徑。
按一下 [新增] 。
使用 和
RegisterModule
新增一行EXPORTS
。 您的檔案看起來應該像下列程式碼:LIBRARY"HelloWorld" EXPORTS RegisterModule
注意
您可以使用/EXPORT:RegisterModule參數來匯出RegisterModule函式,而不是建立模組定義檔案。
建立 C++ 檔案:
在 [方案總管] 中,以滑鼠右鍵按一下 [來源檔案],指向 [新增],然後按一下 [新增專案]。
[新增項目] 對話方塊隨即開啟。
展開 [類別]窗格中的[Visual C++]節點,然後按一下 [程式碼]。
在 [ 範本] 窗格中,選取 [C++ 檔案 ] 範本。
在 [ 名稱] 方塊中,輸入 HelloWorld,並在 [ 位置 ] 方塊中保留檔案的預設路徑。
按一下 [新增] 。
新增下列程式碼:
#define _WINSOCKAPI_ #include <windows.h> #include <sal.h> #include <httpserv.h> // Create the module class. class CHelloWorld : public CHttpModule { public: REQUEST_NOTIFICATION_STATUS OnBeginRequest( IN IHttpContext * pHttpContext, IN IHttpEventProvider * pProvider ) { UNREFERENCED_PARAMETER( pProvider ); // Create an HRESULT to receive return values from methods. HRESULT hr; // Retrieve a pointer to the response. IHttpResponse * pHttpResponse = pHttpContext->GetResponse(); // Test for an error. if (pHttpResponse != NULL) { // Clear the existing response. pHttpResponse->Clear(); // Set the MIME type to plain text. pHttpResponse->SetHeader( HttpHeaderContentType,"text/plain", (USHORT)strlen("text/plain"),TRUE); // Create a string with the response. PCSTR pszBuffer = "Hello World!"; // Create a data chunk. HTTP_DATA_CHUNK dataChunk; // Set the chunk to a chunk in memory. dataChunk.DataChunkType = HttpDataChunkFromMemory; // Buffer for bytes written of data chunk. DWORD cbSent; // Set the chunk to the buffer. dataChunk.FromMemory.pBuffer = (PVOID) pszBuffer; // Set the chunk size to the buffer size. dataChunk.FromMemory.BufferLength = (USHORT) strlen(pszBuffer); // Insert the data chunk into the response. hr = pHttpResponse->WriteEntityChunks( &dataChunk,1,FALSE,TRUE,&cbSent); // Test for an error. if (FAILED(hr)) { // Set the HTTP status. pHttpResponse->SetStatus(500,"Server Error",0,hr); } // End additional processing. return RQ_NOTIFICATION_FINISH_REQUEST; } // Return processing to the pipeline. return RQ_NOTIFICATION_CONTINUE; } }; // Create the module's class factory. class CHelloWorldFactory : public IHttpModuleFactory { public: HRESULT GetHttpModule( OUT CHttpModule ** ppModule, IN IModuleAllocator * pAllocator ) { UNREFERENCED_PARAMETER( pAllocator ); // Create a new instance. CHelloWorld * pModule = new CHelloWorld; // Test for an error. if (!pModule) { // Return an error if the factory cannot create the instance. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); } else { // Return a pointer to the module. *ppModule = pModule; pModule = NULL; // Return a success status. return S_OK; } } void Terminate() { // Remove the class from memory. delete this; } }; // Create the module's exported registration function. HRESULT __stdcall RegisterModule( DWORD dwServerVersion, IHttpModuleRegistrationInfo * pModuleInfo, IHttpServer * pGlobalInfo ) { UNREFERENCED_PARAMETER( dwServerVersion ); UNREFERENCED_PARAMETER( pGlobalInfo ); // Set the request notifications and exit. return pModuleInfo->SetRequestNotifications( new CHelloWorldFactory, RQ_BEGIN_REQUEST, 0 ); }
編譯及測試模組
編譯及測試專案
編譯 HTTP 模組:
在 [建置] 功能表上,按一下 [建置方案]。
確認 Visual Studio 未傳回任何錯誤或警告。
將HelloWorld.dll模組 (完整路徑) 新增至
globalModules
%windir%\system32\inetsrv\config\applicationHost.config 檔案的 區段。
使用 Internet Explorer 流覽至您的網站;您應該會看到顯示要求計數的「開始要求範例」。
注意
您必須先停止 IIS,才能在後續組建上連結專案。
針對您的設定進行疑難排解
如果您的模組未如預期般編譯或無法正常運作,以下是您可以檢查的數個區域:
請確定您已為匯出的函式指定
__stdcall
,或使用呼叫慣例來設定編譯__stdcall (/Gz)
。確定 IIS 已載入HelloWorld.dll:
在 IIS 管理員中,按一下 [連線] 窗格中的預設網站。
在工作區 (中央窗格) ,選取 [ 功能檢視]。
在 [ 分組依據 ] 方塊中,選取 [類別]。
在 [ 伺服器元件] 類別中,按兩下 [ 模組]。
確認已列出 HelloWorld 模組。
請確定您已將正確的
RegisterModule
匯出新增至定義檔。請確定您已將定義檔新增至專案設定。 若要將檔案新增至專案設定,請完成下列步驟:
按一下 [專案] 功能表上的 [屬性] 。
展開樹狀檢視中的 [ 組態屬性 ] 節點,展開 [連結器] 節點,然後按一下 [ 輸入]。
針對 [模組定義檔案 ] 設定,請確定已列出您的定義檔。