//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996-1999.
//
// File:        RegSrv.hxx
//
// Contents:    Macros for Self-registration of Filters
//
// Functions:   Macros to create DllRegisterServer, DllUnregisterServer
//
// History:     03-Jan-97       KyleP       Created from (CiAdmin version)
//
//----------------------------------------------------------------------------

#pragma once

#include <olectl.h>

//
// Structure to define classes (.doc, .xls, etc.)
//

struct SClassEntry
{
    WCHAR const * pwszExt;                  // (ex: .doc)  May be null
    WCHAR const * pwszShortName;            // (ex: Word.Document.8)
    WCHAR const * pwszDescription;          // (ex: Microsoft Word Document)
    WCHAR const * pwszClassId;              // (ex: {00020906-0000-0000-C000-000000000046})
    WCHAR const * pwszClassIdDescription;   // (ex: Microsoft Word Document)
};

//
// Structure to define persistent handler entry.
//

struct SHandlerEntry
{
    WCHAR const * pwszClassId;
    WCHAR const * pwszClassIdDescription;
    WCHAR const * pwszClassIdFilter;
};

//
// Structure to define filter class
//

struct SFilterEntry
{
    WCHAR const * pwszClassId;
    WCHAR const * pwszClassIdDescription;
    WCHAR const * pwszDLL;
    WCHAR const * pwszThreadingModel;
};

//
// Sample use of the three structures
//
//
// SClassEntry const aClasses[] = { { L".doc", L"Word.Document.8",
//                                    L"Microsoft Word Document",
//                                    L"{00020906-0000-0000-C000-000000000046}",
//                                    L"Microsoft Word Document" },
//
//                                  { 0, L"Word.Document.6",
//                                    L"Microsoft Word 6.0 - 7.0 Document",
//                                    L"{00020900-0000-0000-C000-000000000046}",
//                                    L"Microsoft Word 6.0 - 7.0 Document" }
//                                };
//
// SHandlerEntry const OfficeHandler = { L"{98de59a0-d175-11cd-a7bd-00006b827d94}",
//                                       L"Microsoft Office Persistent Handler",
//                                       L"{f07f3920-7b8c-11cf-9be8-00aa004b9986}" };
//
// SFilterEntry const OfficeFilter = { L"{f07f3920-7b8c-11cf-9be8-00aa004b9986}",
//                                     L"Microsoft Office Filter",
//                                     L"OffFilt.dll",
//                                     0 };
//

//
// Function prototypes
//

inline long RegisterACLSID( SClassEntry const & Class,
                            WCHAR const * pwszPHandler,
                            WCHAR const * pwszClassId = 0,
                            BOOL fAppendOnly = FALSE,
                            BOOL fAppendDesc = TRUE );

inline long RegisterAClass( SClassEntry const & Class,
                            WCHAR const * pwszPHandler,
                            WCHAR const * pwszShortName = 0,
                            BOOL fAppendOnly = FALSE );

inline long RegisterAClassAndExt( SClassEntry const & Class,
                                  WCHAR const * pwszPHandler,
                                  BOOL fAppendOnly = FALSE );

//+---------------------------------------------------------------------------
//
//  Function:   BuildKeyValues, private
//
//  Effects:    Given array of key, value, key, value, ... adds the entries
//              under CLSID as:
//
//                  Key1 : <NO NAME> Value1
//                    Key2 : <NO NAME> Value2
//                      :
//                      :
//
//  Arguments:  [awszKeyValues] -- Keys and values
//              [cKeyValues]    -- Number of entries in array.  Must be even.
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    05-Jan-97   KyleP       Created
//
//  Notes:      The *value* entries can be null, signifying no value at a
//              given level.
//
//----------------------------------------------------------------------------

inline long BuildKeyValues( WCHAR const * const * awszKeyValues, unsigned cKeyValues )
{
    WCHAR wcTemp[MAX_PATH];
    wcscpy( wcTemp, L"CLSID" );

    long dwError;
    HKEY hKey = (HKEY)INVALID_HANDLE_VALUE;
    unsigned i = 0;

    do
    {
        if ( INVALID_HANDLE_VALUE != hKey )
        {
            RegCloseKey( hKey );
            hKey = (HKEY)INVALID_HANDLE_VALUE;
        }

        wcscat( wcTemp, L"\\" );
        wcscat( wcTemp, awszKeyValues[i] );

        DWORD  dwDisposition;

        dwError = RegCreateKeyExW( HKEY_CLASSES_ROOT,    // Root
                                   wcTemp,               // Sub key
                                   0,                    // Reserved
                                   0,                    // Class
                                   0,                    // Flags
                                   KEY_ALL_ACCESS,       // Access
                                   0,                    // Security
                                   &hKey,                // Handle
                                   &dwDisposition );     // Disposition

        if ( ERROR_SUCCESS != dwError )
            break;

        i++;

        if ( 0 != awszKeyValues[i] )
            dwError = RegSetValueExW( hKey,                     // Key
                                      0,                        // Name
                                      0,                        // Reserved
                                      REG_SZ,                   // Type
                                      (BYTE *)awszKeyValues[i], // Value
                                      (1 + wcslen(awszKeyValues[i]) ) * sizeof(WCHAR) );

        if ( ERROR_SUCCESS != dwError )
            break;

        i++;
    }
    while ( i < cKeyValues );

    if ( (HKEY)INVALID_HANDLE_VALUE != hKey )
        RegCloseKey( hKey );

    return dwError;
}

//+---------------------------------------------------------------------------
//
//  Function:   AddThreadingModel
//
//  Synopsis:   Adds the threading model value to the CLSID\\GUID\\InProcServer32
//              key
//
//  Arguments:  [wszClsId] - ClassId of the inproc server.
//              [wszThreadingModel] -- 0 (for single threaded) or one of
//                                     Apartment, Free, or Both
//
//  History:    3-07-97   srikants   Created
//
//----------------------------------------------------------------------------

