ページレベル HTTP モジュールの開発 (サンプルコード)
概要
ここでは IIS 7.0 ではじめて利用可能となった、ページレベル HTTP モジュールの簡単なサンプル・プログラムを作成します。
開発環境は Visual C++ 2008 を想定しています。それ以前の環境ですと、ヘッダファイルが見つからないなどの エラーが発生する可能性がありますので気をつけてください。
ここでは統合開発環境を利用せずに Visual C++ 2008 のコマンドプロンプトを利用しています。 統合開発環境を利用する場合の方法は、また後ほど資料を作ろうと思います。
関連資料
サンプルコード
コードの準備
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 にインストールしましょう。