/*++

Copyright (c) 1999 Microsoft Corporation

Module Name:

    access.c

Abstract:

    Implements Win9x accessiblity conversion by hooking the physical registry type
    and emulating the NT registry format.

Author:

    Jim Schmidt (jimschm) 29-Aug-2000

Revision History:

    <alias> <date> <comments>

--*/

//
// Includes
//

#include "pch.h"
#include "logmsg.h"

#define DBG_ACCESS     "Accessibility"

//
// Strings
//

#define S_ACCESSIBILITY_ROOT        TEXT("HKCU\\Control Panel\\Accessibility")

//
// Constants
//

#define SPECIAL_INVERT_OPTION   0x80000000

//
// Macros
//

// none

//
// Types
//

typedef struct {
    PCTSTR ValueName;
    DWORD FlagVal;
} ACCESS_OPTION, *PACCESS_OPTION;

typedef struct {
    PACCESS_OPTION AccessibilityMap;
    PCTSTR Win9xSubKey;
    PCTSTR NtSubKey;
} ACCESSIBILITY_MAPPINGS, *PACCESSIBILITY_MAPPINGS;

typedef struct {
    MEMDB_ENUM EnumStruct;
    DWORD RegType;
} ACCESSIBILITY_ENUM_STATE, *PACCESSIBILITY_ENUM_STATE;


//
// Globals
//

MIG_OBJECTTYPEID g_RegistryTypeId;
HASHTABLE g_ProhibitTable;

ACCESS_OPTION g_FilterKeys[] = {
    TEXT("On"),                     FKF_FILTERKEYSON,
    TEXT("Available"),              FKF_AVAILABLE,
    TEXT("HotKeyActive"),           FKF_HOTKEYACTIVE,
    TEXT("ConfirmHotKey"),          FKF_CONFIRMHOTKEY,
    TEXT("HotKeySound"),            FKF_HOTKEYSOUND,
    TEXT("ShowStatusIndicator"),    FKF_INDICATOR,
    TEXT("ClickOn"),                FKF_CLICKON,
    TEXT("OnOffFeedback"),          0,
    NULL
};

ACCESS_OPTION g_MouseKeys[] = {
    TEXT("On"),                     MKF_MOUSEKEYSON,
    TEXT("Available"),              MKF_AVAILABLE,
    TEXT("HotKeyActive"),           MKF_HOTKEYACTIVE,
    TEXT("ConfirmHotKey"),          MKF_CONFIRMHOTKEY,
    TEXT("HotKeySound"),            MKF_HOTKEYSOUND,
    TEXT("ShowStatusIndicator"),    MKF_INDICATOR,
    TEXT("Modifiers"),              MKF_MODIFIERS|SPECIAL_INVERT_OPTION,
    TEXT("ReplaceNumbers"),         MKF_REPLACENUMBERS,
    TEXT("OnOffFeedback"),          0,
    NULL
};

ACCESS_OPTION g_StickyKeys[] = {
    TEXT("On"),                     SKF_STICKYKEYSON,
    TEXT("Available"),              SKF_AVAILABLE,
    TEXT("HotKeyActive"),           SKF_HOTKEYACTIVE,
    TEXT("ConfirmHotKey"),          SKF_CONFIRMHOTKEY,
    TEXT("HotKeySound"),            SKF_HOTKEYSOUND,
    TEXT("ShowStatusIndicator"),    SKF_INDICATOR,
    TEXT("AudibleFeedback"),        SKF_AUDIBLEFEEDBACK,
    TEXT("TriState"),               SKF_TRISTATE,
    TEXT("TwoKeysOff"),             SKF_TWOKEYSOFF,
    TEXT("OnOffFeedback"),          0,
    NULL
};

ACCESS_OPTION g_SoundSentry[] = {
    TEXT("On"),                     SSF_SOUNDSENTRYON,
    TEXT("Available"),              SSF_AVAILABLE,
    TEXT("ShowStatusIndicator"),    SSF_INDICATOR,
    NULL
};