inline long AddThreadingModel( WCHAR const * wszClsId,
                               WCHAR const * wszThreadingModel )
{
    WCHAR wcTemp[MAX_PATH];
    wcscpy( wcTemp, L"CLSID" );
    wcscat( wcTemp, L"\\" );
    wcscat( wcTemp, wszClsId );
    wcscat( wcTemp, L"\\" );
    wcscat( wcTemp, L"InprocServer32" );

    long dwError;
    HKEY hKey = (HKEY)INVALID_HANDLE_VALUE;
    unsigned i = 0;

    dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                             wcTemp,               // Sub key
                             0,                    // Reserved
                             KEY_ALL_ACCESS,       // Access
                             &hKey );              // Handle

    if ( ERROR_SUCCESS != dwError )
        return dwError;

    if ( 0 != wszThreadingModel )
        dwError = RegSetValueExW( hKey,                   // Key
                                  L"ThreadingModel",      // Name
                                  0,                      // Reserved
                                  REG_SZ,                 // Type
                                  (BYTE *) wszThreadingModel,  // Value
                                  (wcslen(wszThreadingModel) + 1) * sizeof WCHAR );
    else
        RegDeleteValueW( hKey,                   // Key
                         L"ThreadingModel" );    // Name

    if ( (HKEY)INVALID_HANDLE_VALUE != hKey )
        RegCloseKey( hKey );

    return dwError;
}

//+---------------------------------------------------------------------------
//
//  Function:   DestroyKeyValues, private
//
//  Effects:    Given array of key, value, key, value from AddKeyValues,
//              removes the keys.
//
//  Arguments:  [awszKeyValues] -- Keys and values
//              [cKeyValues]    -- Number of entries in array.  Must be even.
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    05-Jan-97   KyleP       Created
//
//----------------------------------------------------------------------------

inline long DestroyKeyValues( WCHAR const * const * awszKeyValues, int cKeyValues )
{
    WCHAR wcTemp[MAX_PATH];

    //
    // Build path to deepest component
    //

    wcscpy( wcTemp, L"CLSID" );
    int i = 0;

    do
    {
        wcscat( wcTemp, L"\\" );
        wcscat( wcTemp, awszKeyValues[i] );

        i += 2;
    }
    while ( i < cKeyValues );

    //
    // Remove components in reverse order
    //

    long dwError;
    HKEY hKey = (HKEY)INVALID_HANDLE_VALUE;

    unsigned cc = wcslen( wcTemp );

    for ( i -= 2; i >= 0; i -= 2 )
    {
        dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                 wcTemp,               // Sub key
                                 0,                    // Reserved
                                 KEY_ALL_ACCESS,       // Access
                                 &hKey );              // Handle

        if ( ERROR_SUCCESS != dwError )
            break;

        #if 0  // Values deleted by RegDeleteKeyW
        //
        // Delete value, if there is one.
        //

        if ( 0 != awszKeyValues[i+1] )
            dwError = RegDeleteValueW( hKey, 0 );

        if ( ERROR_SUCCESS != dwError )
            break;
        #endif // 0

        //
        // Delete subkey, if there is one.
        //

        if ( i+2 < cKeyValues )
            dwError = RegDeleteKeyW( hKey, awszKeyValues[i+2] );

        if ( ERROR_SUCCESS != dwError )
            break;

        //
        // Close key and truncate string to next component.
        //

        if ( INVALID_HANDLE_VALUE != hKey )
        {
            RegCloseKey( hKey );
            hKey = (HKEY)INVALID_HANDLE_VALUE;
        }

        cc -= wcslen( awszKeyValues[i] );
        cc --;

        wcTemp[cc] = 0;
    }

    //
    // Remove the final top key
    //

    if ( ERROR_SUCCESS == dwError )
    {
        do
        {
            dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                     wcTemp,               // Sub key -- "CLSID"
                                     0,                    // Reserved
                                     KEY_ALL_ACCESS,       // Access
                                     &hKey );              // Handle

            if ( ERROR_SUCCESS != dwError )
                break;

            //
            // Delete subkey
            //

            dwError = RegDeleteKeyW( hKey, awszKeyValues[0] );

        } while ( FALSE );
    }

    return dwError;
}

//+---------------------------------------------------------------------------
//
//  Function:   RegisterAClassAndExt, private
//
//  Synopsis:   Registers a class, extensions (optional) and a persistent handler.
//
//  Arguments:  [Class]        -- Class description
//              [pwszPHandler] -- Persistent handler for class
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    05-Jan-97   KyleP       Created
//
//  Notes:      Class is only registered if similar class does not already
//              exist.  Persistent handler is always registered for class.
//
//----------------------------------------------------------------------------

