What notifications are delivered to IIS7 native modules

Here is the output of getmreg tool for all the modules listed under <system.webServer/globalModules> section in IIS7 full install. This tells what notifications are delivered to native modules shipped with IIS7.

1. UriCacheModule – getmreg.exe %windir%\system32\inetsrv\cachuri.dll
Global notifications
GL_CACHE_CLEANUP
GL_CACHE_OPERATION
GL_CONFIGURATION_CHANGE

2. FileCacheModule – getmreg.exe %windir%\system32\inetsrv\cachfile.dll
Global notifications
GL_CACHE_CLEANUP
GL_CACHE_OPERATION
GL_FILE_CHANGE

3. TokenCacheModule – getmreg.exe %windir%\system32\inetsrv\cachtokn.dll
Global notifications
GL_CACHE_CLEANUP
GL_CACHE_OPERATION

4. HttpCacheModule – getmreg.exe %windir%\system32\inetsrv\cachhttp.dll
Global notifications
GL_CACHE_CLEANUP
GL_CONFIGURATION_CHANGE
GL_FILE_CHANGE
Request notifications
RQ_BEGIN_REQUEST

RQ_RESOLVE_REQUEST_CACHE
RQ_UPDATE_REQUEST_CACHE
RQ_SEND_RESPONSE

5. DynamicCompressionModule – getmreg.exe %windir%\system32\inetsrv\compdyn.dll
Request notifications
RQ_SEND_RESPONSE
POST_RQ_RELEASE_REQUEST_STATE

6. StaticCompressionModule – getmreg.exe %windir%\system32\inetsrv\compstat.dll

Request notifications
RQ_MAP_REQUEST_HANDLER
RQ_RELEASE_REQUEST_STATE
 
7. DefaultDocumentModule – getmreg.exe %windir%\system32\inetsrv\defdoc.dll
Request notifications
RQ_EXECUTE_REQUEST_HANDLER
 
8. DirectoryListingModule – getmreg.exe %windir%\system32\inetsrv\dirlist.dll
Request notifications
RQ_EXECUTE_REQUEST_HANDLER
 
9. ProtocolSupportModule – getmreg.exe %windir%\system32\inetsrv\protsup.dll
Request notifications
RQ_EXECUTE_REQUEST_HANDLER
RQ_SEND_RESPONSE
 
10. HttpRedirectionModule – getmreg.exe %windir%\system32\inetsrv\redirect.dll
Request notifications
RQ_MAP_REQUEST_HANDLER
 
11. ServerSideIncludeModule – getmreg.exe %windir%\system32\inetsrv\iis_ssi.dll
Request notifications
RQ_EXECUTE_REQUEST_HANDLER
 
12. StaticFileModule – getmreg.exe %windir%\system32\inetsrv\static.dll
Request notifications
RQ_EXECUTE_REQUEST_HANDLER
 
13. AnonymousAuthenticationModule – getmreg.exe %windir%\system32\inetsrv\authanon.dll
Request notifications
RQ_AUTHENTICATE_REQUEST
Setting priority for request notifications
RQ_AUTHENTICATE_REQUEST
LOW
 
14. CertificateMappingAuthenticationModule – getmreg.exe %windir%\system32\inetsrv\authcert.dll
Request notifications
RQ_AUTHENTICATE_REQUEST
 
15. UrlAuthorizationModule – getmreg.exe %windir%\system32\inetsrv\urlauthz.dll
Request notifications
RQ_AUTHORIZE_REQUEST
 
16. BasicAuthenticationModule – getmreg.exe %windir%\system32\inetsrv\authbas.dll
Request notifications
RQ_AUTHENTICATE_REQUEST
RQ_SEND_RESPONSE
 
17. WindowsAuthenticationModule – getmreg.exe %windir%\system32\inetsrv\authsspi.dll
Request notifications
RQ_AUTHENTICATE_REQUEST
RQ_SEND_RESPONSE
 
18. DigestAuthenticationModule – getmreg.exe %windir%\system32\inetsrv\authmd5.dll
Request notifications
RQ_AUTHENTICATE_REQUEST
RQ_SEND_RESPONSE
 
19. IISCertificateMappingAuthenticationModule – getmreg.exe %windir%\system32\inetsrv\authmap.dll
Request notifications
RQ_AUTHENTICATE_REQUEST
 
20. IpRestrictionModule – getmreg.exe %windir%\system32\inetsrv\iprestr.dll
Request notifications
RQ_BEGIN_REQUEST
 
21. RequestFilteringModule – getmreg.exe %windir%\system32\inetsrv\modrqflt.dll
Request notifications
RQ_BEGIN_REQUEST
 