ACCESS_OPTION g_TimeOut[] = {
    TEXT("On"),                     ATF_TIMEOUTON,
    TEXT("OnOffFeedback"),          ATF_ONOFFFEEDBACK,
    NULL
};

ACCESS_OPTION g_ToggleKeys[] = {
    TEXT("On"),                     TKF_TOGGLEKEYSON,
    TEXT("Available"),              TKF_AVAILABLE,
    TEXT("HotKeyActive"),           TKF_HOTKEYACTIVE,
    TEXT("ConfirmHotKey"),          TKF_CONFIRMHOTKEY,
    TEXT("HotKeySound"),            TKF_HOTKEYSOUND,
    TEXT("ShowStatusIndicator"),    TKF_INDICATOR,
    TEXT("OnOffFeedback"),          0,
    NULL
};

ACCESS_OPTION g_HighContrast[] = {
    TEXT("On"),                     HCF_HIGHCONTRASTON,
    TEXT("Available"),              HCF_AVAILABLE,
    TEXT("HotKeyActive"),           HCF_HOTKEYACTIVE,
    TEXT("ConfirmHotKey"),          HCF_CONFIRMHOTKEY,
    TEXT("HotKeySound"),            HCF_HOTKEYSOUND,
    TEXT("ShowStatusIndicator"),    HCF_INDICATOR,
    TEXT("HotKeyAvailable"),        HCF_HOTKEYAVAILABLE,
    TEXT("OnOffFeedback"),          0,
    NULL
};


ACCESSIBILITY_MAPPINGS g_AccessibilityMappings[] = {
    {g_FilterKeys,      TEXT("KeyboardResponse"),   TEXT("Keyboard Response")},
    {g_MouseKeys,       TEXT("MouseKeys")},
    {g_StickyKeys,      TEXT("StickyKeys")},
    {g_SoundSentry,     TEXT("SoundSentry")},
    {g_TimeOut,         TEXT("TimeOut")},
    {g_ToggleKeys,      TEXT("ToggleKeys")},
    {g_HighContrast,    TEXT("HighContrast")},
    {NULL}
};


//
// Macro expansion list
//

// none

//
// Private function prototypes
//

// none

//
// Macro expansion definition
//

// none

//
// Private prototypes
//

ETMINITIALIZE AccessibilityEtmInitialize;
MIG_PHYSICALENUMADD EmulatedEnumCallback;
MIG_PHYSICALACQUIREHOOK AcquireAccessibilityFlags;
MIG_PHYSICALACQUIREFREE ReleaseAccessibilityFlags;

//
// Code
//

VOID
pProhibit9xSetting (
    IN      PCTSTR Key,
    IN      PCTSTR ValueName        OPTIONAL
    )
{
    MIG_OBJECTSTRINGHANDLE handle;

    handle = IsmCreateObjectHandle (Key, ValueName);
    MYASSERT (handle);

    IsmProhibitPhysicalEnum (g_RegistryTypeId, handle, NULL, 0, NULL);
    HtAddString (g_ProhibitTable, handle);

    IsmDestroyObjectHandle (handle);
}


BOOL
pStoreEmulatedSetting (
    IN      PCTSTR Key,
    IN      PCTSTR ValueName,           OPTIONAL
    IN      DWORD Type,
    IN      PBYTE ValueData,
    IN      UINT ValueDataSize
    )
{
    MIG_OBJECTSTRINGHANDLE handle;
    PCTSTR memdbNode;
    BOOL stored = FALSE;

    handle = IsmCreateObjectHandle (Key, ValueName);
    memdbNode = JoinPaths (TEXT("~Accessibility"), handle);
    IsmDestroyObjectHandle (handle);

    if (MemDbAddKey (memdbNode)) {
        if (ValueData) {
            stored = (MemDbSetValue (memdbNode, Type) != 0);
            stored &= (MemDbSetUnorderedBlob (memdbNode, 0, ValueData, ValueDataSize) != 0);
        } else {
            stored = TRUE;
        }
    }

    FreePathString (memdbNode);

    return stored;
}