inline long RegisterAClassAndExt( SClassEntry const & Class,
                                  WCHAR const * pwszPHandler,
                                  BOOL fAppendOnly )
{
    WCHAR wcTemp[MAX_PATH];

    long dwError = NO_ERROR;
    HKEY  hKey = (HKEY)INVALID_HANDLE_VALUE;

    do
    {
        //
        // First, the optional extension entry
        //

        DWORD dwDisposition;
        DWORD dwType;
        DWORD dwSize;

        if ( 0 == Class.pwszExt )
        {
            //
            // Build up named entry
            //

            wcscpy( wcTemp, Class.pwszShortName );
        }
        else
        {
            wcscpy( wcTemp, Class.pwszExt );

            dwError = RegCreateKeyExW( HKEY_CLASSES_ROOT,    // Root
                                       wcTemp,               // Sub key
                                       0,                    // Reserved
                                       0,                    // Class
                                       0,                    // Flags
                                       KEY_ALL_ACCESS,       // Access
                                       0,                    // Security
                                       &hKey,                // Handle
                                       &dwDisposition );     // Disposition
            if ( ERROR_SUCCESS != dwError )
                break;

            //
            // Write or read class association
            //

            BOOL fSetValue = TRUE;

            if ( REG_OPENED_EXISTING_KEY == dwDisposition )
            {
                dwSize = sizeof(wcTemp);

                dwError = RegQueryValueExW( hKey,            // Key handle
                                            0,               // Name
                                            0,               // Reserved
                                            &dwType,         // Datatype
                                            (BYTE *)wcTemp,  // Data returned here
                                            &dwSize );       // Size of data

                if ( ERROR_SUCCESS == dwError )
                {
                    fSetValue = FALSE;

                    if ( REG_SZ != dwType )
                        dwError = E_FAIL;
                }
                else if ( ERROR_FILE_NOT_FOUND == dwError )
                {
                    //
                    // This is ok, but we need to remember that the
                    // combination of wcTemp[0] == 0 && fAppendOnly means
                    // don't try to register the class.
                    //

                    wcTemp[0] = 0;
                    dwError = ERROR_SUCCESS;
                }
            }

            if ( fSetValue && !fAppendOnly )
            {
                dwError = RegSetValueExW( hKey,                        // Key
                                          0,                           // Name
                                          0,                           // Reserved
                                          REG_SZ,                      // Type
                                          (BYTE *)Class.pwszShortName, // Value
                                          (1 + wcslen(Class.pwszShortName) ) * sizeof(WCHAR) );

                wcTemp[0] = 0;
            }

            if ( ERROR_SUCCESS != dwError )
                break;

            //
            // Write the persistent handler key
            //

            HKEY hKey2 = (HKEY)INVALID_HANDLE_VALUE;

            dwError = RegCreateKeyExW( hKey,                 // Root
                                       L"PersistentHandler", // Sub key
                                       0,                    // Reserved
                                       0,                    // Class
                                       0,                    // Flags
                                       KEY_ALL_ACCESS,       // Access
                                       0,                    // Security
                                       &hKey2,               // Handle
                                       &dwDisposition );     // Disposition

            if ( ERROR_SUCCESS != dwError )
                break;

            dwError = RegSetValueExW( hKey2,                 // Key
                                      0,                     // Name
                                      0,                     // Reserved
                                      REG_SZ,                // Type
                                      (BYTE *)pwszPHandler,  // Value
                                      (1 + wcslen(pwszPHandler) ) * sizeof(WCHAR) );

            if ( (HKEY)INVALID_HANDLE_VALUE != hKey2 )
            {
                RegCloseKey( hKey2 );
                hKey2 = (HKEY)INVALID_HANDLE_VALUE;
            }
        }

        if ( (HKEY)INVALID_HANDLE_VALUE != hKey )
        {
            RegCloseKey( hKey );
            hKey = (HKEY)INVALID_HANDLE_VALUE;
        }

        if ( ERROR_SUCCESS != dwError )
            break;

        //
        // Here, wcTemp may contain the key name for the named entry (ex: Word.Document.8)
        //

        if ( wcTemp[0] != 0 || !fAppendOnly )
            dwError = RegisterAClass( Class, pwszPHandler, (0 == wcTemp[0]) ? 0 : wcTemp, fAppendOnly );

    } while( FALSE );

    if ( (HKEY)INVALID_HANDLE_VALUE != hKey )
    {
        RegCloseKey( hKey );
        hKey = (HKEY)INVALID_HANDLE_VALUE;
    }

    return dwError;
}

//+---------------------------------------------------------------------------
//
//  Function:   RegisterAClass, private
//
//  Synopsis:   Registers a class and a persistent handler.
//
//  Arguments:  [Class]        -- Class description
//              [pwszPHandler] -- Persistent handler for class
//              [pwszClass]    -- If non 0, used instead of class from [Class]
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    12-Feb-97   KyleP       Created
//
//  Notes:      Class is only registered if similar class does not already
//              exist.  Persistent handler is always registered for class.
//
//----------------------------------------------------------------------------

inline long RegisterAClass( SClassEntry const & Class,
                            WCHAR const * pwszPHandler,
                            WCHAR const * pwszShortName,
                            BOOL fAppendOnly )
{
    WCHAR wcTemp[MAX_PATH];

    long dwError;
    HKEY  hKey = (HKEY)INVALID_HANDLE_VALUE;

    if ( 0 == pwszShortName )
        wcscpy( wcTemp, Class.pwszShortName );
    else
        wcscpy( wcTemp, pwszShortName );

    do
    {
        DWORD dwDisposition;
        DWORD dwType;
        DWORD dwSize;

        //
        // Here, wcTemp contains the key name for the named entry (ex: Word.Document.8)
        //

        if ( fAppendOnly )
        {
            dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                     wcTemp,               // Sub key
                                     0,                    // Reserved
                                     KEY_ALL_ACCESS,       // Access
                                     &hKey );              // Handle

            if ( ERROR_SUCCESS != dwError)
            {
                //
                // Not opening the key at all is legit.
                //

                if ( ERROR_FILE_NOT_FOUND == dwError )
                    dwError = ERROR_SUCCESS;

                break;
            }

            dwDisposition = REG_OPENED_EXISTING_KEY;
        }
        else
        {
            dwError = RegCreateKeyExW( HKEY_CLASSES_ROOT,    // Root
                                       wcTemp,               // Sub key
                                       0,                    // Reserved
                                       0,                    // Class
                                       0,                    // Flags
                                       KEY_ALL_ACCESS,       // Access
                                       0,                    // Security
                                       &hKey,                // Handle
                                       &dwDisposition );     // Disposition

            if ( ERROR_SUCCESS != dwError )
                break;
        }

        //
        // If needed, write the description, but only for non-overrides.
        //

        if ( REG_CREATED_NEW_KEY == dwDisposition && 0 == pwszShortName )
        {
            dwError = RegSetValueExW( hKey,                          // Key
                                      0,                             // Name
                                      0,                             // Reserved
                                      REG_SZ,                        // Type
                                      (BYTE *)Class.pwszDescription, // Value
                                      (1 + wcslen(Class.pwszDescription) ) * sizeof(WCHAR) );

            wcscpy( wcTemp, Class.pwszShortName );

            if ( ERROR_SUCCESS != dwError )
                break;
        }

        if ( (HKEY)INVALID_HANDLE_VALUE != hKey )
        {
            RegCloseKey( hKey );
            hKey = (HKEY)INVALID_HANDLE_VALUE;
        }

        //
        // Write or read ClassId
        //

        wcscat( wcTemp, L"\\CLSID" );

        if ( fAppendOnly )
        {
            dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                     wcTemp,               // Sub key
                                     0,                    // Reserved
                                     KEY_ALL_ACCESS,       // Access
                                     &hKey );              // Handle

            if ( ERROR_SUCCESS != dwError)
            {
                //
                // Not opening the key at all is legit.
                //

                if ( ERROR_FILE_NOT_FOUND == dwError )
                    dwError = ERROR_SUCCESS;

                break;
            }

            dwDisposition = REG_OPENED_EXISTING_KEY;
        }
        else
        {
            dwError = RegCreateKeyExW( HKEY_CLASSES_ROOT,    // Root
                                       wcTemp,               // Sub key
                                       0,                    // Reserved
                                       0,                    // Class
                                       0,                    // Flags
                                       KEY_ALL_ACCESS,       // Access
                                       0,                    // Security
                                       &hKey,                // Handle
                                       &dwDisposition );     // Disposition

            if ( ERROR_SUCCESS != dwError )
                break;
        }

        dwSize = sizeof(wcTemp);

        dwError = RegQueryValueExW( hKey,                // Key handle
                                    0,                   // Name
                                    0,                   // Reserved
                                    &dwType,             // Datatype
                                    (BYTE *)(wcTemp),    // Data returned here
                                    &dwSize );           // Size of data

        if ( ERROR_SUCCESS != dwError )
        {
            if ( ERROR_FILE_NOT_FOUND == dwError )
            {
                //
                // Don't set a class id in append mode.
                //

                if ( fAppendOnly )
                {
                    dwError = ERROR_SUCCESS;
                    break;
                }

                dwError = RegSetValueExW( hKey,                          // Key
                                          0,                             // Name
                                          0,                             // Reserved
                                          REG_SZ,                        // Type
                                          (BYTE *)Class.pwszClassId,     // Value
                                          (1 + wcslen(Class.pwszClassId) ) * sizeof(WCHAR) );

                wcTemp[0] = 0; // Default to class from Class structure

                if ( ERROR_SUCCESS != dwError )
                    break;
            }
            else
                break;
        }
        else
        {
            if ( REG_SZ != dwType )
                dwError = E_FAIL;
        }

        if ( (HKEY)INVALID_HANDLE_VALUE != hKey )
        {
            RegCloseKey( hKey );
            hKey = (HKEY)INVALID_HANDLE_VALUE;
        }

        if ( ERROR_SUCCESS != dwError )
            break;

        //
        // Here, wcTemp contains the {class id} (ex: CLSID\{00020906-0000-0000-C000-000000000046})
        //

        dwError = RegisterACLSID( Class, pwszPHandler, (0 == wcTemp[0]) ? 0 : wcTemp, fAppendOnly );

    } while( FALSE );

    if ( (HKEY)INVALID_HANDLE_VALUE != hKey )
    {
        RegCloseKey( hKey );
        hKey = (HKEY)INVALID_HANDLE_VALUE;
    }

    return dwError;
}