22. CustomLoggingModule – getmreg.exe %windir%\system32\inetsrv\logcust.dll
Request notifications
RQ_LOG_REQUEST
 
23. CustomErrorModule – getmreg.exe %windir%\system32\inetsrv\custerr.dll
Request notifications
RQ_SEND_RESPONSE
Setting priority for request notifications
RQ_SEND_RESPONSE
HIGH
 
24. HttpLoggingModule – getmreg.exe %windir%\system32\inetsrv\loghttp.dll
Request notifications
RQ_SEND_RESPONSE
 
25. TracingModule – getmreg.exe %windir%\system32\inetsrv\iisetw.dll
Global notifications
GL_TRACE_EVENT
 
26. FailedRequestsTracingModule – getmreg.exe %windir%\system32\inetsrv\iisfreb.dll
Request notifications
RQ_BEGIN_REQUEST
Global notifications
GL_PRE_BEGIN_REQUEST
GL_TRACE_EVENT
 
27. RequestMonitorModule – getmreg.exe %windir%\system32\inetsrv\iisreqs.dll
Request notifications
RQ_BEGIN_REQUEST
RQ_END_REQUEST
Global notifications
GL_RSCA_QUERY
 
28. IsapiModule – getmreg.exe %windir%\system32\inetsrv\isapi.dll
Request notifications
RQ_EXECUTE_REQUEST_HANDLER
RQ_SEND_RESPONSE
Global notifications
GL_CONFIGURATION_CHANGE
 
29. IsapiFilterModule – getmreg.exe %windir%\system32\inetsrv\filter.dll
Request notifications
RQ_AUTHENTICATE_REQUEST
RQ_AUTHORIZE_REQUEST
RQ_MAP_PATH
RQ_SEND_RESPONSE
Global notifications
GL_PRE_BEGIN_REQUEST
 
30. CgiModule – getmreg.exe %windir%\system32\inetsrv\cgi.dll
Request notifications
RQ_EXECUTE_REQUEST_HANDLER
Global notifications
GL_STOP_LISTENING
GL_CONFIGURATION_CHANGE
 
31. ConfigurationValidationModule – getmreg.exe %windir%\system32\inetsrv\validcfg.dll
Request notifications
RQ_BEGIN_REQUEST
 
32. ManagedEngine – getmreg.exe %windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll
Global notifications
GL_APPLICATION_RESOLVE_MODULES
GL_APPLICATION_STOP
GL_THREAD_CLEANUP

-Kanwal-

Tool to find native module’s pipeline events registration (source code)

//
// Filename – getmreg.cxx 
// Build this as an executable.
// Keep this exe and module dll
// in the same folder
//
// Run using "getmreg.exe <path to module>"
//
// This tool uses hostable web core functionality
// of IIS7. So this will only run on machine with
// IIS7 installed. You don’t need to have w3svc running.
//

#include <stdio.h>
#include <windows.h>
#include "httpserv.h"
#include "hwebcore.h"

HRESULT
WriteContentToConfigFile(
    HANDLE hConfigFile,
    DWORD dwPort,
    PCSTR pszModulePath
);

