IIS Modules (2/6)

Foundations

IIS modules written in C++ are implemented by deriving from the CHttpModule class. The CHttpModule class has several virtual functions that correspond to the different stages of the request lifecycle.

A factory class derived from IHttpModuleFactory must also be provided. It provides the method that the IIS server will call to create a new instance of the module: HRESULT GetHttpModule(OUT CHttpModule** ppModule, IN IModuleAllocator* pAllocator).

The code is packaged in a DLL that must export the HRESULT __stdcall RegisterModule(DWORD dwServerVersion, IHttpModuleRegistrationInfo * pModuleInfo, IHttpServer * pGlobalInfo) function. That function will be called by the IIS server to get an instance of the module factory and the list of events the module wishes to get notified about.

A "Hello World!" Module

We will need an example to illustrate the next topics so let's create the traditional "Hello World!" application in the form of a module that will display a web page with "Hello World!" on it.

File: IISHelloWorldModuleFactory.h
#ifndef _NDFSW_TUTORIALS_IIS_HELLOWORLDMODULEFACTORY_H_
#define _NDFSW_TUTORIALS_IIS_HELLOWORLDMODULEFACTORY_H_

#define _WINSOCKAPI_
#include <httpserv.h>    // for IHttpModuleFactory

class IISHelloWorldModuleFactory : public IHttpModuleFactory
{
public:
    HRESULT GetHttpModule(OUT CHttpModule** ppModule, IN IModuleAllocator* pAllocator);
    void Terminate();
};

#endif
File: IISHelloWorldModuleFactory.cpp
#include "IISHelloWorldModuleFactory.h"
#include "IISHelloWorldModule.h"

HRESULT __stdcall RegisterModule(DWORD dwServerVersion,
    IHttpModuleRegistrationInfo * pModuleInfo,
    IHttpServer * pGlobalInfo)
{
    return pModuleInfo->SetRequestNotifications(new IISHelloWorldModuleFactory(),
        RQ_BEGIN_REQUEST, 0);
}

HRESULT IISHelloWorldModuleFactory::GetHttpModule(OUT CHttpModule** ppModule,
                                                  IN IModuleAllocator* pAllocator)
{
    *ppModule = new(std::nothrow) IISHelloWorldModule();
    if (*ppModule == nullptr)
    {
        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
    }
    return S_OK;
}

void IISHelloWorldModuleFactory::Terminate()
{
    delete this;
}
File: IISHelloWorldModule.h
#ifndef _NDFSW_TUTORIALS_IIS_HELLOWORLDMODULE_H_
#define _NDFSW_TUTORIALS_IIS_HELLOWORLDMODULE_H_

#define _WINSOCKAPI_
#include <httpserv.h>    // for CHttpModule
#include <string>

class IISHelloWorldModule : public CHttpModule
{
public:
    REQUEST_NOTIFICATION_STATUS OnBeginRequest(IN IHttpContext* pHttpContext,
        IN IHttpEventProvider* pProvider);

private:
    void writeResponse(IHttpContext* pHttpContext, const std::string& text);
};

#endif
File: IISHelloWorldModule.cpp
#include "IISHelloWorldModule.h"

REQUEST_NOTIFICATION_STATUS IISHelloWorldModule::OnBeginRequest(IN IHttpContext* pHttpContext,
    IN IHttpEventProvider* pProvider)
{
    writeResponse(pHttpContext, "Hello World!");
    return RQ_NOTIFICATION_FINISH_REQUEST;
}

void IISHelloWorldModule::writeResponse(IHttpContext* pHttpContext,
                                        const std::string& text)
{
    HTTP_DATA_CHUNK dataChunk;
    dataChunk.DataChunkType = HttpDataChunkFromMemory;
    dataChunk.FromMemory.pBuffer = (void*)text.c_str();
    dataChunk.FromMemory.BufferLength = text.size();
    DWORD cbSent;
    pHttpContext->GetResponse()->WriteEntityChunks(&dataChunk, 1, false, false, &cbSent);
}
If you create a 32-bit module it will probably not be loaded successfully if you keep the default settings for the application pool on 64-bit versions of IIS.
/EXPORT:RegisterModule to linker command line

blog comments powered by Disqus

Copyright(c) 2006-2015 Xavier Leclercq | Privacy policy

Home
Contact Us
Search