//+---------------------------------------------------------------------------
//
//  Function:   RegisterACLSID, private
//
//  Synopsis:   Registers a CLSID / persistent handler.
//
//  Arguments:  [Class]        -- Class description
//              [pwszPHandler] -- Persistent handler for class
//              [pwszClassId]  -- If non 0, used instead of class id from [Class]
//              [fAppendOnly]  -- TRUE --> CLSID should not be created
//              [fAppendDesc]  -- TRUE --> Class description should be added.
//                                         Only applies if [fAppendOnly] is FALSE
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    12-Feb-97   KyleP       Created
//
//  Notes:      Class id is only registered if similar class does not already
//              exist.  Persistent handler is always registered for class.
//
//----------------------------------------------------------------------------

inline long RegisterACLSID( SClassEntry const & Class,
                            WCHAR const * pwszPHandler,
                            WCHAR const * pwszClassId,
                            BOOL fAppendOnly,
                            BOOL fAppendDesc )
{
    WCHAR wcTemp[MAX_PATH];

    long dwError;
    HKEY  hKey = (HKEY)INVALID_HANDLE_VALUE;

    wcscpy( wcTemp, L"CLSID\\" );

    if ( 0 == pwszClassId )
        wcscat( wcTemp, Class.pwszClassId );
    else
        wcscat( wcTemp, pwszClassId );

    do
    {
        DWORD dwDisposition;

        //
        // Here, wcTemp contains the CLSID\{class id} (ex: CLSID\{00020906-0000-0000-C000-000000000046})
        //

        if ( fAppendOnly )
        {
            dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                     wcTemp,               // Sub key
                                     0,                    // Reserved
                                     KEY_ALL_ACCESS,       // Access
                                     &hKey );              // Handle

            if ( ERROR_SUCCESS != dwError)
            {
                //
                // Not opening the key at all is legit.
                //

                if ( ERROR_FILE_NOT_FOUND == dwError )
                    dwError = ERROR_SUCCESS;

                break;
            }

            dwDisposition = REG_OPENED_EXISTING_KEY;
        }
        else
        {
            dwError = RegCreateKeyExW( HKEY_CLASSES_ROOT,    // Root
                                       wcTemp,               // Sub key
                                       0,                    // Reserved
                                       0,                    // Class
                                       0,                    // Flags
                                       KEY_ALL_ACCESS,       // Access
                                       0,                    // Security
                                       &hKey,                // Handle
                                       &dwDisposition );     // Disposition
        }

        if ( ERROR_SUCCESS != dwError )
            break;

        //
        // If needed, write the description, but not for override class.
        //

        if ( REG_CREATED_NEW_KEY == dwDisposition && 0 == pwszClassId && fAppendDesc )
        {
            dwError = RegSetValueExW( hKey,                                 // Key
                                      0,                                    // Name
                                      0,                                    // Reserved
                                      REG_SZ,                               // Type
                                      (BYTE *)Class.pwszClassIdDescription, // Value
                                      (1 + wcslen(Class.pwszClassIdDescription) ) * sizeof(WCHAR) );

            if ( ERROR_SUCCESS != dwError )
                break;
        }

        if ( (HKEY)INVALID_HANDLE_VALUE != hKey )
        {
            RegCloseKey( hKey );
            hKey = (HKEY)INVALID_HANDLE_VALUE;
        }

        //
        // Always write persistent handler.
        //

        wcscat( wcTemp, L"\\PersistentHandler" );

        dwError = RegCreateKeyExW( HKEY_CLASSES_ROOT,    // Root
                                   wcTemp,               // Sub key
                                   0,                    // Reserved
                                   0,                    // Class
                                   0,                    // Flags
                                   KEY_ALL_ACCESS,       // Access
                                   0,                    // Security
                                   &hKey,                // Handle
                                   &dwDisposition );     // Disposition

        if ( ERROR_SUCCESS != dwError )
            break;

        dwError = RegSetValueExW( hKey,                  // Key
                                  0,                     // Name
                                  0,                     // Reserved
                                  REG_SZ,                // Type
                                  (BYTE *)pwszPHandler,  // Value
                                  (1 + wcslen(pwszPHandler) ) * sizeof(WCHAR) );

    } while( FALSE );

    if ( (HKEY)INVALID_HANDLE_VALUE != hKey )
    {
        RegCloseKey( hKey );
        hKey = (HKEY)INVALID_HANDLE_VALUE;
    }

    return dwError;
}