VOID
pMoveAccessibilityValue (
    IN      PCTSTR Win9xKey,
    IN      PCTSTR Win9xValue,
    IN      PCTSTR NtKey,
    IN      PCTSTR NtValue,
    IN      BOOL ForceDword
    )
{
    HKEY key;
    PBYTE data = NULL;
    PBYTE storeData;
    DWORD conversionDword;
    DWORD valueType;
    DWORD valueSize;
    MIG_OBJECTSTRINGHANDLE handle;
    BOOL prohibited;

    handle = IsmCreateObjectHandle (Win9xKey, Win9xValue);
    prohibited = (HtFindString (g_ProhibitTable, handle) != NULL);
    IsmDestroyObjectHandle (handle);

    if (prohibited) {
        return;
    }

    key = OpenRegKeyStr (Win9xKey);
    if (!key) {
        return;
    }

    __try {
        if (!GetRegValueTypeAndSize (key, Win9xValue, &valueType, &valueSize)) {
            __leave;
        }

        if (valueType != REG_SZ && valueType != REG_DWORD) {
            __leave;
        }

        data = GetRegValueData (key, Win9xValue);
        if (!data) {
            __leave;
        }

        if (ForceDword && valueType == REG_SZ) {
            storeData = (PBYTE) &conversionDword;
            conversionDword = _ttoi ((PCTSTR) data);
            valueType = REG_DWORD;
            valueSize = sizeof (DWORD);
        } else {
            storeData = data;
        }

        if (pStoreEmulatedSetting (NtKey, NtValue, valueType, storeData, valueSize)) {
            pProhibit9xSetting (Win9xKey, Win9xValue);
        }
    }
    __finally {
        CloseRegKey (key);

        if (data) {
            FreeAlloc (data);
        }
    }
}


VOID
pMoveAccessibilityKey (
    IN      PCTSTR Win9xKey,
    IN      PCTSTR NtKey
    )
{
    HKEY key;
    PBYTE data = NULL;
    DWORD valueType;
    DWORD valueSize;
    LONG rc;
    DWORD index = 0;
    TCHAR valueName[MAX_REGISTRY_KEY];
    DWORD valueNameSize;
    GROWBUFFER value = INIT_GROWBUFFER;
    MIG_OBJECTSTRINGHANDLE handle;
    BOOL prohibited;

    key = OpenRegKeyStr (Win9xKey);
    if (!key) {
        return;
    }

    __try {
        for (;;) {

            valueNameSize = ARRAYSIZE(valueName);
            valueSize = 0;
            rc = RegEnumValue (key, index, valueName, &valueNameSize, NULL, &valueType, NULL, &valueSize);

            if (rc != ERROR_SUCCESS) {
                break;
            }

            handle = IsmCreateObjectHandle (Win9xKey, valueName);
            prohibited = (HtFindString (g_ProhibitTable, handle) != NULL);
            IsmDestroyObjectHandle (handle);

            if (!prohibited) {

                value.End = 0;
                data = GbGrow (&value, valueSize);

                valueNameSize = ARRAYSIZE(valueName);
                rc = RegEnumValue (key, index, valueName, &valueNameSize, NULL, &valueType, value.Buf, &valueSize);

                if (rc != ERROR_SUCCESS) {
                    break;
                }

                if (pStoreEmulatedSetting (NtKey, valueName, valueType, data, valueSize)) {
                    pProhibit9xSetting (Win9xKey, valueName);
                }
            }

            index++;
        }

        if (pStoreEmulatedSetting (NtKey, NULL, 0, NULL, 0)) {
            pProhibit9xSetting (Win9xKey, NULL);
        }
    }
    __finally {
        CloseRegKey (key);

        GbFree (&value);
    }
}


