/*++

Copyright (c) 1990  Microsoft Corporation

Module Name:

    registry.c

Abstract:

    This file contains functions to read and _rite values
    to the registry.

Author:

    Jerry Shea (JerrySh) 30-Sep-1994

Revision History:

--*/

#include "precomp.h"
#pragma hdrstop

#include <shlwapi.h>

#define CONSOLE_REGISTRY_CURRENTPAGE  (L"CurrentPage")
extern BOOL	g_fAutoComplete;
extern BOOL	g_fSaveAutoCompleteState;


NTSTATUS
MyRegOpenKey(
    IN HANDLE hKey,
    IN LPWSTR lpSubKey,
    OUT PHANDLE phResult
    )
{
    OBJECT_ATTRIBUTES   Obja;
    UNICODE_STRING      SubKey;

    //
    // Convert the subkey to a counted Unicode string.
    //

    RtlInitUnicodeString( &SubKey, lpSubKey );

    //
    // Initialize the OBJECT_ATTRIBUTES structure and open the key.
    //

    InitializeObjectAttributes(
        &Obja,
        &SubKey,
        OBJ_CASE_INSENSITIVE,
        hKey,
        NULL
        );

    return NtOpenKey(
              phResult,
              KEY_READ,
              &Obja
              );
}

NTSTATUS
MyRegDeleteKey(
    IN HANDLE hKey,
    IN LPWSTR lpSubKey
    )
{
    UNICODE_STRING      SubKey;

    //
    // Convert the subkey to a counted Unicode string.
    //

    RtlInitUnicodeString( &SubKey, lpSubKey );

    //
    // Delete the subkey
    //

    return NtDeleteValueKey(
              hKey,
              &SubKey
              );
}

NTSTATUS
MyRegCreateKey(
    IN HANDLE hKey,
    IN LPWSTR lpSubKey,
    OUT PHANDLE phResult
    )
{
    OBJECT_ATTRIBUTES   Obja;
    UNICODE_STRING      SubKey;

    //
    // Convert the subkey to a counted Unicode string.
    //

    RtlInitUnicodeString( &SubKey, lpSubKey );

    //
    // Initialize the OBJECT_ATTRIBUTES structure and open the key.
    //

    InitializeObjectAttributes(
        &Obja,
        &SubKey,
        OBJ_CASE_INSENSITIVE,
        hKey,
        NULL
        );

    return NtCreateKey(
                    phResult,
                    KEY_READ | KEY_WRITE,
                    &Obja,
                    0,
                    NULL,
                    0,
                    NULL
                    );
}

NTSTATUS
MyRegQueryValue(
    IN HANDLE hKey,
    IN LPWSTR lpValueName,
    IN DWORD dwValueLength,
    OUT LPBYTE lpData
    )
{
    UNICODE_STRING ValueName;
    ULONG BufferLength;
    ULONG ResultLength;
    PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
    NTSTATUS Status;

    //
    // Convert the subkey to a counted Unicode string.
    //

    RtlInitUnicodeString( &ValueName, lpValueName );

    BufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + dwValueLength;
    KeyValueInformation = HeapAlloc(RtlProcessHeap(),0,BufferLength);
    if (KeyValueInformation == NULL)
        return STATUS_NO_MEMORY;

    Status = NtQueryValueKey(
                hKey,
                &ValueName,
                KeyValuePartialInformation,
                KeyValueInformation,
                BufferLength,
                &ResultLength
                );
    if (NT_SUCCESS(Status)) {
        ASSERT(KeyValueInformation->DataLength <= dwValueLength);
        RtlCopyMemory(lpData,
            KeyValueInformation->Data,
            KeyValueInformation->DataLength);
        if (KeyValueInformation->Type == REG_SZ) {
            if (KeyValueInformation->DataLength + sizeof(WCHAR) > dwValueLength) {
                KeyValueInformation->DataLength -= sizeof(WCHAR);
            }
            lpData[KeyValueInformation->DataLength++] = 0;
            lpData[KeyValueInformation->DataLength] = 0;
        }
    }
    HeapFree(RtlProcessHeap(),0,KeyValueInformation);
    return Status;
}