//+---------------------------------------------------------------------------
//
//  Function:   RemoveAClassName, private
//
//  Synopsis:   Removes all references to class name (ex: Word.Document.8)
//
//  Arguments:  [pwszClass] -- Class Name
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    05-Jan-97   KyleP       Created
//
//----------------------------------------------------------------------------

inline long RemoveAClassName( WCHAR * pwszClass )
{
    //
    // First, delete class name entry.
    //

    long dwEnum = ERROR_SUCCESS;   // The enumerator
    long dwIgnore;                 // For non-fatal errors

    HKEY hKeyEnum = (HKEY)INVALID_HANDLE_VALUE;

    long dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                  0,                    // Sub key
                                  0,                    // Reserved
                                  KEY_ALL_ACCESS,       // Access
                                  &hKeyEnum );          // Handle


    if ( ERROR_SUCCESS == dwError )
    {
        dwIgnore = RegDeleteKeyW( hKeyEnum, pwszClass );

        //
        // Now enumerate all classes entries, looking for the clsid
        //

        DWORD dwIndex = 0;

        while ( ERROR_SUCCESS == dwEnum )
        {
            WCHAR wcTemp[MAX_PATH];
            DWORD dwSize = sizeof(wcTemp)/sizeof(wcTemp[0]);
            FILETIME ftUnused;

            dwEnum = RegEnumKeyExW( hKeyEnum,               // Handle of key
                                    dwIndex,                // Index of registry subkey
                                    wcTemp,                 // Buffer for name
                                    &dwSize,                // Size of buffer / key
                                    0,                      // Reserved
                                    0,                      // Class (unused)
                                    0,                      // Class size (unused)
                                    &ftUnused );            // Filetime (unused)

            dwIndex++;

            if ( ERROR_SUCCESS == dwEnum )
            {
                HKEY hKey;

                dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                         wcTemp,               // Sub key
                                         0,                    // Reserved
                                         KEY_ALL_ACCESS,       // Access
                                         &hKey );              // Handle

                if ( ERROR_SUCCESS == dwError )
                {
                    WCHAR wcTemp2[MAX_PATH];
                    DWORD dwType;

                    dwSize = sizeof(wcTemp2);

                    dwError = RegQueryValueExW( hKey,                // Key handle
                                                0,                   // Name
                                                0,                   // Reserved
                                                &dwType,             // Datatype
                                                (BYTE *)wcTemp2,     // Data returned here
                                                &dwSize );           // Size of data

                    RegCloseKey( hKey );

                    if ( ERROR_SUCCESS == dwError && 0 == _wcsicmp( wcTemp2, pwszClass ) )
                    {
                        //
                        // Always delete the value
                        //

                        if ( ERROR_SUCCESS == dwIgnore )
                            dwIgnore = RegDeleteValueW( hKey, 0 );
                        else
                            RegDeleteValueW( hKey, 0 );

                        //
                        // Any other key(s)?
                        //

                        dwSize = sizeof(wcTemp);

                        DWORD dw2 = RegEnumKeyExW( hKey,                   // Handle of key
                                                   0,                      // Index of registry subkey
                                                   wcTemp,                 // Buffer for name
                                                   &dwSize,                // Size of buffer / key
                                                   0,                      // Reserved
                                                   0,                      // Class (unused)
                                                   0,                      // Class size (unused)
                                                   &ftUnused );            // Filetime (unused)

                        if ( ERROR_NO_MORE_ITEMS == dw2 )
                        {
                            if ( ERROR_SUCCESS == dwIgnore )
                                dwIgnore = RegDeleteKeyW( hKeyEnum, wcTemp );
                            else
                                RegDeleteKeyW( hKeyEnum, wcTemp );

                            dwIndex = 0;
                        }

                    }
                    else
                        dwError = ERROR_SUCCESS;  // Just didn't have a null key (or no match)
                }
            }
        }
    }

    if ( ERROR_NO_MORE_ITEMS != dwEnum )
        dwError = dwEnum;

    if ( ERROR_SUCCESS != dwError )
        return dwError;
    else
        return dwIgnore;
}

//+---------------------------------------------------------------------------
//
//  Function:   RemoveAClass, private
//
//  Synopsis:   Removes all references to class
//
//  Arguments:  [pwszClass] -- Class
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    05-Jan-97   KyleP       Created
//
//----------------------------------------------------------------------------