VOID
pTranslateAccessibilityKey (
    IN      PCTSTR Win9xSubKey,
    IN      PCTSTR NtSubKey,
    IN      PACCESS_OPTION AccessibilityMap
    )
{
    TCHAR full9xKey[MAX_REGISTRY_KEY];
    TCHAR fullNtKey[MAX_REGISTRY_KEY];
    MIG_OBJECTSTRINGHANDLE handle = NULL;
    HKEY key = NULL;
    PCTSTR data;
    DWORD flags = 0;
    DWORD thisFlag;
    BOOL enabled;
    TCHAR buffer[32];

    __try {
        StringCopy (full9xKey, S_ACCESSIBILITY_ROOT TEXT("\\"));
        StringCopy (fullNtKey, full9xKey);
        StringCat (full9xKey, Win9xSubKey);
        StringCat (fullNtKey, NtSubKey);

        key = OpenRegKeyStr (full9xKey);
        if (!key) {
            __leave;
        }

        while (AccessibilityMap->ValueName) {
            //
            // Prohibit enum of this value
            //

            handle = IsmCreateObjectHandle (full9xKey, AccessibilityMap->ValueName);
            MYASSERT (handle);

            IsmProhibitPhysicalEnum (g_RegistryTypeId, handle, NULL, 0, NULL);
            HtAddString (g_ProhibitTable, handle);

            IsmDestroyObjectHandle (handle);
            handle = NULL;

            //
            // Update the emulated flags
            //

            data = GetRegValueString (key, AccessibilityMap->ValueName);
            if (data) {

                enabled = (_ttoi (data) != 0);
                thisFlag = (AccessibilityMap->FlagVal & (~SPECIAL_INVERT_OPTION));

                if (AccessibilityMap->FlagVal & SPECIAL_INVERT_OPTION) {
                    enabled = !enabled;
                }

                if (enabled) {
                    flags |= thisFlag;
                }

                FreeAlloc (data);
            }

            AccessibilityMap++;
        }

        //
        // Put the emulated value in the hash table
        //

        wsprintf (buffer, TEXT("%u"), flags);
        pStoreEmulatedSetting (fullNtKey, TEXT("Flags"), REG_SZ, (PBYTE) buffer, SizeOfString (buffer));
    }
    __finally {
        if (key) {
            CloseRegKey (key);
        }
    }
}