extern
"C"
INT
__cdecl
wmain(
    INT argc,
    __in_ecount(argc) PCWSTR argv[]
)
{
    //
    // Introduction
    //
    wprintf(L"GetMReg: Prints event registration information of native modules.\r\n");
    wprintf(L" Author: Kanwaljeet Singla\r\n\r\n");

   
HRESULT hr = S_OK;
    DWORD dwErr = 0;
    DWORD dwSize = 0;

    if(argc != 2)
    {
        wprintf(L"Usage: getmreg <path to native module>\r\nAborting\r\n");
        goto finished;
    }
   
    //
    // Set the module path in an environment variable
    // which module can read
    //
    if(SetEnvironmentVariable(
            L"MODULEPATH",
            argv[1]) == FALSE)
    {
        wprintf(L"Call to SetEnvironmentVariable failed\r\nAborting\r\n");
        goto finished;
    }

    //
    // Build path to hwebcore.dll using GetSystemDirectory
    //
    HINSTANCE hHWebCore = NULL;
    PWSTR pszSystemDir = NULL;
   
    dwSize = GetSystemDirectory(pszSystemDir, 0);
    if(dwSize == 0)
    {
        wprintf(L"Call to GetSystemDirectory failed\r\nAborting\r\n");
        goto finished;
    }

    pszSystemDir = (PWSTR)malloc((dwSize + 1)* sizeof(WCHAR));
    if(pszSystemDir == NULL)
    {
        wprintf(L"Out of memory error\r\nAborting\r\n");
        goto finished;
    }

    if(GetSystemDirectory(pszSystemDir, dwSize + 1) == 0)
    {
        wprintf(L"Call to GetSystemDirectory gave unexpected error\r\nAborting\r\n");
        goto finished;
    }

    PWSTR hwebcore = (PWSTR)malloc(MAX_PATH * sizeof(WCHAR));
    if(hwebcore == NULL)
    {
        wprintf(L"Out of memory error\r\nAborting\r\n");
        goto finished;

    }


    if(wcslen(pszSystemDir) > MAX_PATH – 22)
    {
        wprintf(L"hwebcore.dll path larger than MAX_PATH\r\nAborting\r\n");
        goto finished;
    }

 

 

    wcscat(hwebcore, L"\\inetsrv\\hwebcore.dll");
   
    //
    // Load hwebcore.dll
    //
    hHWebCore = LoadLibraryEx(hwebcore, NULL, 0);
    if(hHWebCore == NULL)
    {
        wprintf(L"Could not load hwebcore.dll\r\nAborting\r\n");
        goto finished;
    }
    //
    // Get entry point WebcoreActivate and WebcoreShutdown
    //
    PFN_WEB_CORE_ACTIVATE pfnWebcoreActivate = NULL;
    PFN_WEB_CORE_SHUTDOWN pfnWebcoreShutdown = NULL;

    pfnWebcoreActivate = (PFN_WEB_CORE_ACTIVATE)GetProcAddress(
        hHWebCore,
        WEB_CORE_ACTIVATE_DLL_ENTRY);

    pfnWebcoreShutdown = (PFN_WEB_CORE_SHUTDOWN) GetProcAddress(
        hHWebCore,
        WEB_CORE_SHUTDOWN_DLL_ENTRY
        );

    if(pfnWebcoreActivate == NULL ||
       pfnWebcoreShutdown == NULL)
    {
        wprintf(L"Didn’t get WebcoreActivate or WebcoreShutdown entry points\r\nAborting\r\n");
        goto finished;
    }

    //
    // Get current process path
    //
    PSTR pszHelperModulePath = NULL;
    pszHelperModulePath = (PSTR)malloc(MAX_PATH * sizeof(CHAR));
    dwSize = GetModuleFileNameA(NULL,
        pszHelperModulePath,
        MAX_PATH);

    if(dwSize == 0)
    {
        wprintf(L"Call to GetModuleFileNameA failed\r\nAborting\r\n");
        goto finished;
    }

    //
    // Get the folder and add GetMRegModule.dll to build module path
    //
    PSTR pszLastSlash = strrchr(pszHelperModulePath, ‘\\’);

    *(pszLastSlash + 1) = 0;

    if(strlen(pszHelperModulePath) > MAX_PATH – 18)
    {
        wprintf(L"GetMRegModule.dll path larger than MAX_PATH\r\nAborting\r\n");
        goto finished;
    }

 

    strcat(pszHelperModulePath, "GetMRegModule.dll");

    //
    // Create config file in temp folder
    // Ports starting from 31212 will be tried if
    // WebcoreActivate fails with error 0x80070038
    //

    DWORD dwPort = 31212;
    PWSTR pszTempPath = NULL;
    dwSize = GetTempPath(0, pszTempPath);

    if(dwSize == 0)
    {
        wprintf(L"Call to GetTempPath failed\r\nAborting\r\n");
        goto finished;
    }

    pszTempPath = (PWSTR)malloc((dwSize + 1)* sizeof(WCHAR));
    if(pszTempPath == NULL)
    {
        wprintf(L"Out of memory error\r\nAborting\r\n");
        goto finished;
    }

    if(GetTempPath(dwSize + 1, pszTempPath) == 0)
    {
        wprintf(L"Call to GetTempPath gave unexpected error\r\nAborting\r\n");
        goto finished;
    }

    PWSTR configPath = (PWSTR)malloc(MAX_PATH * sizeof(WCHAR));
    wcscpy(configPath, pszTempPath);
    wcscat(configPath, L"getmreg.config");
   
    //
    // CREATE_ALWAYS overwrite existing file
    //
createconfig:
    HANDLE hConfigFile = CreateFile(configPath,
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
    if(hConfigFile == NULL)
    {
        wprintf(L"Couldn’t create file\r\nAborting\r\n");
        goto finished;
    }

    hr = WriteContentToConfigFile(
        hConfigFile,
        dwPort,
        pszHelperModulePath);
    if(FAILED(hr))
    {
        goto finished;
    }

    if(hConfigFile != NULL)
    {
        CloseHandle(hConfigFile);
        hConfigFile = NULL;
    }

    //
    // Call WebcoreActivate which should call RegisterModule of the module
    //
    hr = pfnWebcoreActivate(configPath, L"", L"GETMREG");
    if(FAILED(hr))
    {
        wprintf(L"Call to webcore activate failed %d\r\n", hr);
        if(hr == 0x80070038)
        {
            wprintf(L"Trying different port\r\n");
            dwPort++;
            goto createconfig;
        }
        else
        {
            wprintf(L"Aborting\r\n");
            goto finished;
        }
    }

    //
    // Call WebcoreShutdown
    //
    hr = pfnWebcoreShutdown(1);
    if(FAILED(hr))
    {
        wprintf(L"Call to webcore shutdown failed\r\n");
        wprintf(L"Aborting\r\n");
        goto finished;
    }

finished:
    //
    // Unload hwebcore.dll
    //
    if(hHWebCore != NULL)
    {
        FreeLibrary(hHWebCore);
        pfnWebcoreActivate = NULL;
        pfnWebcoreShutdown = NULL;
        hHWebCore = NULL;
    }

    //
    // free allocated string buffers
    //
    if(pszSystemDir != NULL)
    {
        free(pszSystemDir);
        pszSystemDir = NULL;
    }

    if(hwebcore != NULL)
    {
        free(hwebcore);
        hwebcore = NULL;
    }

    if(pszHelperModulePath != NULL)
    {
        free(pszHelperModulePath);
        pszHelperModulePath = NULL;
    }

    if(pszTempPath != NULL)
    {
        free(pszTempPath);
        pszTempPath = NULL;
    }

    if(configPath != NULL)
    {
        free(configPath);
        configPath = NULL;
    }
   
    //
    // Close file handles
    //
    if(hConfigFile != NULL)
    {
        CloseHandle(hConfigFile);
        hConfigFile = NULL;
    }

    return 0;
}   // wmain

HRESULT
WriteContentToConfigFile(
    IN HANDLE hConfigFile,
    IN DWORD dwPort,
    IN PCSTR pszModulePath
)
{
    HRESULT hr = S_OK;
    PCSTR pszConfigContent1 =
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
        "\r\n"
        "<configuration>\r\n"
        "\r\n"
        "    <configSections>\r\n"
        "        <sectionGroup name=\"system.applicationHost\">\r\n"
        "            <section name=\"applicationPools\" allowDefinition=\"AppHostOnly\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"customMetadata\" allowDefinition=\"AppHostOnly\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"listenerAdapters\" allowDefinition=\"AppHostOnly\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"log\" allowDefinition=\"AppHostOnly\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"sites\" allowDefinition=\"AppHostOnly\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"webLimits\" allowDefinition=\"AppHostOnly\" overrideModeDefault=\"Deny\" />\r\n"
        "        </sectionGroup>\r\n"
        "\r\n"
        "        <sectionGroup name=\"system.webServer\">\r\n"
        "            <section name=\"asp\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"caching\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"cgi\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"defaultDocument\" overrideModeDefault=\"Allow\" />\r\n"
        "            <section name=\"directoryBrowse\" overrideModeDefault=\"Allow\" />\r\n"
        "            <section name=\"globalModules\" allowDefinition=\"AppHostOnly\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"handlers\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"httpCompression\" allowDefinition=\"AppHostOnly\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"httpErrors\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"httpLogging\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"httpProtocol\" overrideModeDefault=\"Allow\" />\r\n"
        "            <section name=\"httpRedirect\" overrideModeDefault=\"Allow\" />\r\n"
        "            <section name=\"httpTracing\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"isapiFilters\" allowDefinition=\"MachineToApplication\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"modules\" allowDefinition=\"MachineToApplication\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"odbcLogging\" overrideModeDefault=\"Deny\" />\r\n"
        "            <sectionGroup name=\"security\">\r\n"
        "                <section name=\"access\" overrideModeDefault=\"Deny\" />\r\n"
        "                <section name=\"applicationDependencies\" overrideModeDefault=\"Deny\" />\r\n"
        "                <sectionGroup name=\"authentication\">\r\n"
        "                    <section name=\"anonymousAuthentication\" overrideModeDefault=\"Deny\" />\r\n"
        "                    <section name=\"basicAuthentication\" overrideModeDefault=\"Deny\" />\r\n"
        "                    <section name=\"clientCertificateMappingAuthentication\" overrideModeDefault=\"Deny\" />\r\n"
        "                    <section name=\"digestAuthentication\" overrideModeDefault=\"Deny\" />\r\n"
        "                    <section name=\"iisClientCertificateMappingAuthentication\" overrideModeDefault=\"Deny\" />\r\n"
        "                    <section name=\"windowsAuthentication\" overrideModeDefault=\"Deny\" />\r\n"
        "                </sectionGroup>\r\n"
        "                <section name=\"authorization\" overrideModeDefault=\"Deny\" />\r\n"
        "                <section name=\"ipSecurity\" overrideModeDefault=\"Deny\" />\r\n"
        "                <section name=\"isapiCgiRestriction\" allowDefinition=\"AppHostOnly\" overrideModeDefault=\"Deny\" />\r\n"
        "                <section name=\"requestFiltering\" overrideModeDefault=\"Deny\" />\r\n"
        "            </sectionGroup>\r\n"
        "            <section name=\"serverRuntime\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"serverSideInclude\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"staticContent\" overrideModeDefault=\"Deny\" />\r\n"
        "            <sectionGroup name=\"tracing\">\r\n"
        "                <section name=\"traceFailedRequests\" overrideModeDefault=\"Deny\" />\r\n"
        "                <section name=\"traceProviderDefinitions\" overrideModeDefault=\"Deny\" />\r\n"
        "            </sectionGroup>\r\n"
        "            <section name=\"urlCompression\" overrideModeDefault=\"Deny\" />\r\n"
        "            <section name=\"validation\" overrideModeDefault=\"Allow\" />\r\n"
        "        </sectionGroup>\r\n"
        "    </configSections>\r\n"
        "\r\n"
        "    <configProtectedData>\r\n"
        "        <providers>\r\n"
        "            <add name=\"IISWASOnlyRsaProvider\" type=\"\" description=\"Uses RsaCryptoServiceProvider to encrypt and decrypt\" keyContainerName=\"iisWasKey\" cspProviderName=\"\" useMachineContainer=\"true\" useOAEP=\"false\" />\r\n"
        "        </providers>\r\n"
        "    </configProtectedData>\r\n"
        "\r\n"
        "    <system.applicationHost>\r\n"
        "\r\n"
        "        <applicationPools>\r\n"
        "            <add name=\"MyAppPool\" />\r\n"
        "        </applicationPools>\r\n"
        "\r\n"
        "        <listenerAdapters>\r\n"
        "            <add name=\"http\" />\r\n"
        "        </listenerAdapters>\r\n"
        "\r\n"
        "        <sites>\r\n"
        "            <site name=\"My Web Site\" id=\"31212\">\r\n"
        "                <application path=\"/\">\r\n"
        "                    <virtualDirectory path=\"/\" physicalPath=\"%systemdrive%\\inetpub\\wwwroot\\\" />\r\n"
        "                </application>\r\n"
        "                <bindings>\r\n"
        "                    <binding protocol=\"http\" bindingInformation=\"*:";
   
    PCSTR pszConfigContent2 =
        ":\" />\r\n"
        "                </bindings>\r\n"
        "            </site>\r\n"
        "            <applicationDefaults applicationPool=\"MyAppPool\" />\r\n"
        "            <virtualDirectoryDefaults allowSubDirConfig=\"true\" />\r\n"
        "        </sites>\r\n"
        "\r\n"
        "    </system.applicationHost>\r\n"
        "\r\n"
        "    <system.webServer>\r\n"
        "\r\n"
        "        <globalModules>\r\n"
        "            <add name=\"GetMRegModule\" image=\"";

   
PCSTR pszConfigContent3 =
        "\" />\r\n"
        "        </globalModules>\r\n"
        "\r\n"
        "    </system.webServer>\r\n"
        "\r\n"
        "</configuration>\r\n";

   
//
    // Put port number in the config string
    //
    PSTR pszPort = NULL;
    pszPort = (PSTR)malloc(6 * sizeof(CHAR));
    _itoa(dwPort, pszPort, 10);
   
   PSTR pszConfigContent = NULL;
    pszConfigContent = (PSTR)malloc(
        strlen(pszConfigContent1) +
        strlen(pszPort) +
        strlen(pszConfigContent2) +
        strlen(pszModulePath) +
        strlen(pszConfigContent3) + 1);

    strcpy(pszConfigContent, pszConfigContent1);
    strcat(pszConfigContent, pszPort);
    strcat(pszConfigContent, pszConfigContent2);
    strcat(pszConfigContent, pszModulePath);
    strcat(pszConfigContent, pszConfigContent3);

    //
    // Write the contents to the temp config file
    //
    DWORD cbBytes;
    if(WriteFile(
        hConfigFile,
        pszConfigContent,
        strlen(pszConfigContent),
        &cbBytes,
        NULL) == 0)
    {
        wprintf(L"No bytes written to config file\r\nAborting\r\n");
        hr = E_FAIL;
        goto finished;
    }

finished:
    if(pszPort != NULL)
    {
        free(pszPort);
        pszPort = NULL;
    }
    if(pszConfigContent != NULL)
    {
        free(pszConfigContent);
        pszConfigContent = NULL;
    }

 

 
}
 

 

 

// Build this as a library and export RegisterModule
// Keep the name as GetMRegModule.dll (or change the name
// in other executable accordingly
//

#include "httpserv.h"
#include "http.h"
#include <stdio.h>
 class MyRegistrationProvider : IHttpModuleRegistrationInfo
{
public:
    MyRegistrationProvider(
        IHttpModuleRegistrationInfo *pModuleInfo
    )
    {
        _pModuleInfo    = pModuleInfo;
        _pModuleFactory = NULL;
        _pGlobalModule  = NULL;
    }

    ~MyRegistrationProvider()
    {
        if(_pModuleFactory != NULL)
        {
            _pModuleFactory->Terminate();
        }

        if(_pGlobalModule != NULL)
        {
            _pGlobalModule->Terminate();
        }
    }

    PCWSTR
    GetName(
        VOID
    ) const
    {
        return _pModuleInfo->GetName();
    }

    HTTP_MODULE_ID
    GetId(
        VOID
    ) const
    {
        return _pModuleInfo->GetId();
    }

    HRESULT
    SetRequestNotifications(
        IN IHttpModuleFactory * pModuleFactory,
        IN DWORD                dwRequestNotifications,
        IN DWORD                dwPostRequestNotifications
    )
    {
        //
        // Print request notifications
        //
        _pModuleFactory = pModuleFactory;
        wprintf(L"Request notifications\r\n");
        PrintRequestNotifications(dwRequestNotifications, dwPostRequestNotifications);
        wprintf(L"\r\n");

        //
        // Blindly return S_OK. We don’t actually want to
        // the notifications
        //
        return S_OK;
    }

    HRESULT
    SetGlobalNotifications(
        IN CGlobalModule *      pGlobalModule,
        IN DWORD                dwGlobalNotifications
    )
    {
        //
        // Print global notifications
        //
        _pGlobalModule = pGlobalModule;
        wprintf(L"Global notifications\r\n");
        PrintGlobalNotifications(dwGlobalNotifications);
        wprintf(L"\r\n");

        //
        // Blindly return S_OK
        //
        return S_OK;
    }

    HRESULT
    SetPriorityForRequestNotification(
        IN DWORD                dwRequestNotification,
        IN PCWSTR               pszPriority
    )
    {
        //
        // Print request notification priority information
        //
        wprintf(L"Setting priority for request notifications\r\n");
        PrintRequestNotifications(dwRequestNotification, 0);
        wprintf(L"%s\r\n", pszPriority);
        wprintf(L"\r\n");

        //
        // Blindly return S_OK
        //
        return S_OK;
    }

    HRESULT
    SetPriorityForGlobalNotification(
        IN DWORD                dwGlobalNotification,
        IN PCWSTR               pszPriority
    )
    {
        //
        // Print global notification priority information
        //
        wprintf(L"Setting priority for request notifications\r\n");
        PrintGlobalNotifications(dwGlobalNotification);
        wprintf(L"%s\r\n", pszPriority);
        wprintf(L"\r\n");

        //
        // Blindly return S_OK
        //
        return S_OK;
    }

private
:
    IHttpModuleRegistrationInfo * _pModuleInfo;
    IHttpModuleFactory          * _pModuleFactory;
    CGlobalModule               * _pGlobalModule;

    VOID PrintRequestNotifications(
        DWORD dwRequestNotifications,
        DWORD dwPostRequestNotifications
    );

    VOID PrintGlobalNotifications(
        DWORD dwGlobalNotifications
    );
};

VOID MyRegistrationProvider::PrintRequestNotifications(
    DWORD dwRequestNotifications,
    DWORD dwPostRequestNotifications
)
{
    DWORD count = 0;
    PCWSTR rnNames[16] = {
        L"RQ_BEGIN_REQUEST",
        L"RQ_AUTHENTICATE_REQUEST",
        L"RQ_AUTHORIZE_REQUEST",
        L"RQ_RESOLVE_REQUEST_CACHE",
        L"RQ_MAP_REQUEST_HANDLER",
        L"RQ_ACQUIRE_REQUEST_STATE",
        L"RQ_PRE_EXECUTE_REQUEST_HANDLER",
        L"RQ_EXECUTE_REQUEST_HANDLER",
        L"RQ_RELEASE_REQUEST_STATE",
        L"RQ_UPDATE_REQUEST_CACHE",
        L"RQ_LOG_REQUEST",
        L"RQ_END_REQUEST",
        L"RQ_MAP_PATH",
        L"RQ_READ_ENTITY",
        L"RQ_SEND_RESPONSE",
        L"RQ_CUSTOM_NOTIFICATION"
    };

    //
    // Print request registration information
    //
    for(DWORD i = 0; i <= 11; i++)
    {
        count = (1 << i);
        if((dwRequestNotifications & count) != 0)
        {
            wprintf(L"%s\r\n", rnNames[i]);
        }
    }

    //
    // Print asynchronous request registration information
    //
    for(DWORD i = 0; i <= 3; i++)
    {
        count = (1 << (31 – i));
        if((dwRequestNotifications & count) != 0)
        {
            wprintf(L"%s\r\n", rnNames[12 + i]);
        }
    }

    //
    // Print POST request registration information
    //
    for(DWORD i = 0; i <= 11; i++)
    {
        count = (1 << i);
        if((dwPostRequestNotifications & count) != 0)
        {
            wprintf(L"POST_%s\r\n", rnNames[i]);
        }
    }

    //
    // Print asynchronous POST request registration information
    //
    for(DWORD i = 0; i <= 3; i++)
    {
        count = (1 << (31 – i));
        if((dwPostRequestNotifications & count) != 0)
        {
            wprintf(L"POST_%s\r\n", rnNames[12 + i]);
        }
    }
}

VOID MyRegistrationProvider::PrintGlobalNotifications(
    DWORD dwGlobalNotifications
)
{
    DWORD count = 0;
    PCWSTR gnNames[16] = {
        L"",
        L"GL_STOP_LISTENING",
        L"GL_CACHE_CLEANUP",
        L"",
        L"GL_CACHE_OPERATION",
        L"GL_HEALTH_CHECK",
        L"GL_CONFIGURATION_CHANGE",
        L"GL_FILE_CHANGE",
        L"GL_PRE_BEGIN_REQUEST",
        L"GL_APPLICATION_START",
        L"GL_APPLICATION_RESOLVE_MODULES",
        L"GL_APPLICATION_STOP",
        L"GL_RSCA_QUERY",
        L"GL_TRACE_EVENT",
        L"GL_CUSTOM_NOTIFICATION",
        L"GL_THREAD_CLEANUP"
    };

    //
    // Print global registration information
    //
    for(DWORD i = 0; i <= 15; i++)
    {
        count = (1 << i);
        if((dwGlobalNotifications & count) != 0)
        {
            wprintf(L"%s\r\n", gnNames[i]);
        }
    }
}

HRESULT
RegisterModule(
    DWORD                           dwServerVersion,
    IHttpModuleRegistrationInfo *   pModuleInfo,
    IHttpServer *                   pGlobalInfo
)
{
    HRESULT hr = S_OK;

    //
    // Load another module
    //
    HINSTANCE hModule = NULL;
    PWSTR pszModulePath = NULL;
    DWORD dwSize = 0;

    //
    // Get the size of the buffer to be allocated
    //
    dwSize = GetEnvironmentVariable(
        L"MODULEPATH",
        pszModulePath,
        0);

    if(dwSize == 0)
    {
        wprintf(L"Environment variable MODULEPATH should point to module\r\n");
        goto finished;
    }

    //
    // Allocate buffer and call again
    //
    pszModulePath = (PWSTR)malloc(dwSize * sizeof(WCHAR));
    if(GetEnvironmentVariable(
        L"MODULEPATH",
        pszModulePath,
        dwSize) == 0)
    {
        wprintf(L"Error getting environment variable MODULEPATH\r\n");
        goto finished;
    }

    wprintf(L"Registration information for module %s\r\n\r\n", pszModulePath);

    //
    // Load the module whose registrations need to be found
    //
    hModule = LoadLibraryEx(
        pszModulePath,
        NULL,
        0);

    if(hModule == NULL)
    {
        wprintf(L"Couldn’t load module\r\n");
        wprintf(L"Aborting\r\n");
        goto finished;
    }

    //
    // Get RegisterModule entry point
    //
    PFN_REGISTERMODULE  pfnRegisterModule;
    pfnRegisterModule = (PFN_REGISTERMODULE)GetProcAddress(hModule, "RegisterModule" );

    if(pfnRegisterModule == NULL)
    {
        wprintf(L"RegisterModule entry point not found\r\n");
        wprintf(L"Aborting\r\n");
        goto finished;
    }

    //
    // Call register module now
    //
    MyRegistrationProvider * pRegProvider = new MyRegistrationProvider(pModuleInfo);

    hr = pfnRegisterModule(
        dwServerVersion,
        (IHttpModuleRegistrationInfo *)pRegProvider,
        pGlobalInfo);

    if(FAILED(hr))
    {
        wprintf(L"RegisterModule returned error\r\n");
        goto finished;
    }

finished:
    if(pRegProvider != NULL)
    {
        delete pRegProvider;
        pRegProvider = NULL;
    }

    if(hModule != NULL)
    {
        FreeLibrary(hModule);
        hModule = NULL;
    }

    if(pszModulePath != NULL)
    {
        free(pszModulePath);
        pszModulePath = NULL;
    }

    return S_OK;
}

Use attached GetMRegInstall.zip containing GetMRegInstall.exe to install the program.

-Kanwal

//
// Filename – module.cxx
//

 

    return hr;

    wcscpy(hwebcore, pszSystemDir);

 

Execution order of modules in IIS7

Each request received by IIS 7.0 goes through multiple stages in the IIS request pipeline (read more about request pipeline here). In IIS, request processing move from one stage to the next stage in a fixed sequence. If any of the modules in system.webServer/modules section have subscribed to the event for the current stage then IIS calls each of those modules one by one before moving on to next stage. If there are multiple modules which subscribe to the same event (say RQ_BEGIN_REQUEST), module with higher priority is called first. Native modules can set execution priority for itself in RegisterModule using SetPriorityForRequestNotification. The following code snippet illustrates this for RQ_BEGIN_REQUEST.

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

    HRESULT hr = S_OK;

    IHttpModuleFactory* pModuleFactory = NULL;
 
    // create module factory

    hr = pModuleInfo->SetRequestNotifications(pModuleFactory, RQ_BEGIN_REQUEST, 0 );
    // some stuff

    hr = pModuleInfo->SetPriorityForRequestNotification(
               
RQ_BEGIN_REQUEST,
                PRIORITY_ALIAS_FIRST);

    // more stuff
    return hr;
}