inline long RemoveAClass( WCHAR * pwszClassId )
{
    //
    // First, delete class entry.
    //

    long dwIgnore;                // For non-fatal errors
    long dwEnum = ERROR_SUCCESS;  // For enumerator

    HKEY hKeyEnum = (HKEY)INVALID_HANDLE_VALUE;

    long dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                  L"CLSID",             // Sub key
                                  0,                    // Reserved
                                  KEY_ALL_ACCESS,       // Access
                                  &hKeyEnum );          // Handle

    if ( ERROR_SUCCESS == dwError )
    {
        dwIgnore = RegDeleteKeyW( hKeyEnum, pwszClassId );

        RegCloseKey( hKeyEnum );

        long dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                      0,                    // Sub key
                                      0,                    // Reserved
                                      KEY_ALL_ACCESS,       // Access
                                      &hKeyEnum );          // Handle
    }

    if ( ERROR_SUCCESS == dwError )
    {
        //
        // Now enumerate all classes entries, looking for the clsid
        //

        DWORD dwIndex = 0;

        while ( ERROR_SUCCESS == dwEnum )
        {
            WCHAR wcTemp[MAX_PATH];
            DWORD dwSize = sizeof(wcTemp)/sizeof(wcTemp[0]);
            FILETIME ftUnused;

            dwEnum = RegEnumKeyExW( hKeyEnum,               // Handle of key
                                    dwIndex,                // Index of registry subkey
                                    wcTemp,                 // Buffer for name
                                    &dwSize,                // Size of buffer / key
                                    0,                      // Reserved
                                    0,                      // Class (unused)
                                    0,                      // Class size (unused)
                                    &ftUnused );            // Filetime (unused)

            dwIndex++;

            if ( ERROR_SUCCESS == dwEnum )
            {
                wcscat( wcTemp, L"\\CLSID" );

                HKEY hKey;

                dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                         wcTemp,               // Sub key
                                         0,                    // Reserved
                                         KEY_ALL_ACCESS,       // Access
                                         &hKey );              // Handle

                if ( ERROR_SUCCESS == dwError )
                {
                    WCHAR wcTemp2[MAX_PATH];
                    DWORD dwType;

                    dwSize = sizeof(wcTemp2);

                    dwError = RegQueryValueExW( hKey,                // Key handle
                                                0,                   // Name
                                                0,                   // Reserved
                                                &dwType,             // Datatype
                                                (BYTE *)wcTemp2,     // Data returned here
                                                &dwSize );           // Size of data

                    RegCloseKey( hKey );

                    if ( ERROR_SUCCESS == dwError && 0 == _wcsicmp( wcTemp2, pwszClassId ) )
                    {
                        wcTemp[ wcslen(wcTemp) - wcslen( L"\\CLSID" ) ] = 0;

                        dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                                 wcTemp,               // Sub key
                                                 0,                    // Reserved
                                                 KEY_ALL_ACCESS,       // Access
                                                 &hKey );              // Handle

                        if ( ERROR_SUCCESS == dwError )
                        {
                            if ( ERROR_SUCCESS == dwIgnore )
                                dwIgnore = RegDeleteKeyW( hKey, L"CLSID" );
                            else
                                RegDeleteKeyW( hKey, L"CLSID" );

                            dwIndex = 0;
                        }

                        //
                        // If there are no more entries, then the class name can be deleted
                        //

                        dwSize = sizeof(wcTemp)/sizeof(wcTemp[0]);

                        long dw2 = RegEnumKeyExW( hKey,               // Handle of key
                                                  0,                  // Index of registry subkey
                                                  wcTemp,             // Buffer for name
                                                  &dwSize,            // Size of buffer / key
                                                  0,                  // Reserved
                                                  0,                  // Class (unused)
                                                  0,                  // Class size (unused)
                                                  &ftUnused );        // Filetime (unused)

                        RegCloseKey( hKey );

                        if ( ERROR_NO_MORE_ITEMS == dw2 )
                            RemoveAClassName( wcTemp );
                    }
                }
                else
                    dwError = ERROR_SUCCESS;  // Just didn't have CLSID
            }
        }
    }

    if ( ERROR_NO_MORE_ITEMS != dwEnum )
        dwError = dwEnum;

    if ( ERROR_SUCCESS != dwError )
        return dwError;
    else
        return dwIgnore;
}

//+---------------------------------------------------------------------------
//
//  Function:   RegisterAHandler, private
//
//  Synopsis:   Registers a persistent handler in registry
//
//  Arguments:  [Handler] -- Persistent handler
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    05-Jan-97   KyleP       Created
//
//----------------------------------------------------------------------------

inline long RegisterAHandler( SHandlerEntry const & Handler )
{
    WCHAR const * aKeyValues[6] = { Handler.pwszClassId,
                                    Handler.pwszClassIdDescription,
                                    L"PersistentAddinsRegistered",
                                    0,
                                    L"{89BCB740-6119-101A-BCB7-00DD010655AF}",  // IID_IFilter
                                    Handler.pwszClassIdFilter };

    return BuildKeyValues( aKeyValues, sizeof(aKeyValues)/sizeof(aKeyValues[0]) );
}

//+---------------------------------------------------------------------------
//
//  Function:   RegisterAFilter, private
//
//  Synopsis:   Registers a filter in registry
//
//  Arguments:  [Filter] -- IFilter implementation
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    05-Jan-97   KyleP       Created
//
//----------------------------------------------------------------------------

inline long RegisterAFilter( SFilterEntry const & Filter )
{
    WCHAR const * aKeyValues[4] = { Filter.pwszClassId,
                                    Filter.pwszClassIdDescription,
                                    L"InprocServer32",
                                    Filter.pwszDLL };

    long retVal = BuildKeyValues( aKeyValues, sizeof(aKeyValues)/sizeof(aKeyValues[0]) );
    if ( ERROR_SUCCESS == retVal )
        retVal = AddThreadingModel( Filter.pwszClassId, Filter.pwszThreadingModel );

    return retVal;
}

//+---------------------------------------------------------------------------
//
//  Function:   UnRegisterAHandler, private
//
//  Synopsis:   Unregisters a persistent handler, including class entries.
//
//  Arguments:  [Handler] -- Persistent handler
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    05-Jan-97   KyleP       Created
//
//----------------------------------------------------------------------------