VOID
pFillTranslationTable (
    VOID
    )
{
    PACCESSIBILITY_MAPPINGS mappings;

    //
    // Loop through all flags that need translation. Disable enumeration of
    // the Win9x physical values and enable enumeration of the translated values
    // via population of the hash table.
    //

    mappings = g_AccessibilityMappings;

    while (mappings->AccessibilityMap) {

        pTranslateAccessibilityKey (
            mappings->Win9xSubKey,
            mappings->NtSubKey ? mappings->NtSubKey : mappings->Win9xSubKey,
            mappings->AccessibilityMap
            );

        mappings++;
    }

    //
    // Add all keys that have moved, ordered from most specific to least specific
    //

    // AutoRepeat values are transposed
    pMoveAccessibilityValue (
        S_ACCESSIBILITY_ROOT TEXT("\\KeyboardResponse"), TEXT("AutoRepeatDelay"),
        S_ACCESSIBILITY_ROOT TEXT("\\Keyboard Response"), TEXT("AutoRepeatRate"),
        FALSE
        );

    pMoveAccessibilityValue (
        S_ACCESSIBILITY_ROOT TEXT("\\KeyboardResponse"), TEXT("AutoRepeatRate"),
        S_ACCESSIBILITY_ROOT TEXT("\\Keyboard Response"), TEXT("AutoRepeatDelay"),
        FALSE
        );

    // double c in DelayBeforeAcceptance value name
    pMoveAccessibilityValue (
        S_ACCESSIBILITY_ROOT TEXT("\\KeyboardResponse"), TEXT("DelayBeforeAcceptancce"),
        S_ACCESSIBILITY_ROOT TEXT("\\Keyboard Response"), TEXT("DelayBeforeAcceptance"),
        FALSE
        );

    // add a space to the key name for the rest of the values
    pMoveAccessibilityKey (
        S_ACCESSIBILITY_ROOT TEXT("\\KeyboardResponse"),
        S_ACCESSIBILITY_ROOT TEXT("\\Keyboard Response")
        );

    // change BaudRate to Baud & convert to DWORD
    pMoveAccessibilityValue (
        S_ACCESSIBILITY_ROOT TEXT("\\SerialKeys"), TEXT("BaudRate"),
        S_ACCESSIBILITY_ROOT TEXT("\\SerialKeys"), TEXT("Baud"),
        TRUE
        );

    // convert Flags to DWORD
    pMoveAccessibilityValue (
        S_ACCESSIBILITY_ROOT TEXT("\\SerialKeys"), TEXT("Flags"),
        S_ACCESSIBILITY_ROOT TEXT("\\SerialKeys"), TEXT("Flags"),
        TRUE
        );

    // add space between high and contrast
    pMoveAccessibilityValue (
        S_ACCESSIBILITY_ROOT TEXT("\\HighContrast"), TEXT("Pre-HighContrast Scheme"),
        S_ACCESSIBILITY_ROOT TEXT("\\HighContrast"), TEXT("Pre-High Contrast Scheme"),
        FALSE
        );

    // move two values from the root into their own subkeys
    pMoveAccessibilityValue (
        S_ACCESSIBILITY_ROOT, TEXT("Blind Access"),
        S_ACCESSIBILITY_ROOT TEXT("\\Blind Access"), TEXT("On"),
        FALSE
        );

    pStoreEmulatedSetting (S_ACCESSIBILITY_ROOT TEXT("\\Blind Access"), NULL, 0, NULL, 0);

    pMoveAccessibilityValue (
        S_ACCESSIBILITY_ROOT, TEXT("Keyboard Preference"),
        S_ACCESSIBILITY_ROOT TEXT("\\Keyboard Preference"), TEXT("On"),
        FALSE
        );

    pStoreEmulatedSetting (S_ACCESSIBILITY_ROOT TEXT("\\Keyboard Preference"), NULL, 0, NULL, 0);

}


BOOL
WINAPI
AccessibilityEtmInitialize (
    IN      MIG_PLATFORMTYPEID Platform,
    IN      PMIG_LOGCALLBACK LogCallback,
    IN      PVOID Reserved
    )
{
    MIG_OBJECTSTRINGHANDLE objectName;
    BOOL b = TRUE;

    LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);

    if (ISWIN9X()) {
        g_RegistryTypeId = IsmGetObjectTypeId (S_REGISTRYTYPE);
        MYASSERT (g_RegistryTypeId);

        g_ProhibitTable = HtAlloc();
        MYASSERT (g_ProhibitTable);

        if (g_RegistryTypeId) {
            //
            // Add a callback for additional enumeration. If we are unable to do so, then
            // someone else is already doing something different for this key.
            //

            objectName = IsmCreateObjectHandle (S_ACCESSIBILITY_ROOT, NULL);

            b = IsmAddToPhysicalEnum (g_RegistryTypeId, objectName, EmulatedEnumCallback, 0);

            IsmDestroyObjectHandle (objectName);

            if (b) {
                //
                // Add a callback to acquire the data of the new physical objects
                //

                objectName = IsmCreateSimpleObjectPattern (
                                    S_ACCESSIBILITY_ROOT,
                                    TRUE,
                                    NULL,
                                    TRUE
                                    );

                b = IsmRegisterPhysicalAcquireHook (
                        g_RegistryTypeId,
                        objectName,
                        AcquireAccessibilityFlags,
                        ReleaseAccessibilityFlags,
                        0,
                        NULL
                        );

                IsmDestroyObjectHandle (objectName);
            }

            if (b) {

                //
                // Now load memdb with the current registry values and
                // prohibit the enumeration of Win9x values.
                //

                pFillTranslationTable ();
            }
            ELSE_DEBUGMSG ((DBG_WARNING, "Not allowed to translate accessibility key"));
        }

        HtFree (g_ProhibitTable);
        g_ProhibitTable = NULL;
    }

    return b;
}


