今天接到Product Manager的通知,Exchange 2007環境下的Native Module再也不須要開發(詳情可見上篇),但最近幾天一直在作Prototype,那就作一下小結吧,總結一下最近幾天的收穫。windows
一. 準備工做:app
1. 開發前安裝Windows Platform SDK,主要是使用其中的#include <httpserv.h>(用到的不少接口均可以在其中看到)ide
2. WireShark,用來進行抓包,能夠驗證本身是否正確拿到http request和response的信息函數
二. Visual Studio 2005編碼:測試
1. Native Module主要使用3個基本組件:this
A. HttpModule類 - HttpModule是當前模塊的積累。在HttpModule類中咱們將實現請求通知方法,這個方法是由IIS在相關的請求處理事件中調用的。(其中主要是定義咱們的處理時間方法,例如onBeginRequest)編碼
B. HttpModule類工廠 - 針對每一個被處理的請求,HttpModule類工廠能夠建立或刪除用於處理請求的模塊spa
C. RegisterModule類函數 - 一個Native Module只會實現一個此函數,用於導出函數,使IIS可以加載模塊(我遇到一個問題,至今還沒解決,就是此函數中我發現只能註冊一個事件,若是多個會致使IIS ative sync pool stop掉,DLL用不起來)code
2. 其餘具體編碼可參見個人示例,具體開發流程可參見《IIS 7開發與管理徹底參考手冊》orm
三. 安裝此Native Module
通過個人測試發現,個人Native Module可以工做,主要是作了如下幾項工做:
1. 編譯後的DLL放置在C:\Windows\System32\inetsrv下
2. 修改applicationHost.xml配置文件,C:\Windows\System32\inetsrv\config,在其中的<globalModules>中添加咱們的模塊
3. IIS 7中,[Domain\User]下,Module中,右鍵選擇Configure Native Module,而後選擇Register,填入咱們模塊的信息。
目前我還不肯定2,3是不是重複了,可是我發現這二者都作的狀況,個人Native Module是工做的,而3的Register不是修改2的配置文件,具體有待驗證。
通過以上三個步驟,個人Native Module能夠工做了!目前能夠拿到Http的Request Header的信息。但願此次小結,能對有開發此類需求的同窗一點參考,因爲此功能被PM去掉了,因此很遺憾這塊我不能繼續作下去,只能是小結啦。:-)
參考資料:
1. 《Professional IIS7》,Wrox出版社出版(Programmer to Programer的理念),很是詳細的講解IIS7,其中12章詳細介紹了Http兩類Module的開發。其中文版是《IIS 7開發與管理徹底參考手冊》
2. MSDN
http://msdn.microsoft.com/en-us/library/ms690856(v=vs.90).aspx
Prototype代碼附上,功能:取Http request的header信息
#define _WINSOCKAPI_ #include <windows.h> #include <sal.h> #include <httpserv.h> #include "writeLog.h" // Create the module class. class CTestNativeModule : public CHttpModule { //TODO // Implement Notification Method/s REQUEST_NOTIFICATION_STATUS OnBeginRequest( IN IHttpContext * pHttpContext, IN IHttpEventProvider * pProvider ) { WriteLog("--> CTestNativeModule, OnBeginRequest()"); // We won’t be using this, so confirm that to avoid compiler warnings UNREFERENCED_PARAMETER( pProvider ); IHttpRequest* pHttpRequest = pHttpContext->GetRequest(); //dump request header DumpRequestHeader(pHttpContext, pHttpRequest); WriteLog("<-- CTestNativeModule, OnBeginRequest()"); return RQ_NOTIFICATION_CONTINUE; } void DumpRequestHeader(IHttpContext * pHttpContext, IHttpRequest* pHttpRequest) { WriteLog("--> CTestNativeModule, DumpRequestHeader()"); // Buffer size for returned variable values. DWORD cbValue = 512; PCSTR pHeaderValue = (PCSTR) pHttpContext->AllocateRequestMemory( cbValue ); for(HTTP_HEADER_ID i = (HTTP_HEADER_ID)0; i < HttpHeaderRequestMaximum; i = (HTTP_HEADER_ID)((int)i + 1)) { pHeaderValue = pHttpRequest->GetHeader(i); WriteLog(pHeaderValue); } HTTP_REQUEST* rawHttpRequest = pHttpRequest->GetRawHttpRequest(); WriteLog("RawUrl", rawHttpRequest->pRawUrl); PCSTR pKey = ""; pKey = "Cmd"; pHeaderValue = pHttpRequest->GetHeader(pKey); WriteLog(pKey, pHeaderValue); pKey = "DeviceId"; pHeaderValue = pHttpRequest->GetHeader(pKey); WriteLog(pKey, pHeaderValue); pKey = "DeviceType"; pHeaderValue = pHttpRequest->GetHeader(pKey); WriteLog(pKey, pHeaderValue); pKey = "AttachmentName"; pHeaderValue = pHttpRequest->GetHeader(pKey); WriteLog(pKey, pHeaderValue); pKey = "MS-ASProtocolVersion"; pHeaderValue = pHttpRequest->GetHeader(pKey); WriteLog(pKey, pHeaderValue); pKey = "X-EAS-Proxy"; pHeaderValue = pHttpRequest->GetHeader(pKey); WriteLog(pKey, pHeaderValue); pKey = "User-Agent"; pHeaderValue = pHttpRequest->GetHeader(pKey); WriteLog(pKey, pHeaderValue); /* //Authorization pKey = "Authorization"; pHeaderValue = pHttpRequest->GetHeader(pKey); writeLog(pKey, pHeaderValue); //Content-Type pKey = "Content-Type"; pHeaderValue = pHttpRequest->GetHeader(pKey); writeLog(pKey, pHeaderValue); //Host pKey = "Host"; pHeaderValue = pHttpRequest->GetHeader(pKey); writeLog(pKey, pHeaderValue); //Content-Length pKey = "Content-Length"; pHeaderValue = pHttpRequest->GetHeader(pKey); writeLog(pKey, pHeaderValue);*/ WriteLog("<-- CTestNativeModule, DumpRequestHeader()"); } void DumpRequestContent(IHttpContext* pHttpContext, IHttpRequest* pHttpRequest) { // Create an HRESULT to receive return values from methods. /*HRESULT hr; // Allocate a 1K buffer. DWORD cbBytesReceived = 1024; void* pvRequestBody = pHttpContext->AllocateRequestMemory(cbBytesReceived); hr = pHttpRequest->ReadEntityBody( pvRequestBody, cbBytesReceived, false, &cbBytesReceived, NULL);*/ } }; // Create the module's class factory. class CTestNativeModuleFactory : public IHttpModuleFactory { public: HRESULT GetHttpModule( OUT CHttpModule ** ppModule, IN IModuleAllocator * pAllocator ) { WriteLog("--> CTestNativeModuleFactory, GetHttpModule()"); UNREFERENCED_PARAMETER( pAllocator ); // Create a new instance. CTestNativeModule * pModule = new CTestNativeModule; // 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; } WriteLog("<-- CTestNativeModuleFactory, GetHttpModule()"); } void Terminate() { WriteLog("--> CTestNativeModuleFactory, Terminate()"); // Remove the class from memory. delete this; WriteLog("<-- CTestNativeModuleFactory, Terminate()"); } }; // Create the module's exported registration function. HRESULT __stdcall RegisterModule( DWORD dwServerVersion, IHttpModuleRegistrationInfo * pModuleInfo, IHttpServer * pGlobalInfo ) { WriteLog("--> RegisterModule()"); HRESULT hr = S_OK; UNREFERENCED_PARAMETER( dwServerVersion ); UNREFERENCED_PARAMETER( pGlobalInfo ); // TODO // Register for notifications // Set notification priority CTestNativeModuleFactory* testNMFacotry = new CTestNativeModuleFactory; // Set the request notifications // BeginRequest hr = pModuleInfo->SetRequestNotifications( testNMFacotry, RQ_BEGIN_REQUEST, // Register for BeginRequest notifications 0); if( hr == S_OK ) // Do this only if there was no error { hr = pModuleInfo->SetPriorityForRequestNotification( RQ_BEGIN_REQUEST, // which notification PRIORITY_ALIAS_FIRST // what priority ); } WriteLog("<-- RegisterModule()"); return hr; }