ページレベル HTTP モジュールの開発 (サンプルコード)

概要

ここでは IIS 7.0 ではじめて利用可能となった、ページレベル HTTP モジュールの簡単なサンプル・プログラムを作成します。

開発環境は Visual C++ 2008 を想定しています。それ以前の環境ですと、ヘッダファイルが見つからないなどの エラーが発生する可能性がありますので気をつけてください。

ここでは統合開発環境を利用せずに Visual C++ 2008 のコマンドプロンプトを利用しています。 統合開発環境を利用する場合の方法は、また後ほど資料を作ろうと思います。

関連資料

  1. ページレベル HTTP モジュールのインストール
  2. ページレベル HTTP モジュールの動作確認

サンプルコード

コードの準備

rhttpmod.h として以下を保存します。


#pragma once

#include <windows.h>
#include <httpserv.h>

HRESULT __stdcall RegisterModule(
     DWORD dwServerVersion, 
     IHttpModuleRegistrationInfo * pModuleInfo, 
     IHttpServer * pGlobalInfo );

rhttpmod.cpp として以下を保存します。


#define _WINSOCKAPI_
#include "rhttpmod.h"
#include "myhttpmod.h"


HRESULT __stdcall RegisterModule(
     DWORD dwServerVersion,
     IHttpModuleRegistrationInfo * pModuleInfo,
     IHttpServer * pGlobalInfo
) {

     ::OutputDebugString ( TEXT("RegisterModule") );

     return pModuleInfo->SetRequestNotifications( 
          new MyHttpModuleFactory,
          RQ_BEGIN_REQUEST,
          0
     );

}

myhttpmod.h として以下を保存します。


#pragma once

#include <windows.h>
#include <httpserv.h>


class MyHttpModuleFactory : public IHttpModuleFactory {
public:

     MyHttpModuleFactory();
     ~MyHttpModuleFactory();
     
     HRESULT GetHttpModule(
          CHttpModule**          ppModule,
          IModuleAllocator*     pAllocator
     );
     
     void Terminate();

};


class MyHttpModule : public CHttpModule {
public:

     MyHttpModule();
     ~MyHttpModule();

     REQUEST_NOTIFICATION_STATUS OnBeginRequest(
          IHttpContext*          pHttpContext,
          IHttpEventProvider*     pProvider
     );
};

myhttpmod.cpp として以下を保存します。


#define _WINSOCKAPI_
#include "myhttpmod.h"

#define MYHTTP_MODULE_MIME     "text/html"


/////////////////////////////////////////////////////////////////////
//
// MyHttpModuleFactory クラス
//


MyHttpModuleFactory::MyHttpModuleFactory() {
     ::OutputDebugString ( TEXT( "MyHttpModuleFactory::MyHttpModuleFactory" ) );
}


/////////////////////////////////////////////////////////////////////


MyHttpModuleFactory::~MyHttpModuleFactory() {
     ::OutputDebugString ( TEXT( "MyHttpModuleFactory::~MyHttpModuleFactory" ) );
}


/////////////////////////////////////////////////////////////////////


HRESULT MyHttpModuleFactory::GetHttpModule(
     CHttpModule**          ppModule,
     IModuleAllocator*     pAllocator
) {

     ::OutputDebugString ( TEXT( "MyHttpModuleFactory::GetHttpModule" ) );
          
     MyHttpModule* pModule = new MyHttpModule;

     if (!pModule) {
          ::OutputDebugString ( TEXT( "!pModule" ) );
          return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
     }

     *ppModule = pModule;

     return S_OK;

}


/////////////////////////////////////////////////////////////////////


void MyHttpModuleFactory::Terminate() {
     ::OutputDebugString ( TEXT( "MyHttpModuleFactory::Terminate" ) );
     delete this;
}


/////////////////////////////////////////////////////////////////////
//
// MyHttpModule クラス
//


MyHttpModule::MyHttpModule() {
     ::OutputDebugString ( TEXT( "MyHttpModule::MyHttpModule" ) );
}


/////////////////////////////////////////////////////////////////////


MyHttpModule::~MyHttpModule() {
     ::OutputDebugString ( TEXT( "MyHttpModule::~MyHttpModule" ) );
}


/////////////////////////////////////////////////////////////////////