BOOL
WINAPI
EmulatedEnumCallback (
    IN OUT  PMIG_TYPEOBJECTENUM ObjectEnum,
    IN      MIG_OBJECTSTRINGHANDLE Pattern,
    IN      MIG_PARSEDPATTERN ParsedPattern,
    IN      ULONG_PTR Arg,
    IN      BOOL Abort
    )
{
    PACCESSIBILITY_ENUM_STATE state = (PACCESSIBILITY_ENUM_STATE) ObjectEnum->EtmHandle;
    BOOL result = FALSE;
    BOOL cleanUpMemdb = TRUE;
    PCTSTR p;

    for (;;) {

        if (!Abort) {

            //
            // Begin or continue? If the EtmHandle is NULL, begin. Otherwise, continue.
            //

            if (!state) {
                state = (PACCESSIBILITY_ENUM_STATE) MemAllocUninit (sizeof (ACCESSIBILITY_ENUM_STATE));
                if (!state) {
                    MYASSERT (FALSE);
                    return FALSE;
                }

                ObjectEnum->EtmHandle = (LONG_PTR) state;

                result = MemDbEnumFirst (
                            &state->EnumStruct,
                            TEXT("~Accessibility\\*"),
                            ENUMFLAG_NORMAL,
                            1,
                            MEMDB_LAST_LEVEL
                            );

            } else {
                result = MemDbEnumNext (&state->EnumStruct);
            }

            //
            // If an item was found, populate the enum struct. Otherwise, set
            // Abort to TRUE to clean up.
            //

            if (result) {
                //
                // Test against pattern
                //

                if (!IsmParsedPatternMatch (ParsedPattern, 0, state->EnumStruct.KeyName)) {
                    continue;
                }

                MYASSERT ((ObjectEnum->ObjectTypeId & (~PLATFORM_MASK)) == g_RegistryTypeId);

                ObjectEnum->ObjectName = state->EnumStruct.KeyName;
                state->RegType = state->EnumStruct.Value;

                //
                // Fill in node, leaf and details
                //

                IsmDestroyObjectString (ObjectEnum->ObjectNode);
                IsmDestroyObjectString (ObjectEnum->ObjectLeaf);
                IsmReleaseMemory (ObjectEnum->NativeObjectName);

                IsmCreateObjectStringsFromHandle (
                    ObjectEnum->ObjectName,
                    &ObjectEnum->ObjectNode,
                    &ObjectEnum->ObjectLeaf
                    );

                MYASSERT (ObjectEnum->ObjectNode);

                ObjectEnum->Level = 0;

                p = _tcschr (ObjectEnum->ObjectNode, TEXT('\\'));
                while (p) {
                    ObjectEnum->Level++;
                    p = _tcschr (p + 1, TEXT('\\'));
                }

                ObjectEnum->SubLevel = 0;

                if (ObjectEnum->ObjectLeaf) {
                    ObjectEnum->IsNode = FALSE;
                    ObjectEnum->IsLeaf = TRUE;
                } else {
                    ObjectEnum->IsNode = TRUE;
                    ObjectEnum->IsLeaf = FALSE;
                }

                if (state->RegType) {
                    ObjectEnum->Details.DetailsSize = sizeof (state->RegType);
                    ObjectEnum->Details.DetailsData = &state->RegType;
                } else {
                    ObjectEnum->Details.DetailsSize = 0;
                    ObjectEnum->Details.DetailsData = NULL;
                }

                //
                // Rely on base type to get the native object name
                //

                ObjectEnum->NativeObjectName = IsmGetNativeObjectName (
                                                    ObjectEnum->ObjectTypeId,
                                                    ObjectEnum->ObjectName
                                                    );


            } else {
                Abort = TRUE;
                cleanUpMemdb = FALSE;
            }
        }

        if (Abort) {
            //
            // Clean up our enum struct
            //

            if (state) {
                if (cleanUpMemdb) {
                    MemDbAbortEnum (&state->EnumStruct);
                }

                IsmDestroyObjectString (ObjectEnum->ObjectNode);
                ObjectEnum->ObjectNode = NULL;
                IsmDestroyObjectString (ObjectEnum->ObjectLeaf);
                ObjectEnum->ObjectLeaf = NULL;
                IsmReleaseMemory (ObjectEnum->NativeObjectName);
                ObjectEnum->NativeObjectName = NULL;
                FreeAlloc (state);
            }

            // return value ignored in Abort case, and ObjectEnum is zeroed by the ISM
        }

        break;
    }

    return result;
}


