本教學示範如何使用 C++ 建立一個範例請求層級 HTTP 模組,實作 IIS 7 中新的請求處理架構。 這種新架構擴充了原生程式碼程式設計的能力,當您在撰寫 IIS 應用程式時,比較早期版本的 ASP.NET HTTP 模組及 ISAPI 過濾器或擴充應用程式。 欲了解更多使用新請求處理架構設計 HTTP 模組的資訊,請參見 HTTP 模組設計 Native-Code。
在這個教學中,你會為你的 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++ 與模組定義檔案加入專案。
將原始碼檔案加入專案
建立 module-definition 檔案以匯出 RegisterModule 函式:
在解決方案總管中,右鍵點擊 「來源檔案」,指向 「新增」,然後點選 「新增項目」。
[新增項目] 對話框開啟。
在分類窗格中展開 Visual C++ 節點,然後點選程式碼。
在 範本 面板中,選擇 Module-Definition 檔案 範本。
在 名稱 框輸入 HelloWorld,並在 位置 欄位保留檔案的預設路徑。
按一下新增。
加上一條含有
EXPORTS和RegisterModule的線。 你的檔案應該會像下面的程式碼一樣: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 模組(包含完整路徑)加入 %windir%\system32\inetsrv\config\applicationHost.config 檔案的區段
globalModules。
使用 Internet Explorer 瀏覽您的網站;你應該會看到「開始請求範例」,並顯示請求數量。
備註
你需要在後續建置中連結專案前先停止 IIS。
設定故障排除
如果你的模組無法編譯或運作如預期,以下是幾個你可以檢查的區域:
請確保你已指定
__stdcall匯出函式,或已透過呼叫__stdcall (/Gz)慣例設定編譯。確保 IIS 已載入 HelloWorld.dll:
在 IIS Manager 中,點擊連接欄中的預設網站。
在工作區(中央窗格)中,選擇 「功能檢視」。
在「按群組」框中,選擇類別。
在 伺服器元件 類別中, 雙擊模組。
確認 HelloWorld 模組是否被列出。
請確保你已將正確的
RegisterModule匯出檔案加入定義檔案。請確保你已經將定義檔加入專案設定。 要將檔案加入專案設定,請完成以下步驟:
在 [項目] 功能表上,點擊 [屬性]。
在樹狀檢視中展開 設定屬性 節點,展開 連結節點 ,然後點選 輸入。
在 模組定義檔案 設定中,請確保你的定義檔案被列出。