#if defined(FE_SB)
NTSTATUS
MyRegEnumValue(
    IN HANDLE hKey,
    IN DWORD dwIndex,
    OUT DWORD dwValueLength,
    OUT LPWSTR lpValueName,
    OUT DWORD dwDataLength,
    OUT LPBYTE lpData
    )
{
    ULONG BufferLength;
    ULONG ResultLength;
    PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
    NTSTATUS Status;

    //
    // Convert the subkey to a counted Unicode string.
    //

    BufferLength = sizeof(KEY_VALUE_FULL_INFORMATION) + dwValueLength + dwDataLength;
    KeyValueInformation = LocalAlloc(LPTR,BufferLength);
    if (KeyValueInformation == NULL)
        return STATUS_NO_MEMORY;

    Status = NtEnumerateValueKey(
                hKey,
                dwIndex,
                KeyValueFullInformation,
                KeyValueInformation,
                BufferLength,
                &ResultLength
                );
    if (NT_SUCCESS(Status)) {
        ASSERT(KeyValueInformation->NameLength <= dwValueLength);
        RtlMoveMemory(lpValueName,
                      KeyValueInformation->Name,
                      KeyValueInformation->NameLength);
        lpValueName[ KeyValueInformation->NameLength >> 1 ] = UNICODE_NULL;


        ASSERT(KeyValueInformation->DataLength <= dwDataLength);
        RtlMoveMemory(lpData,
            (PBYTE)KeyValueInformation + KeyValueInformation->DataOffset,
            KeyValueInformation->DataLength);
        if (KeyValueInformation->Type == REG_SZ ||
            KeyValueInformation->Type ==REG_MULTI_SZ
           ) {
            if (KeyValueInformation->DataLength + sizeof(WCHAR) > dwDataLength) {
                KeyValueInformation->DataLength -= sizeof(WCHAR);
            }
            lpData[KeyValueInformation->DataLength++] = 0;
            lpData[KeyValueInformation->DataLength] = 0;
        }
    }
    LocalFree(KeyValueInformation);
    return Status;
}
#endif

LPWSTR
TranslateConsoleTitle(
    LPWSTR ConsoleTitle
    )
/*++

    this routine translates path characters into '_' characters because
    the NT registry apis do not allow the creation of keys with
    names that contain path characters.  it allocates a buffer that
    must be freed.

--*/
{
    int ConsoleTitleLength, i;
    LPWSTR TranslatedTitle;

    ConsoleTitleLength = lstrlenW(ConsoleTitle) + 1;
    TranslatedTitle = HeapAlloc(RtlProcessHeap(), 0,
                                ConsoleTitleLength * sizeof(WCHAR));
    if (TranslatedTitle == NULL) {
        return NULL;
    }
    for (i = 0; i < ConsoleTitleLength; i++) {
        if (ConsoleTitle[i] == '\\') {
            TranslatedTitle[i] = (WCHAR)'_';
        } else {
            TranslatedTitle[i] = ConsoleTitle[i];
        }
    }
    return TranslatedTitle;
}


NTSTATUS
MyRegSetValue(
    IN HANDLE hKey,
    IN LPWSTR lpValueName,
    IN DWORD dwType,
    IN LPVOID lpData,
    IN DWORD cbData
    )
{
    UNICODE_STRING ValueName;

    //
    // Convert the subkey to a counted Unicode string.
    //

    RtlInitUnicodeString( &ValueName, lpValueName );

    return NtSetValueKey(
                    hKey,
                    &ValueName,
                    0,
                    dwType,
                    lpData,
                    cbData
                    );
}


NTSTATUS
MyRegUpdateValue(
    IN HANDLE hConsoleKey,
    IN HANDLE hKey,
    IN LPWSTR lpValueName,
    IN DWORD dwType,
    IN LPVOID lpData,
    IN DWORD cbData
    )
{
    NTSTATUS Status;
    BYTE Data[MAX_PATH];

    //
    // If this is not the main console key but the value is the same,
    // delete it. Otherwise, set it.
    //

    if (hConsoleKey != hKey) {
        Status = MyRegQueryValue(hConsoleKey, lpValueName, sizeof(Data), Data);
        if (NT_SUCCESS(Status)) {
            if (RtlCompareMemory(lpData, Data, cbData) == cbData) {
                return MyRegDeleteKey(hKey, lpValueName);
            }
        }
    }

    return MyRegSetValue(hKey, lpValueName, dwType, lpData, cbData);
}


PCONSOLE_STATE_INFO
InitRegistryValues(VOID)