BOOL
WINAPI
AcquireAccessibilityFlags(
    IN      MIG_OBJECTSTRINGHANDLE ObjectName,
    IN      PMIG_CONTENT ObjectContent,
    IN      MIG_CONTENTTYPE ContentType,
    IN      UINT MemoryContentLimit,
    OUT     PMIG_CONTENT *NewObjectContent,         CALLER_INITIALIZED OPTIONAL
    IN      BOOL ReleaseContent,
    IN      ULONG_PTR Arg
    )
{
    BOOL result = TRUE;
    PDWORD details;
    PMIG_CONTENT ourContent;
    PCTSTR memdbNode;

    //
    // Is this object in our hash table?
    //

    if (ContentType == CONTENTTYPE_FILE) {
        DEBUGMSG ((DBG_ERROR, "Accessibility content cannot be saved to a file"));
        result = FALSE;
    } else {

        memdbNode = JoinPaths (TEXT("~Accessibility"), ObjectName);

        if (MemDbTestKey (memdbNode)) {

            //
            // Alloc updated content struct
            //

            ourContent = MemAllocZeroed (sizeof (MIG_CONTENT) + sizeof (DWORD));
            ourContent->EtmHandle = ourContent;
            details = (PDWORD) (ourContent + 1);

            //
            // Get the content from memdb
            //

            ourContent->MemoryContent.ContentBytes = MemDbGetUnorderedBlob (
                                                            memdbNode,
                                                            0,
                                                            &ourContent->MemoryContent.ContentSize
                                                            );

            if (ourContent->MemoryContent.ContentBytes) {
                MemDbGetValue (memdbNode, details);

                ourContent->Details.DetailsSize = sizeof (DWORD);
                ourContent->Details.DetailsData = details;

            } else {
                ourContent->MemoryContent.ContentSize = 0;

                ourContent->Details.DetailsSize = 0;
                ourContent->Details.DetailsData = NULL;
            }

            ourContent->ContentInFile = FALSE;

            //
            // Pass it to ISM
            //

            *NewObjectContent = ourContent;

        }

        FreePathString (memdbNode);
    }

    return result;      // always TRUE unless an error occurred
}

VOID
WINAPI
ReleaseAccessibilityFlags(
    IN      PMIG_CONTENT ObjectContent
    )
{
    //
    // This callback is called to free the content we allocated above.
    //

    if (ObjectContent->MemoryContent.ContentBytes) {
        MemDbReleaseMemory (ObjectContent->MemoryContent.ContentBytes);
    }

    FreeAlloc ((PMIG_CONTENT) ObjectContent->EtmHandle);
}


BOOL
WINAPI
AccessibilitySourceInitialize (
    IN      PMIG_LOGCALLBACK LogCallback,
    IN      PVOID Reserved
    )
{
    LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);

    if (!g_RegistryTypeId) {
        g_RegistryTypeId = IsmGetObjectTypeId (S_REGISTRYTYPE);
    }

    return TRUE;
}