inline long UnRegisterAHandler( SHandlerEntry const & Handler )
{
    WCHAR const * aKeyValues[6] = { Handler.pwszClassId,
                                    Handler.pwszClassIdDescription,
                                    L"PersistentAddinsRegistered",
                                    0,
                                    L"{89BCB740-6119-101A-BCB7-00DD010655AF}",  // IID_IFilter
                                    Handler.pwszClassIdFilter };

    //
    // dwIgnore is used to record non-fatal errors
    //

    long dwIgnore = DestroyKeyValues( aKeyValues, sizeof(aKeyValues)/sizeof(aKeyValues[0]) );
    long dwError = ERROR_SUCCESS;

    //
    // Now, enumerate all classes and delete any persistent handler entries.
    //

    HKEY hKeyEnum = (HKEY)INVALID_HANDLE_VALUE;

    long dwEnum = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                 L"CLSID",              // Sub key
                                 0,                    // Reserved
                                 KEY_ALL_ACCESS,       // Access
                                 &hKeyEnum );          // Handle

    DWORD dwIndex = 0;

    while ( ERROR_SUCCESS == dwEnum )
    {
        WCHAR wcTemp[MAX_PATH];

        wcscpy( wcTemp, L"CLSID\\" );
        unsigned cc = wcslen( wcTemp );

        DWORD dwSize = sizeof(wcTemp)/sizeof(wcTemp[0]) - cc;
        FILETIME ftUnused;

        dwEnum = RegEnumKeyExW( hKeyEnum,               // Handle of key
                                dwIndex,                // Index of registry subkey
                                wcTemp + cc,            // Buffer for name
                                &dwSize,                // Size of buffer / key
                                0,                      // Reserved
                                0,                      // Class (unused)
                                0,                      // Class size (unused)
                                &ftUnused );            // Filetime (unused)

        dwIndex++;

        //
        // Does the key have a persistent handler?
        //

        if ( ERROR_SUCCESS == dwEnum )
        {
            wcscat( wcTemp, L"\\PersistentHandler" );

            HKEY hKey;

            dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                     wcTemp,               // Sub key
                                     0,                    // Reserved
                                     KEY_ALL_ACCESS,       // Access
                                     &hKey );              // Handle

            if ( ERROR_SUCCESS == dwError )
            {
                //
                // Is this the persistent handler we're looking for?
                //

                WCHAR wcTemp2[MAX_PATH];
                DWORD dwType;

                dwSize = sizeof(wcTemp2);

                dwError = RegQueryValueExW( hKey,                // Key handle
                                            0,                   // Name
                                            0,                   // Reserved
                                            &dwType,             // Datatype
                                            (BYTE *)wcTemp2,     // Data returned here
                                            &dwSize );           // Size of data

                RegCloseKey( hKey );

                if ( ERROR_SUCCESS == dwError && 0 == _wcsicmp( wcTemp2, Handler.pwszClassId ) )
                {
                    wcTemp[ wcslen(wcTemp) - wcslen( L"\\PersistentHandler" ) ] = 0;

                    dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                             wcTemp,               // Sub key
                                             0,                    // Reserved
                                             KEY_ALL_ACCESS,       // Access
                                             &hKey );              // Handle

                    if ( ERROR_SUCCESS == dwError )
                    {
                        if ( ERROR_SUCCESS == dwIgnore )
                            dwIgnore = RegDeleteKeyW( hKey, L"PersistentHandler" );
                        else
                            RegDeleteKeyW( hKey, L"PersistentHandler" );

                        dwIndex = 0; // Start over again
                    }

                    //
                    // If that was the *only* entry under the clsid, then the class can be
                    // removed.
                    //

                    dwSize = sizeof(wcTemp2)/sizeof(wcTemp2[0]);

                    long dw2 = RegEnumKeyExW( hKey,             // Handle of key
                                              0,                // Index of registry subkey
                                              wcTemp2,          // Buffer for name
                                              &dwSize,          // Size of buffer / key
                                              0,                // Reserved
                                              0,                // Class (unused)
                                              0,                // Class size (unused)
                                              &ftUnused );      // Filetime (unused)

                    RegCloseKey( hKey );

                    if ( ERROR_NO_MORE_ITEMS == dw2 )
                        RemoveAClass( wcTemp + wcslen( L"CLSID\\" ) );
                }
                else
                {
                    //
                    // Didn't have persistent handler null key.  Odd but not fatal.
                    // Or, key didn't match target.
                    //

                    dwIgnore = dwError;
                    dwError = ERROR_SUCCESS;
                }

            }
            else
                dwError = ERROR_SUCCESS;  // Just didn't have persistent handler
        }
    }

    if ( (HKEY)INVALID_HANDLE_VALUE != hKeyEnum )
        RegCloseKey( hKeyEnum );

    if ( ERROR_NO_MORE_ITEMS != dwEnum )
        dwError = dwEnum;

    if ( ERROR_SUCCESS != dwError )
        return dwError;
    else
        return dwIgnore;
}

//+---------------------------------------------------------------------------
//
//  Function:   UnRegisterAnExt, private
//
//  Synopsis:   Unregisters a filter extension
//
//  Arguments:  [Class] -- Class description to unregister
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    21-Jan-1999   KyleP       Created
//
//----------------------------------------------------------------------------

inline long UnRegisterAnExt( SClassEntry const & Class )
{
    HKEY hKey = (HKEY)INVALID_HANDLE_VALUE;
    DWORD dwError;

    do
    {
        dwError = RegOpenKeyExW( HKEY_CLASSES_ROOT,    // Root
                                 Class.pwszExt,        // Sub key -- "CLSID"
                                 0,                    // Reserved
                                 KEY_ALL_ACCESS,       // Access
                                 &hKey );              // Handle

        if ( ERROR_SUCCESS != dwError )
            break;

        dwError = RegDeleteKeyW( hKey, L"PersistentHandler" );

    } while ( FALSE );

    if ( INVALID_HANDLE_VALUE != hKey )
    {
        RegCloseKey( hKey );
        hKey = (HKEY)INVALID_HANDLE_VALUE;
    }

    return dwError;
}

//+---------------------------------------------------------------------------
//
//  Function:   UnRegisterAFilter, private
//
//  Synopsis:   Unregisters a filter
//
//  Arguments:  [Filter] -- IFilter implementation
//
//  Returns:    ERROR_SUCCESS on success
//
//  History:    05-Jan-97   KyleP       Created
//
//----------------------------------------------------------------------------

inline long UnRegisterAFilter( SFilterEntry const & Filter )
{
    WCHAR const * aKeyValues[4] = { Filter.pwszClassId,
                                    Filter.pwszClassIdDescription,
                                    L"InprocServer32",
                                    Filter.pwszDLL };

    return DestroyKeyValues( aKeyValues, sizeof(aKeyValues)/sizeof(aKeyValues[0]) );
}

//+---------------------------------------------------------------------------
//
//  Function:   DllUnregisterServer
//
//  Synopsis:   Self-unregistration
//
//  History:    22-Nov-96   KyleP       Created
//
//----------------------------------------------------------------------------

//+---------------------------------------------------------------------------
//
//  Function:   DllRegisterServer
//
//  Synopsis:   Self-registration
//
//  History:    22-Nov-96   KyleP       Created
//
//  Notes:      There are two versions here.  Version 1 registers only
//              extensions.  Version 2 registers extensions and
//              [nameless] Class IDs.
//
//----------------------------------------------------------------------------