/*++

Routine Description:

    This routine allocates a state info structure and fill it in with
    default values.

Arguments:

    none

Return Value:

    pStateInfo - pointer to structure to receive information

--*/

{
    PCONSOLE_STATE_INFO pStateInfo;

    pStateInfo = HeapAlloc(RtlProcessHeap(), 0, sizeof(CONSOLE_STATE_INFO));
    if (pStateInfo == NULL) {
        return NULL;
    }

    pStateInfo->Length = sizeof(CONSOLE_STATE_INFO);
    pStateInfo->ScreenAttributes = 0x07;            // white on black
    pStateInfo->PopupAttributes = 0xf5;             // purple on white
    pStateInfo->InsertMode = FALSE;
    pStateInfo->QuickEdit = FALSE;
    pStateInfo->FullScreen = FALSE;
    pStateInfo->ScreenBufferSize.X = 80;
    pStateInfo->ScreenBufferSize.Y = 25;
    pStateInfo->WindowSize.X = 80;
    pStateInfo->WindowSize.Y = 25;
    pStateInfo->WindowPosX = 0;
    pStateInfo->WindowPosY = 0;
    pStateInfo->AutoPosition = TRUE;
    pStateInfo->FontSize.X = 0;
    pStateInfo->FontSize.Y = 0;
    pStateInfo->FontFamily = 0;
    pStateInfo->FontWeight = 0;
    pStateInfo->FaceName[0] = TEXT('\0');
    pStateInfo->CursorSize = 25;
    pStateInfo->HistoryBufferSize = 25;
    pStateInfo->NumberOfHistoryBuffers = 4;
    pStateInfo->HistoryNoDup = 0;
    pStateInfo->ColorTable[ 0] = RGB(0,   0,   0   );
    pStateInfo->ColorTable[ 1] = RGB(0,   0,   0x80);
    pStateInfo->ColorTable[ 2] = RGB(0,   0x80,0   );
    pStateInfo->ColorTable[ 3] = RGB(0,   0x80,0x80);
    pStateInfo->ColorTable[ 4] = RGB(0x80,0,   0   );
    pStateInfo->ColorTable[ 5] = RGB(0x80,0,   0x80);
    pStateInfo->ColorTable[ 6] = RGB(0x80,0x80,0   );
    pStateInfo->ColorTable[ 7] = RGB(0xC0,0xC0,0xC0);
    pStateInfo->ColorTable[ 8] = RGB(0x80,0x80,0x80);
    pStateInfo->ColorTable[ 9] = RGB(0,   0,   0xFF);
    pStateInfo->ColorTable[10] = RGB(0,   0xFF,0   );
    pStateInfo->ColorTable[11] = RGB(0,   0xFF,0xFF);
    pStateInfo->ColorTable[12] = RGB(0xFF,0,   0   );
    pStateInfo->ColorTable[13] = RGB(0xFF,0,   0xFF);
    pStateInfo->ColorTable[14] = RGB(0xFF,0xFF,0   );
    pStateInfo->ColorTable[15] = RGB(0xFF,0xFF,0xFF);
#if defined(FE_SB)
    pStateInfo->CodePage = OEMCP; // scotthsu
#endif
    pStateInfo->hWnd = NULL;
    pStateInfo->ConsoleTitle[0] = TEXT('\0');

    g_fAutoComplete = TRUE;

    return pStateInfo;
}




#define SZ_REGKEY_CMDAUTOCOMPLETE           TEXT("Software\\Microsoft\\Command Processor")
#define SZ_REGVALUE_CMDAUTOCOMPLETE         TEXT("CompletionChar")
#define DWORD_CMD_TAB_AUTOCOMPLETE_ON       0x00000009          // 9 is tab
#define DWORD_CMD_TAB_AUTOCOMPLETE_OFF      0x00000020          // 20 is space which turns it off.

BOOL
IsAutoCompleteOn(
    void
    )
{
    DWORD dwType;
    DWORD dwValue = DWORD_CMD_TAB_AUTOCOMPLETE_ON;
    DWORD cbSize = sizeof(dwValue);

    if ((ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_CMDAUTOCOMPLETE, SZ_REGVALUE_CMDAUTOCOMPLETE, &dwType, (LPBYTE)&dwValue, &cbSize)) ||
        (REG_DWORD != dwType))
    {
        dwValue = DWORD_CMD_TAB_AUTOCOMPLETE_ON;    // Fall back to the default value.
    }

    return (DWORD_CMD_TAB_AUTOCOMPLETE_ON == dwValue);
}


