チュートリアル: ネイティブ コードを使用したRequest-Level HTTP モジュールの作成

このチュートリアルでは、C++ を使用して、IIS 7 で新しい要求処理アーキテクチャを実装するサンプル要求レベルの HTTP モジュールを作成する方法について説明します。 この新しいアーキテクチャでは、以前のバージョンの 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 プロジェクトを作成するには

  1. Visual Studio 2005 を開きます。

  2. グローバル オプションに SDK インクルード ファイルへの適切なパスがすべて含まれることを確認します。

    1. [ツール] メニューの [オプション] をクリックします。

    2. ツリー ビューで [ プロジェクトとソリューション] ノードを展開し、[ VC++ ディレクトリ] をクリックします。

    3. [ ディレクトリの表示] ドロップダウン ボックスで、[ファイルを 含める] を選択します。

    4. Windows SDK インクルード ファイルをインストールしたパスが一覧表示されていることを確認します。 パスが一覧にない場合は、[ 改行 ] アイコンをクリックし、SDK インクルード ファイルをインストールしたパスを追加します。 既定のインストール ディレクトリは $(VCInstallDir)PlatformSDK\bin です。

    5. [OK] をクリックします。

  3. 新しい C++ プロジェクトを作成します。

    1. [ファイル] メニューの [新規作成] をポイントし、 [プロジェクト] をクリックします。

      [新しいプロジェクト] ダイアログ ボックスが表示されます。

    2. [ プロジェクトの種類 ] ウィンドウで、[ Visual C++ ] ノードを展開し、[ Win32] をクリックします。

    3. [テンプレート] ウィンドウ 、[ Win32 プロジェクト] を選択します。

    4. [ 名前 ] ボックスに 「HelloWorld」と入力します。

    5. [ 場所 ] ボックスに、サンプルのパスを入力します。

    6. [OK] をクリックします。

      Win32 アプリケーション ウィザードが開きます。

    7. [ アプリケーションの設定] をクリックします

    8. [ アプリケーションの種類] で、[ DLL] をクリックします。

    9. [ その他のオプション] で、[ 空のプロジェクト] をクリックします。

    10. [完了] をクリックします。

コード ファイルとソース ファイルの追加

次の手順では、必要な C++ ファイルとモジュール定義ファイルをプロジェクトに追加します。

ソース ファイルをプロジェクトに追加するには

  1. RegisterModule 関数をエクスポートするモジュール定義ファイルを作成します。

    1. ソリューション エクスプローラーで[ソース ファイル]を右クリックし、[追加]、[新しい項目] の順にクリックします。

      [新しい項目の追加] ダイアログ ボックスが開きます。

    2. [カテゴリ] ウィンドウで [Visual C++] ノードを展開し、[コード] をクリックします。

    3. [テンプレート] ペイン 、[ モジュール定義ファイル ] テンプレートを選択します。

    4. [ 名前 ] ボックスに 「HelloWorld」と入力し、[ 場所 ] ボックスにファイルの既定のパスをそのまま使用します。

    5. [追加] をクリックします。

    6. RegisterModuleを含む行をEXPORTS追加します。 ファイルは次のコードのようになります。

      LIBRARY"HelloWorld"  
      EXPORTS  
          RegisterModule  
      

      注意

      モジュール定義ファイルを作成する代わりに、/EXPORT:RegisterModule スイッチを使用して RegisterModule 関数をエクスポートできます。

  2. C++ ファイルを作成します。

    1. ソリューション エクスプローラーで[ソース ファイル]を右クリックし、[追加]、[新しい項目] の順にクリックします。

      [新しい項目の追加] ダイアログ ボックスが開きます。

    2. [カテゴリ] ウィンドウで [Visual C++] ノードを展開し、[コード] をクリックします。

    3. [テンプレート] ウィンドウ C++ ファイル テンプレートを選択します。

    4. [ 名前 ] ボックスに 「HelloWorld」と入力し、[ 場所 ] ボックスにファイルの既定のパスをそのまま使用します。

    5. [追加] をクリックします。

    6. 次のコードを追加します。

      #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
          );
      }
      

モジュールのコンパイルとテスト

プロジェクトをコンパイルしてテストするには

  1. HTTP モジュールをコンパイルします。

    1. [ビルド] メニューの [ソリューションのビルド] をクリックします。

    2. Visual Studio がエラーまたは警告を返さなかったことを確認します。

    3. HelloWorld.dll モジュール (完全なパスを含む) を globalModules %windir%\system32\inetsrv\config\applicationHost.config ファイルのセクションに追加します。

  2. インターネット エクスプローラーを使用して Web サイトを参照します。"Begin Request sample" と表示され、要求数が表示されます。

注意

後続のビルドでプロジェクトをリンクする前に、IIS を停止する必要があります。

設定のトラブルシューティング

モジュールがコンパイルされない場合、または期待どおりに動作しない場合は、チェックできるいくつかの領域を次に示します。

  • エクスポートした関数に対して を指定 __stdcall しているか、呼び出し規則を使用してコンパイルを __stdcall (/Gz) 構成していることを確認します。

  • IIS がHelloWorld.dll読み込まれたことを確認します。

    1. IIS マネージャーで、[接続] ウィンドウの [既定の Web サイト] をクリックします。

    2. ワークスペース (中央のウィンドウ) で、[ 機能ビュー] を選択します。

    3. [ グループ化 ] ボックスで、[ カテゴリ] を選択します。

    4. [ サーバー コンポーネント] カテゴリで、[ モジュール] をダブルクリックします。

    5. HelloWorld モジュールが一覧表示されていることを確認します。

  • 正しい RegisterModule エクスポートが定義ファイルに追加されていることを確認します。

  • 定義ファイルがプロジェクト設定に追加されていることを確認します。 プロジェクト設定にファイルを追加するには、次の手順を実行します。

    1. [プロジェクト] メニューの [プロパティ] をクリックします。

    2. ツリー ビューで [ 構成プロパティ] ノードを展開し、[ リンカー ] ノードを展開して、[ 入力] をクリックします。

    3. [ モジュール定義ファイル] 設定で、定義ファイルが一覧表示されていることを確認します。

参照

Native-Code HTTP モジュールの作成
Native-Code HTTP モジュールの設計