#define DEFINE_REGISTERFILTER( Name, Handler, Filter, aClasses )  \
                                                               \
STDAPI Name##UnregisterServer()                                \
{                                                              \
    /*                                                         \
     * Always remove Persistent Handler and Filter entries     \
     */                                                        \
                                                               \
    long dwError = UnRegisterAHandler( Handler );              \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        dwError = UnRegisterAFilter( Filter );                 \
    else                                                       \
        UnRegisterAFilter( Filter );                           \
                                                               \
    for ( unsigned i = 0; i < sizeof(aClasses)/sizeof(aClasses[0]); i++ ) \
    {                                                          \
        if ( ERROR_SUCCESS == dwError )                        \
            dwError = UnRegisterAnExt( aClasses[i] );          \
        else                                                   \
             UnRegisterAnExt( aClasses[i] );                   \
    }                                                          \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        return S_OK;                                           \
    else                                                       \
        return S_FALSE;                                        \
}                                                              \
                                                               \
STDAPI Name##RegisterServer()                                  \
{                                                              \
    /*                                                         \
     * Always create Persistent Handler and Filter entries     \
     */                                                        \
                                                               \
    long dwError = RegisterAHandler( Handler );                \
                                                               \
    /*                                                         \
     * First, register the CLSID and persistent handler,       \
     * then work back to the class description and the         \
     * extension. This ensures we cover all possible           \
     * mappings.                                               \
     *                                                         \
     */                                                        \
                                                               \
    OSVERSIONINFO Version;                                     \
    Version.dwOSVersionInfoSize = sizeof(Version);             \
                                                               \
    BOOL fAppendOnly = FALSE;                                  \
                                                               \
    if ( GetVersionEx( &Version ) &&                           \
         Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&      \
         Version.dwMajorVersion >= 5 )                         \
    {                                                          \
        fAppendOnly = TRUE;                                    \
    }                                                          \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        dwError = RegisterAFilter( Filter );                   \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        for ( unsigned i = 0; ERROR_SUCCESS == dwError && i < sizeof(aClasses)/sizeof(aClasses[0]); i++ ) \
            dwError = RegisterACLSID( aClasses[i], Handler.pwszClassId, 0, fAppendOnly );                        \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        for ( unsigned i = 0; ERROR_SUCCESS == dwError && i < sizeof(aClasses)/sizeof(aClasses[0]); i++ ) \
            dwError = RegisterAClass( aClasses[i], Handler.pwszClassId, 0, fAppendOnly );                        \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        for ( unsigned i = 0; ERROR_SUCCESS == dwError && i < sizeof(aClasses)/sizeof(aClasses[0]); i++ ) \
            dwError = RegisterAClassAndExt( aClasses[i], Handler.pwszClassId, fAppendOnly );                     \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        return S_OK;                                           \
    else                                                       \
        return SELFREG_E_CLASS;                                \
}




#define DEFINE_DLLREGISTERFILTER( Handler, Filter, aClasses )  \
    DEFINE_REGISTERFILTER( Dll, Handler, Filter, aClasses )

//
// Version 2
//

#define DEFINE_REGISTERFILTER2( Name, Handler, Filter, aClasses )  \
                                                               \
STDAPI Name##UnregisterServer()                                \
{                                                              \
    /*                                                         \
     * Always remove Persistent Handler and Filter entries     \
     */                                                        \
                                                               \
    long dwError = UnRegisterAHandler( Handler );              \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        dwError = UnRegisterAFilter( Filter );                 \
    else                                                       \
        UnRegisterAFilter( Filter );                           \
                                                               \
    for ( unsigned i = 0; i < sizeof(aClasses)/sizeof(aClasses[0]); i++ ) \
    {                                                          \
        if ( ERROR_SUCCESS == dwError )                        \
            dwError = UnRegisterAnExt( aClasses[i] );          \
        else                                                   \
            UnRegisterAnExt( aClasses[i] );                    \
    }                                                          \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        return S_OK;                                           \
    else                                                       \
        return S_FALSE;                                        \
}                                                              \
                                                               \
STDAPI Name##RegisterServer()                                  \
{                                                              \
    /*                                                         \
     * Always create Persistent Handler and Filter entries     \
     */                                                        \
                                                               \
    long dwError = RegisterAHandler( Handler );                \
                                                               \
    /*                                                         \
     * First, register the CLSID and persistent handler,       \
     * then work back to the class description and the         \
     * extension. This ensures we cover all possible           \
     * mappings.                                               \
     *                                                         \
     */                                                        \
                                                               \
    OSVERSIONINFO Version;                                     \
    Version.dwOSVersionInfoSize = sizeof(Version);             \
                                                               \
    BOOL fAppendOnly = FALSE;                                  \
                                                               \
    if ( GetVersionEx( &Version ) &&                           \
         Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&      \
         Version.dwMajorVersion >= 5 )                         \
    {                                                          \
        fAppendOnly = TRUE;                                    \
    }                                                          \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        dwError = RegisterAFilter( Filter );                   \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        for ( unsigned i = 0; ERROR_SUCCESS == dwError && i < sizeof(aClasses)/sizeof(aClasses[0]); i++ ) \
            dwError = RegisterACLSID( aClasses[i], Handler.pwszClassId, 0, FALSE, FALSE );                \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        for ( unsigned i = 0; ERROR_SUCCESS == dwError && i < sizeof(aClasses)/sizeof(aClasses[0]); i++ ) \
            dwError = RegisterAClass( aClasses[i], Handler.pwszClassId, 0, fAppendOnly );                        \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        for ( unsigned i = 0; ERROR_SUCCESS == dwError && i < sizeof(aClasses)/sizeof(aClasses[0]); i++ ) \
            dwError = RegisterAClassAndExt( aClasses[i], Handler.pwszClassId, fAppendOnly );                     \
                                                               \
    if ( ERROR_SUCCESS == dwError )                            \
        return S_OK;                                           \
    else                                                       \
        return SELFREG_E_CLASS;                                \
}




#define DEFINE_DLLREGISTERFILTER2( Handler, Filter, aClasses )  \
    DEFINE_REGISTERFILTER2( Dll, Handler, Filter, aClasses )