void
SaveAutoCompleteSetting(
    IN BOOL fAutoComplete
    )
{
    // Only over write the registry value if someone has changed the value.
    if (g_fSaveAutoCompleteState)
    {
        DWORD dwValue = (fAutoComplete ? DWORD_CMD_TAB_AUTOCOMPLETE_ON : DWORD_CMD_TAB_AUTOCOMPLETE_OFF);

        SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_CMDAUTOCOMPLETE, SZ_REGVALUE_CMDAUTOCOMPLETE, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
    }
}


DWORD
GetRegistryValues(
    PCONSOLE_STATE_INFO pStateInfo
    )

/*++

Routine Description:

    This routine reads in values from the registry and places them
    in the supplied structure.

Arguments:

    pStateInfo - optional pointer to structure to receive information

Return Value:

    current page number

--*/

{
    HANDLE hCurrentUserKey;
    HANDLE hConsoleKey;
    HANDLE hTitleKey;
    NTSTATUS Status;
    LPWSTR TranslatedTitle;
    DWORD dwValue;
    DWORD dwRet = 0;
    DWORD i;
    WCHAR awchBuffer[LF_FACESIZE];

    //
    // Open the current user registry key
    //

    Status = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &hCurrentUserKey);
    if (!NT_SUCCESS(Status)) {
        return 0;
    }

    //
    // Open the console registry key
    //

    Status = MyRegOpenKey(hCurrentUserKey,
                          CONSOLE_REGISTRY_STRING,
                          &hConsoleKey);
    if (!NT_SUCCESS(Status)) {
        NtClose(hCurrentUserKey);
        return 0;
    }

    //
    // If there is no structure to fill out, just get the current
    // page and bail out.
    //

    if (pStateInfo == NULL) {
        if (NT_SUCCESS(MyRegQueryValue(hConsoleKey,
                       CONSOLE_REGISTRY_CURRENTPAGE,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
            dwRet = dwValue;
        }
        goto CloseKeys;
    }

    //
    // Open the console title subkey, if there is one
    //

    if (pStateInfo->ConsoleTitle[0] != TEXT('\0')) {
        TranslatedTitle = TranslateConsoleTitle(pStateInfo->ConsoleTitle);
        if (TranslatedTitle == NULL) {
            NtClose(hConsoleKey);
            NtClose(hCurrentUserKey);
            return 0;
        }
        Status = MyRegOpenKey(hConsoleKey,
                              TranslatedTitle,
                              &hTitleKey);
        HeapFree(RtlProcessHeap(),0,TranslatedTitle);
        if (!NT_SUCCESS(Status)) {
            NtClose(hConsoleKey);
            NtClose(hCurrentUserKey);
            return 0;
        }
    } else {
        hTitleKey = hConsoleKey;
    }

    //
    // Initial screen fill
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_FILLATTR,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->ScreenAttributes = (WORD)dwValue;
    }

    //
    // Initial popup fill
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_POPUPATTR,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->PopupAttributes = (WORD)dwValue;
    }

    //
    // Initial color table
    //

    for (i = 0; i < 16; i++) {
        wsprintf(awchBuffer, CONSOLE_REGISTRY_COLORTABLE, i);
        if (NT_SUCCESS(MyRegQueryValue(hTitleKey, awchBuffer,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
            pStateInfo->ColorTable[i] = dwValue;
        }
    }

    //
    // Initial insert mode
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_INSERTMODE,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->InsertMode = !!dwValue;
    }

    //
    // Initial quick edit mode
    //
    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_QUICKEDIT,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->QuickEdit = !!dwValue;
    }

    //
    // Initial autocomplete mode
    //
    g_fAutoComplete = IsAutoCompleteOn();

#ifdef i386
    //
    // Initial full screen mode
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_FULLSCR,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->FullScreen = !!dwValue;
    }
#endif
#if defined(FE_SB) // scotthsu
    //
    // Initial code page
    //

    ASSERT(OEMCP != 0);
    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_CODEPAGE,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        if (IsValidCodePage(dwValue)) {
            pStateInfo->CodePage = (UINT) dwValue;
        }
    }