REQUEST_NOTIFICATION_STATUS MyHttpModule::OnBeginRequest(
     IHttpContext*          pHttpContext,
     IHttpEventProvider*     pProvider
) {

     ::OutputDebugString ( TEXT( "MyHttpModule::OnBeginRequest" ) );          

     HRESULT hr;

     //
     // レスポンスをクリアする
     //

     IHttpResponse * pHttpResponse = pHttpContext->GetResponse();

     if ( !pHttpResponse ) {
          ::OutputDebugString ( TEXT( "pHttpResponse == NULL!!" ) );
          return RQ_NOTIFICATION_CONTINUE;
     }
          
     pHttpResponse->Clear();

     //
     // テスト用のファイルを開く
     //

     HANDLE hFile = CreateFile (
          TEXT( "C:\\Temp\\wwwroot\\index.htm" ),
          GENERIC_READ,
          FILE_SHARE_READ,
          NULL,
          OPEN_EXISTING,
          0,
          NULL );

     if ( INVALID_HANDLE_VALUE == hFile ) {
          ::OutputDebugString ( TEXT( "CreateFile Failed." ) );
          return RQ_NOTIFICATION_CONTINUE;
     }

     //
     // Content-Type ヘッダを設定
     //

     pHttpResponse->SetHeader( 
          HttpHeaderContentType, 
          MYHTTP_MODULE_MIME, 
          (USHORT) lstrlenA ( MYHTTP_MODULE_MIME ),
          TRUE);

     //
     // レスポンスの内容を設定
     // ここではファイルハンドルを渡し、ファイル全体を送信する
     //

     HTTP_DATA_CHUNK dataChunk;
     dataChunk.DataChunkType = HttpDataChunkFromFileHandle;
     dataChunk.FromFileHandle.FileHandle = hFile;
     dataChunk.FromFileHandle.ByteRange.StartingOffset.QuadPart = 0;
     dataChunk.FromFileHandle.ByteRange.Length.QuadPart = HTTP_BYTE_RANGE_TO_EOF;
     DWORD cbSent;

     hr = pHttpResponse->WriteEntityChunks(
          &dataChunk,
          1,
          FALSE,
          TRUE,
          &cbSent);

     if ( FAILED(hr) ) {
          pHttpResponse->SetStatus( 500, "Server Error", 0, hr);
     }

     CloseHandle ( hFile );

     ::OutputDebugString ( TEXT( "Exit MyHttpModule::OnBeginRequest" ) );

     return RQ_NOTIFICATION_FINISH_REQUEST;

}

rhttpmod.def として以下を保存します。

LIBRARY rhttpmod

EXPORTS
	RegisterModule

makefile として以下を保存します。

TARGETNAME=rhttpmod
DEFFILE=rhttpmod
OUTDIR=.\chk
LINK32=link.exe

ALL : "$(OUTDIR)\$(TARGETNAME).dll"


"$(OUTDIR)" :
	@if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"


CPP_PROJ=\
	/MT\
	/W3\
	/Fo"$(OUTDIR)\\"\
	/Fd"$(OUTDIR)\\"\
	/c\
	/Gz\
	/DUNICODE\
	/D_UNICODE\
	/D_WIN32_WINNT=0x0600\
	/DWIN32
		

LINK32_FLAGS=\
	/SUBSYSTEM:windows\
	/PDB:"$(OUTDIR)\$(TARGETNAME).pdb"\
	/DEBUG\
	/RELEASE\
	/OUT:"$(OUTDIR)\$(TARGETNAME).dll"\
	/DLL\
	/DEF:$(DEFFILE).def
	

LINK32_OBJS= \
	"$(OUTDIR)\$(TARGETNAME).obj"\
	"$(OUTDIR)\myhttpmod.obj"



"$(OUTDIR)\$(TARGETNAME).dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
    $(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS)


.c{$(OUTDIR)}.obj::
   $(CPP) $(CPP_PROJ) $< 


.cpp{$(OUTDIR)}.obj::
   $(CPP) $(CPP_PROJ) $< 

ページレベル HTTP モジュールのビルド

上記コードを nmake でビルドすると、rhttpmod.dll という DLL ができます。

makefile や nmake でのビルド方法に慣れていない人は、当サイトの情報 makefile の書き方 等を見てください。また、ビルドするためには新しい Windows SDK がインストールされている環境でビルドする必要があります。 Visual C++ 2008 なら大丈夫のはずです。

それでは、ここで作成したページレベル HTTP モジュール DLL (rhttpmod.dll) を IIS 7.0 にインストールしましょう。

* 次へ (ページレベル HTTP モジュールのインストール)

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Web/DB プログラミング徹底解説