If multiple modules subscribe to the same event and set the same priority, the module that is listed first in the system.webServer/modules section gets executed first. RQ_EXECUTE_REQUEST_HANDLER is different in this respect as it picks up the ordering from system.webServer/handlers section. Taking the example of StaticFile handler entry from default IIS configuration which looks like the following

<add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />

IIS picks one handler for a request but each entry can have multiple modules executed which can appear as comma separated list as is the case for StaticFile handler. StaticFileModule, DefaultDocumentModule and DirectoryListingModule, all three subscribe to RQ_EXECUTE_HANDLER and use default priority. The default ordering of these modules is important to ensure they work correctly. Changing it can have undesirable effects. For example, putting DefaultDocumentModule before DirectoryListingModule will make DirectoryListingModule run first and if directoryBrowse is disabled, it will generate a 403.14 even before DefaultDocumentModule got a chance to check defaultDocument section and pick default file. DirectoryListingModule should execute only if defaultDocument is disabled and putting it after DefaultDocumentModule serve that purpose.

So IIS decides module execution order as following:

  1. Module which subscribe to an earlier pipeline stages execute before the modules which subscribe to a later stage.
  2. Among modules which subscribe for the same event, module with higher priority runs before module with lower priority. RQ_SEND_RESPONSE priority order is opposite of other notifications. Modules with RQ_SEND_RESPONSE priority LAST are run first, followed by priority LOW and so on. You cannot set priority of managed modules. All managed modules assume default priority.
  3. Among modules which subscribe for the same event and with same priority, module appearing first in system.webServer/modules section gets called first (RQ_EXECUTE_REQUEST_HANDLER stage is special and ordering is picked from system.webServer/handlers section and not from system.webServer/modules).

Global modules which subscribe only to global events can use IHttpModuleRegistrationInfo::SetPriorityForGlobalNotification for setting the priority. Step 3 for globalModules is based on ordering in system.webServer/globalModules section. For native modules which subscribe to only request events, ordering in system.webServer/globalModules section is immaterial (even though they appear in globalModules section). IIS just use the globalModules entry to load the module but calls only modules which appear in system.webServer/modules section.

-Kanwal