#endif

    //
    // Initial screen buffer size
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_BUFFERSIZE,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->ScreenBufferSize.X = LOWORD(dwValue);
        pStateInfo->ScreenBufferSize.Y = HIWORD(dwValue);
    }

    //
    // Initial window size
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_WINDOWSIZE,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->WindowSize.X = LOWORD(dwValue);
        pStateInfo->WindowSize.Y = HIWORD(dwValue);
    }

    //
    // Initial window position
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_WINDOWPOS,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->WindowPosX = (SHORT)LOWORD(dwValue);
        pStateInfo->WindowPosY = (SHORT)HIWORD(dwValue);
        pStateInfo->AutoPosition = FALSE;
    }

    //
    // Initial font size
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_FONTSIZE,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->FontSize.X = LOWORD(dwValue);
        pStateInfo->FontSize.Y = HIWORD(dwValue);
    }

    //
    // Initial font family
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_FONTFAMILY,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->FontFamily = dwValue;
    }

    //
    // Initial font weight
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_FONTWEIGHT,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->FontWeight = dwValue;
    }

    //
    // Initial font face name
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_FACENAME,
                       sizeof(awchBuffer), (PBYTE)awchBuffer))) {
        RtlCopyMemory(pStateInfo->FaceName, awchBuffer, sizeof(awchBuffer));
    }

    //
    // Initial cursor size
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_CURSORSIZE,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->CursorSize = dwValue;
    }

    //
    // Initial history buffer size
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_HISTORYSIZE,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->HistoryBufferSize = dwValue;
    }

    //
    // Initial number of history buffers
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_HISTORYBUFS,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->NumberOfHistoryBuffers = dwValue;
    }

    //
    // Initial history duplication mode
    //

    if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
                       CONSOLE_REGISTRY_HISTORYNODUP,
                       sizeof(dwValue), (PBYTE)&dwValue))) {
        pStateInfo->HistoryNoDup = dwValue;
    }

    //
    // Close the registry keys
    //

    if (hTitleKey != hConsoleKey) {
        NtClose(hTitleKey);
    }

CloseKeys:
    NtClose(hConsoleKey);
    NtClose(hCurrentUserKey);

    return dwRet;
}


VOID
SetRegistryValues(
    PCONSOLE_STATE_INFO pStateInfo,
    DWORD dwPage
    )

/*++

Routine Description:

    This routine writes values to the registry from the supplied
    structure.

Arguments:

    pStateInfo - optional pointer to structure containing information
    dwPage     - current page number

Return Value:

    none

--*/

{
    HANDLE hCurrentUserKey;
    HANDLE hConsoleKey;
    HANDLE hTitleKey;
    NTSTATUS Status;
    LPWSTR TranslatedTitle;
    DWORD dwValue;
    DWORD i;
    WCHAR awchBuffer[LF_FACESIZE];

    //
    // Open the current user registry key
    //

    Status = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &hCurrentUserKey);
    if (!NT_SUCCESS(Status)) {
        return;
    }

    //
    // Open the console registry key
    //

    Status = MyRegCreateKey(hCurrentUserKey,
                            CONSOLE_REGISTRY_STRING,
                            &hConsoleKey);
    if (!NT_SUCCESS(Status)) {
        NtClose(hCurrentUserKey);
        return;
    }

    //
    // Save the current page
    //

    MyRegSetValue(hConsoleKey,
                  CONSOLE_REGISTRY_CURRENTPAGE,
                  REG_DWORD, &dwPage, sizeof(dwPage));

    //
    // If we only want to save the current page, bail out
    //

    if (pStateInfo == NULL) {
        goto CloseKeys;
    }

    //
    // Open the console title subkey, if there is one
    //

    if (pStateInfo->ConsoleTitle[0] != TEXT('\0')) {
        TranslatedTitle = TranslateConsoleTitle(pStateInfo->ConsoleTitle);
        if (TranslatedTitle == NULL) {
            NtClose(hConsoleKey);
            NtClose(hCurrentUserKey);
            return;
        }
        Status = MyRegCreateKey(hConsoleKey,
                                TranslatedTitle,
                                &hTitleKey);
        HeapFree(RtlProcessHeap(),0,TranslatedTitle);
        if (!NT_SUCCESS(Status)) {
            NtClose(hConsoleKey);
            NtClose(hCurrentUserKey);
            return;
        }
    } else {
        hTitleKey = hConsoleKey;
    }

    //
    // Save screen and popup colors and color table
    //

    dwValue = pStateInfo->ScreenAttributes;
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_FILLATTR,
                     REG_DWORD, &dwValue, sizeof(dwValue));
    dwValue = pStateInfo->PopupAttributes;
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_POPUPATTR,
                     REG_DWORD, &dwValue, sizeof(dwValue));
    for (i = 0; i < 16; i++) {
        dwValue = pStateInfo->ColorTable[i];
        wsprintf(awchBuffer, CONSOLE_REGISTRY_COLORTABLE, i);
        MyRegUpdateValue(hConsoleKey, hTitleKey, awchBuffer,
                         REG_DWORD, &dwValue, sizeof(dwValue));
    }

    //
    // Save insert, quickedit, and fullscreen mode settings
    //

    dwValue = pStateInfo->InsertMode;
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_INSERTMODE,
                     REG_DWORD, &dwValue, sizeof(dwValue));
    dwValue = pStateInfo->QuickEdit;
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_QUICKEDIT,
                     REG_DWORD, &dwValue, sizeof(dwValue));

    SaveAutoCompleteSetting(g_fAutoComplete);

#ifdef i386
    dwValue = pStateInfo->FullScreen;
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_FULLSCR,
                     REG_DWORD, &dwValue, sizeof(dwValue));
#endif
#if defined(FE_SB) // scotthsu

    ASSERT(OEMCP != 0);
    if (gfFESystem) {
        dwValue = (DWORD) pStateInfo->CodePage;
        MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_CODEPAGE,
                         REG_DWORD, &dwValue, sizeof(dwValue));
    }
#endif

    //
    // Save screen buffer size
    //

    dwValue = MAKELONG(pStateInfo->ScreenBufferSize.X,
                       pStateInfo->ScreenBufferSize.Y);
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_BUFFERSIZE,
                     REG_DWORD, &dwValue, sizeof(dwValue));

    //
    // Save window size
    //

    dwValue = MAKELONG(pStateInfo->WindowSize.X,
                       pStateInfo->WindowSize.Y);
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_WINDOWSIZE,
                     REG_DWORD, &dwValue, sizeof(dwValue));

    //
    // Save window position
    //

    if (pStateInfo->AutoPosition) {
        MyRegDeleteKey(hTitleKey, CONSOLE_REGISTRY_WINDOWPOS);
    } else {
        dwValue = MAKELONG(pStateInfo->WindowPosX,
                           pStateInfo->WindowPosY);
        MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_WINDOWPOS,
                         REG_DWORD, &dwValue, sizeof(dwValue));
    }

    //
    // Save font size, family, weight, and face name
    //

    dwValue = MAKELONG(pStateInfo->FontSize.X,
                       pStateInfo->FontSize.Y);
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_FONTSIZE,
                     REG_DWORD, &dwValue, sizeof(dwValue));
    dwValue = pStateInfo->FontFamily;
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_FONTFAMILY,
                     REG_DWORD, &dwValue, sizeof(dwValue));
    dwValue = pStateInfo->FontWeight;
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_FONTWEIGHT,
                     REG_DWORD, &dwValue, sizeof(dwValue));
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_FACENAME,
                     REG_SZ, pStateInfo->FaceName,
                      (_tcslen(pStateInfo->FaceName) + 1) * sizeof(TCHAR));

    //
    // Save cursor size
    //

    dwValue = pStateInfo->CursorSize;
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_CURSORSIZE,
                     REG_DWORD, &dwValue, sizeof(dwValue));

    //
    // Save history buffer size and number
    //

    dwValue = pStateInfo->HistoryBufferSize;
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_HISTORYSIZE,
                     REG_DWORD, &dwValue, sizeof(dwValue));
    dwValue = pStateInfo->NumberOfHistoryBuffers;
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_HISTORYBUFS,
                     REG_DWORD, &dwValue, sizeof(dwValue));
    dwValue = pStateInfo->HistoryNoDup;
    MyRegUpdateValue(hConsoleKey, hTitleKey, CONSOLE_REGISTRY_HISTORYNODUP,
                     REG_DWORD, &dwValue, sizeof(dwValue));

    //
    // Close the registry keys
    //

    if (hTitleKey != hConsoleKey) {
        NtClose(hTitleKey);
    }

CloseKeys:
    NtClose(hConsoleKey);
    NtClose(hCurrentUserKey);
}
