/*++ Copyright (c) 1990 Microsoft Corporation Module Name: misc.c Abstract: This file implements the NT console server font routines. Author: Therese Stowell (thereses) 22-Jan-1991 Revision History: --*/ #include "shellprv.h" #pragma hdrstop #include "lnkcon.h" #define CONSOLE_REGISTRY_STRING (TEXT("Console")) #define CONSOLE_REGISTRY_FONTSIZE (TEXT("FontSize")) #define CONSOLE_REGISTRY_FONTFAMILY (TEXT("FontFamily")) #define CONSOLE_REGISTRY_BUFFERSIZE (TEXT("ScreenBufferSize")) #define CONSOLE_REGISTRY_CURSORSIZE (TEXT("CursorSize")) #define CONSOLE_REGISTRY_WINDOWSIZE (TEXT("WindowSize")) #define CONSOLE_REGISTRY_WINDOWPOS (TEXT("WindowPosition")) #define CONSOLE_REGISTRY_FILLATTR (TEXT("ScreenColors")) #define CONSOLE_REGISTRY_POPUPATTR (TEXT("PopupColors")) #define CONSOLE_REGISTRY_FULLSCR (TEXT("FullScreen")) #define CONSOLE_REGISTRY_QUICKEDIT (TEXT("QuickEdit")) #define CONSOLE_REGISTRY_FACENAME (TEXT("FaceName")) #define CONSOLE_REGISTRY_FONTWEIGHT (TEXT("FontWeight")) #define CONSOLE_REGISTRY_INSERTMODE (TEXT("InsertMode")) #define CONSOLE_REGISTRY_HISTORYSIZE (TEXT("HistoryBufferSize")) #define CONSOLE_REGISTRY_HISTORYBUFS (TEXT("NumberOfHistoryBuffers")) #define CONSOLE_REGISTRY_HISTORYNODUP (TEXT("HistoryNoDup")) #define CONSOLE_REGISTRY_COLORTABLE (TEXT("ColorTable%02u")) #define CONSOLE_REGISTRY_CODEPAGE (TEXT("CodePage")) /* * Initial default fonts and face names */ /* * TTPoints -- Initial font pixel heights for TT fonts */ SHORT TTPoints[] = { 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 24, 28, 36, 72 }; /* * TTPointsDbcs -- Initial font pixel heights for TT fonts of DBCS. */ SHORT TTPointsDbcs[] = { 6, 8, 10, 12, 14, 16, 18, 20, 24, 28, 36, 72 }; typedef struct _FONTENUMDATA { CONSOLEPROP_DATA *pcpd; HDC hDC; BOOL bFindFaces; ULONG ulFE; PSHORT pTTPoints; UINT nTTPoints; UINT uDefCP; } FONTENUMDATA, *PFONTENUMDATA; FACENODE * AddFaceNode(FACENODE * *ppStart, LPTSTR ptsz) { FACENODE * pNew; FACENODE * *ppTmp; UINT cch; int cb; HRESULT hr; /* * Is it already here? */ for (ppTmp = ppStart; *ppTmp; ppTmp = &((*ppTmp)->pNext)) { if (lstrcmp(((*ppTmp)->atch), ptsz) == 0) { // already there ! return *ppTmp; } } cch = lstrlen(ptsz) + 1; cb = cch * sizeof(TCHAR); pNew = (FACENODE *)LocalAlloc(LPTR ,sizeof(FACENODE) + cb); if (pNew == NULL) { return NULL; } pNew->pNext = NULL; pNew->dwFlag = 0; hr = StringCchCopy(pNew->atch, cch, ptsz); if (FAILED(hr)) { LocalFree(pNew); // return as failure to allocate pNew = NULL; } *ppTmp = pNew; return pNew; } VOID DestroyFaceNodes( CONSOLEPROP_DATA *pcpd ) { FACENODE * pNext; FACENODE * pTmp; pTmp = pcpd->gpFaceNames; while (pTmp != NULL) { pNext = pTmp->pNext; LocalFree(pTmp); pTmp = pNext; } pcpd->gpFaceNames = NULL; } int AddFont( CONSOLEPROP_DATA *pcpd, ENUMLOGFONT *pelf, NEWTEXTMETRIC *pntm, int nFontType, HDC hDC, FACENODE * pFN ) /*++ Add the font desribed by the LOGFONT structure to the font table if it's not already there. --*/ { HFONT hFont; TEXTMETRIC tm; LONG nFont; COORD SizeToShow; COORD SizeActual; COORD SizeWant; BYTE tmFamily; SIZE Size; LPTSTR ptszFace = pelf->elfLogFont.lfFaceName; /* get font info */ SizeWant.Y = (SHORT)pelf->elfLogFont.lfHeight; SizeWant.X = (SHORT)pelf->elfLogFont.lfWidth; CreateBoldFont: hFont = CreateFontIndirect(&pelf->elfLogFont); ASSERT(hFont); if (!hFont) { return FE_SKIPFONT; // same font in other sizes may still be suitable } // // for reasons unbeknownst to me, removing this code causes GDI // to yack, claiming that the font is owned by another process. // SelectObject(hDC, hFont); GetTextMetrics(hDC, &tm); GetTextExtentPoint32(hDC, TEXT("0"), 1, &Size); SizeActual.X = (SHORT)Size.cx; SizeActual.Y = (SHORT)(tm.tmHeight + tm.tmExternalLeading); tmFamily = tm.tmPitchAndFamily; if (TM_IS_TT_FONT(tmFamily) && (SizeWant.Y >= 0)) { SizeToShow = SizeWant; if (SizeWant.X == 0) { // Asking for zero width height gets a default aspect-ratio width // It's better to show that width rather than 0. SizeToShow.X = SizeActual.X; } } else { SizeToShow = SizeActual; } // there's a GDI bug - this assert fails occasionally //ASSERT (tm.tmMaxCharWidth == pntm->tmMaxCharWidth); /* * NOW, determine whether this font entry has already been cached * LATER : it may be possible to do this before creating the font, if * we can trust the dimensions & other info from pntm. * Sort by size: * 1) By pixelheight (negative Y values) * 2) By height (as shown) * 3) By width (as shown) */ for (nFont = 0; nFont < (LONG)pcpd->NumberOfFonts; ++nFont) { COORD SizeShown; if (pcpd->FontInfo[nFont].hFont == NULL) { continue; } if (pcpd->FontInfo[nFont].SizeWant.X > 0) { SizeShown.X = pcpd->FontInfo[nFont].SizeWant.X; } else { SizeShown.X = pcpd->FontInfo[nFont].Size.X; } if (pcpd->FontInfo[nFont].SizeWant.Y > 0) { // This is a font specified by cell height. SizeShown.Y = pcpd->FontInfo[nFont].SizeWant.Y; } else { SizeShown.Y = pcpd->FontInfo[nFont].Size.Y; if (pcpd->FontInfo[nFont].SizeWant.Y < 0) { // This is a TT font specified by character height. if (SizeWant.Y < 0 && SizeWant.Y > pcpd->FontInfo[nFont].SizeWant.Y) { // Requested pixelheight is smaller than this one. break; } } } if (SIZE_EQUAL(SizeShown, SizeToShow) && pcpd->FontInfo[nFont].Family == tmFamily && pcpd->FontInfo[nFont].Weight == tm.tmWeight && lstrcmp(pcpd->FontInfo[nFont].FaceName, ptszFace) == 0) { /* * Already have this font */ DeleteObject(hFont); return FE_FONTOK; } if ((SizeToShow.Y < SizeShown.Y) || (SizeToShow.Y == SizeShown.Y && SizeToShow.X < SizeShown.X)) { /* * This new font is smaller than nFont */ break; } } /* * If we have to grow our font table, do it */ if (pcpd->NumberOfFonts == pcpd->FontInfoLength) { FONT_INFO *Temp; pcpd->FontInfoLength += FONT_INCREMENT; Temp = (FONT_INFO *)LocalReAlloc(pcpd->FontInfo, sizeof(FONT_INFO) * pcpd->FontInfoLength, LMEM_MOVEABLE|LMEM_ZEROINIT); ASSERT(Temp); if (Temp == NULL) { pcpd->FontInfoLength -= FONT_INCREMENT; return FE_ABANDONFONT; // no point enumerating more - no memory! } pcpd->FontInfo = Temp; } /* * The font we are adding should be inserted into the list, * if it is smaller than the last one. */ if (nFont < (LONG)pcpd->NumberOfFonts) { MoveMemory( &pcpd->FontInfo[nFont+1], &pcpd->FontInfo[nFont], sizeof(FONT_INFO) * (pcpd->NumberOfFonts - nFont) ); } /* * Store the font info */ pcpd->FontInfo[nFont].hFont = hFont; pcpd->FontInfo[nFont].Family = tmFamily; pcpd->FontInfo[nFont].Size = SizeActual; if (TM_IS_TT_FONT(tmFamily)) { pcpd->FontInfo[nFont].SizeWant = SizeWant; } else { pcpd->FontInfo[nFont].SizeWant.X = 0; pcpd->FontInfo[nFont].SizeWant.Y = 0; } pcpd->FontInfo[nFont].Weight = tm.tmWeight; pcpd->FontInfo[nFont].FaceName = pFN->atch; pcpd->FontInfo[nFont].tmCharSet = tm.tmCharSet; ++pcpd->NumberOfFonts; /* * If this is a true type font, create a bold version too. */ if (nFontType == TRUETYPE_FONTTYPE && !IS_BOLD(pcpd->FontInfo[nFont].Weight)) { pelf->elfLogFont.lfWeight = FW_BOLD; goto CreateBoldFont; } return FE_FONTOK; // and continue enumeration } NTSTATUS InitializeFonts( CONSOLEPROP_DATA *pcpd ) { return EnumerateFonts( pcpd, EF_DEFFACE); // Just the Default font } STDAPI_(void) DestroyFonts( CONSOLEPROP_DATA *pcpd ) { ULONG FontIndex; if (pcpd->FontInfo != NULL) { for (FontIndex = 0; FontIndex < pcpd->NumberOfFonts; FontIndex++) { DeleteObject(pcpd->FontInfo[FontIndex].hFont); } LocalFree(pcpd->FontInfo); pcpd->FontInfo = NULL; pcpd->NumberOfFonts = 0; } DestroyFaceNodes( pcpd ); } /* * Returns bit combination * FE_ABANDONFONT - do not continue enumerating this font * FE_SKIPFONT - skip this font but keep enumerating * FE_FONTOK - font was created and added to cache or already there */ int FontEnum( ENUMLOGFONT *pelf, NEWTEXTMETRIC *pntm, int nFontType, PFONTENUMDATA pfed ) /*++ Is called exactly once by GDI for each font in the system. This routine is used to store the FONT_INFO structure. --*/ { UINT i; LPTSTR ptszFace = pelf->elfLogFont.lfFaceName; FACENODE * pFN; BOOL bNegAC; #ifdef DEBUG OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx(&osvi); // NTMW_STRUCTURE is different on 5.0+ platforms and the flag for 5.0+ // platforms now lives in NEWTEXTMETRIC structure. AssertMsg(osvi.dwMajorVersion > 4, TEXT("We now only support running on Win2k or Millennium and later so we should never hit this.")); #endif bNegAC = !(pntm->ntmFlags & NTM_NONNEGATIVE_AC); // // reject variable width and italic fonts, also tt fonts with neg ac // if ( !(pelf->elfLogFont.lfPitchAndFamily & FIXED_PITCH) || (pelf->elfLogFont.lfItalic) || bNegAC ) { if (!IsAvailableTTFont(pfed->pcpd,ptszFace)) return pfed->bFindFaces ? FE_SKIPFONT : FE_ABANDONFONT; } /* * reject TT fonts for whoom family is not modern, that is do not use * FF_DONTCARE // may be surprised unpleasantly * FF_DECORATIVE // likely to be symbol fonts * FF_SCRIPT // cursive, inappropriate for console * FF_SWISS OR FF_ROMAN // variable pitch */ if ((nFontType == TRUETYPE_FONTTYPE) && ((pelf->elfLogFont.lfPitchAndFamily & 0xf0) != FF_MODERN)) { return pfed->bFindFaces ? FE_SKIPFONT : FE_ABANDONFONT; } /* * reject non-TT fonts that aren't OEM */ if ((nFontType != TRUETYPE_FONTTYPE) && (!IsFarEastCP(pfed->uDefCP) || !IS_ANY_DBCS_CHARSET(pelf->elfLogFont.lfCharSet)) && (pelf->elfLogFont.lfCharSet != OEM_CHARSET)) { return pfed->bFindFaces ? FE_SKIPFONT : FE_ABANDONFONT; } /* * reject non-TT vertical/non-Terminal Font for FE */ if (IsFarEastCP(pfed->uDefCP)) { if ((nFontType != TRUETYPE_FONTTYPE) && ((ptszFace[0] == TEXT('@')) || (lstrcmp(ptszFace, TEXT("Terminal")) != 0))) { return pfed->bFindFaces ? FE_SKIPFONT : FE_ABANDONFONT; } } /* * reject Far East TT fonts that aren't Far East charset. */ if (IsAvailableTTFont(pfed->pcpd, ptszFace) && !IS_ANY_DBCS_CHARSET(pelf->elfLogFont.lfCharSet) && !IsAvailableTTFontCP(pfed->pcpd, ptszFace,0) ) { return FE_SKIPFONT; // should be enumerate next charset. } /* * Add or find the facename */ pFN = AddFaceNode(&pfed->pcpd->gpFaceNames, ptszFace); if (pFN == NULL) { return FE_ABANDONFONT; } if (pfed->bFindFaces) { DWORD dwFontType = 0; if (nFontType == TRUETYPE_FONTTYPE) { dwFontType = EF_TTFONT; } else if (nFontType == RASTER_FONTTYPE) { dwFontType = EF_OEMFONT; } pFN->dwFlag |= dwFontType | EF_NEW; if (IS_ANY_DBCS_CHARSET(pelf->elfLogFont.lfCharSet)) pFN->dwFlag |= EF_DBCSFONT; return FE_SKIPFONT; } if (IS_BOLD(pelf->elfLogFont.lfWeight)) { // return FE_SKIPFONT; } /* * Add the font to the table. If this is a true type font, add the * sizes from the array. Otherwise, just add the size we got. */ if (nFontType & TRUETYPE_FONTTYPE) { for (i = 0; i < pfed->nTTPoints; i++) { pelf->elfLogFont.lfHeight = pfed->pTTPoints[i]; pelf->elfLogFont.lfWidth = 0; pelf->elfLogFont.lfWeight = 400; pfed->ulFE |= AddFont(pfed->pcpd, pelf, pntm, nFontType, pfed->hDC, pFN); if (pfed->ulFE & FE_ABANDONFONT) { return FE_ABANDONFONT; } } } else { pfed->ulFE |= AddFont(pfed->pcpd, pelf, pntm, nFontType, pfed->hDC, pFN); if (pfed->ulFE & FE_ABANDONFONT) { return FE_ABANDONFONT; } } return FE_FONTOK; // and continue enumeration } BOOL DoFontEnum( CONSOLEPROP_DATA *pcpd, HDC hDC, LPTSTR ptszFace, PSHORT pTTPoints, UINT nTTPoints) { BOOL bDeleteDC = FALSE; FONTENUMDATA fed; LOGFONT LogFont; HRESULT hr = S_OK; if (hDC == NULL) { hDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL); bDeleteDC = TRUE; } fed.pcpd = pcpd; fed.hDC = hDC; fed.bFindFaces = (ptszFace == NULL); fed.ulFE = 0; fed.pTTPoints = pTTPoints; fed.nTTPoints = nTTPoints; fed.uDefCP = pcpd->uOEMCP; RtlZeroMemory(&LogFont, sizeof(LOGFONT)); LogFont.lfCharSet = DEFAULT_CHARSET; if (ptszFace) { hr = StringCchCopy(LogFont.lfFaceName, ARRAYSIZE(LogFont.lfFaceName), ptszFace); } if (SUCCEEDED(hr)) { /* * EnumFontFamiliesEx function enumerates one font in every face in every character set. */ EnumFontFamiliesEx(hDC, &LogFont, (FONTENUMPROC)FontEnum, (LPARAM)&fed, 0); } if (bDeleteDC) { DeleteDC(hDC); } return (fed.ulFE & FE_FONTOK) != 0; } VOID RemoveFace(CONSOLEPROP_DATA *pcpd, LPTSTR ptszFace) { DWORD i; int nToRemove = 0; // // Delete & Remove fonts with Face Name == ptszFace // for (i = 0; i < pcpd->NumberOfFonts; i++) { if (lstrcmp(pcpd->FontInfo[i].FaceName, ptszFace) == 0) { BOOL bDeleted = DeleteObject(pcpd->FontInfo[i].hFont); pcpd->FontInfo[i].hFont = NULL; nToRemove++; } else if (nToRemove > 0) { /* * Shuffle from FontInfo[i] down nToRemove slots. */ MoveMemory( &pcpd->FontInfo[i - nToRemove], &pcpd->FontInfo[i], sizeof(FONT_INFO)*(pcpd->NumberOfFonts - i) ); pcpd->NumberOfFonts -= nToRemove; i -= nToRemove; nToRemove = 0; } } pcpd->NumberOfFonts -= nToRemove; } NTSTATUS EnumerateFonts( CONSOLEPROP_DATA *pcpd, DWORD Flags) { TEXTMETRIC tm; HDC hDC; FACENODE * pFN; ULONG ulOldEnumFilter; BOOL bEnumOEMFace = TRUE; DWORD FontIndex; DWORD dwFontType = 0; dwFontType = (EF_TTFONT|EF_OEMFONT|EF_DEFFACE) & Flags; if (pcpd->FontInfo == NULL) { // // allocate memory for the font array // pcpd->NumberOfFonts = 0; pcpd->FontInfo = (FONT_INFO *)LocalAlloc(LPTR, sizeof(FONT_INFO) * INITIAL_FONTS); if (pcpd->FontInfo == NULL) return STATUS_NO_MEMORY; pcpd->FontInfoLength = INITIAL_FONTS; } hDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL); // Before enumeration, turn off font enumeration filters. ulOldEnumFilter = SetFontEnumeration(FE_FILTER_NONE); if (Flags & EF_DEFFACE) { SelectObject(hDC, GetStockObject(OEM_FIXED_FONT)); GetTextFace(hDC, LF_FACESIZE, pcpd->DefaultFaceName); // Make sure we are going to enumerate the OEM face. pFN = AddFaceNode(&pcpd->gpFaceNames, pcpd->DefaultFaceName); if (NULL == pFN) { LocalFree(pcpd->FontInfo); pcpd->FontInfo = NULL; pcpd->FontInfoLength = 0; pcpd->NumberOfFonts = 0; SetFontEnumeration(ulOldEnumFilter); DeleteDC(hDC); return STATUS_NO_MEMORY; } pFN->dwFlag |= EF_DEFFACE | EF_OEMFONT; GetTextMetrics(hDC, &tm); pcpd->DefaultFontSize.X = (SHORT)(tm.tmMaxCharWidth); pcpd->DefaultFontSize.Y = (SHORT)(tm.tmHeight+tm.tmExternalLeading); pcpd->DefaultFontFamily = tm.tmPitchAndFamily; if (IS_ANY_DBCS_CHARSET(tm.tmCharSet)) pcpd->DefaultFontSize.X /= 2; } if (pcpd->gbEnumerateFaces) { /* * Set the EF_OLD bit and clear the EF_NEW bit * for all previously available faces */ for (pFN = pcpd->gpFaceNames; pFN; pFN = pFN->pNext) { pFN->dwFlag |= EF_OLD; pFN->dwFlag &= ~EF_NEW; } // // Use DoFontEnum to get the names of all the suitable Faces // All facenames found will be put in gpFaceNames with // the EF_NEW bit set. // DoFontEnum(pcpd, hDC, NULL, TTPoints, 1); pcpd->gbEnumerateFaces = FALSE; } // Use DoFontEnum to get all fonts from the system. Our FontEnum // proc puts just the ones we want into an array // for (pFN = pcpd->gpFaceNames; pFN; pFN = pFN->pNext) { if ((pFN->dwFlag & (EF_OLD|EF_NEW)) == EF_OLD) { // The face is no longer available RemoveFace(pcpd, pFN->atch); pFN->dwFlag &= ~EF_ENUMERATED; continue; } if ((pFN->dwFlag & dwFontType) == 0) { // not the kind of face we want continue; } if (pFN->dwFlag & EF_ENUMERATED) { // we already enumerated this face continue; } if (pFN->dwFlag & EF_TTFONT) { if (IsFarEastCP(pcpd->uOEMCP) && !IsAvailableTTFontCP(pcpd, pFN->atch, 0)) DoFontEnum(pcpd, hDC, pFN->atch, TTPointsDbcs, NELEM(TTPointsDbcs)); else DoFontEnum(pcpd, hDC, pFN->atch, TTPoints, NELEM(TTPoints)); } else { DoFontEnum(pcpd, hDC, pFN->atch, NULL, 0); // If we find that the face just enumerated is the same as OEM, // reset flag so we don't try to enumerate it again. if (lstrcmpi(pFN->atch, pcpd->DefaultFaceName) == 0) { bEnumOEMFace = FALSE; } } pFN->dwFlag |= EF_ENUMERATED; } // After enumerating fonts, restore the font enumeration filter. SetFontEnumeration(ulOldEnumFilter); DeleteDC(hDC); for (FontIndex = 0; FontIndex < pcpd->NumberOfFonts; FontIndex++) { if (pcpd->FontInfo[FontIndex].Size.X == pcpd->DefaultFontSize.X && pcpd->FontInfo[FontIndex].Size.Y == pcpd->DefaultFontSize.Y && pcpd->FontInfo[FontIndex].Family == pcpd->DefaultFontFamily) { break; } } ASSERT(FontIndex < pcpd->NumberOfFonts); if (FontIndex < pcpd->NumberOfFonts) { pcpd->DefaultFontIndex = FontIndex; } else { pcpd->DefaultFontIndex = 0; } return STATUS_SUCCESS; } /* * Get the font index for a new font * If necessary, attempt to create the font. * Always return a valid FontIndex (even if not correct) * Family: Find/Create a font with of this Family * 0 - don't care * ptszFace: Find/Create a font with this face name. * NULL or TEXT("") - use DefaultFaceName * Size: Must match SizeWant or actual Size. */ int FindCreateFont( CONSOLEPROP_DATA *pcpd, DWORD Family, LPTSTR ptszFace, COORD Size, LONG Weight) { #define NOT_CREATED_NOR_FOUND -1 #define CREATED_BUT_NOT_FOUND -2 int i; int FontIndex = NOT_CREATED_NOR_FOUND; BOOL bFontOK; TCHAR AltFaceName[LF_FACESIZE]; COORD AltFontSize; BYTE AltFontFamily; ULONG AltFontIndex = 0; LPTSTR ptszAltFace = NULL; UINT uCurrentCP = pcpd->lpFEConsole->uCodePage; UINT uDefaultCP = pcpd->uOEMCP; BYTE CharSet = CodePageToCharSet(uCurrentCP); if (!IsFarEastCP(uDefaultCP) || IS_ANY_DBCS_CHARSET(CharSet)) { if (ptszFace == NULL || *ptszFace == TEXT('\0')) { ptszFace = pcpd->DefaultFaceName; } if (Size.Y == 0) { Size = pcpd->DefaultFontSize; } } else { MakeAltRasterFont(pcpd, uCurrentCP, &AltFontSize, &AltFontFamily, &AltFontIndex, AltFaceName, ARRAYSIZE(AltFaceName)); if (ptszFace == NULL || *ptszFace == L'\0') { ptszFace = AltFaceName; } if (Size.Y == 0) { Size.X = AltFontSize.X; Size.Y = AltFontSize.Y; } } if (IsAvailableTTFont(pcpd, ptszFace)) { ptszAltFace = GetAltFaceName(pcpd, ptszFace); } else { ptszAltFace = ptszFace; } /* * Try to find the exact font */ TryFindExactFont: for (i=0; i < (int)pcpd->NumberOfFonts; i++) { /* * If looking for a particular Family, skip non-matches */ if ((Family != 0) && ((BYTE)Family != pcpd->FontInfo[i].Family)) { continue; } /* * Skip non-matching sizes */ if ((!SIZE_EQUAL(pcpd->FontInfo[i].SizeWant, Size) && !SIZE_EQUAL(pcpd->FontInfo[i].Size, Size))) { continue; } /* * Skip non-matching weights */ if ((Weight != 0) && (Weight != pcpd->FontInfo[i].Weight)) { continue; } /* * Skip fonts that have unmatched charset */ if (!TM_IS_TT_FONT(pcpd->FontInfo[i].Family) && pcpd->FontInfo[i].tmCharSet != CharSet) { continue; } /* * Size (and maybe Family) match. * If we don't care about the name, or if it matches, use this font. * Else if name doesn't match and it is a raster font, consider it. */ if ((ptszFace == NULL) || (ptszFace[0] == TEXT('\0')) || (lstrcmp(pcpd->FontInfo[i].FaceName, ptszFace) == 0) || (lstrcmp(pcpd->FontInfo[i].FaceName, ptszAltFace) == 0) ) { FontIndex = i; goto FoundFont; } else if (!TM_IS_TT_FONT(pcpd->FontInfo[i].Family)) { FontIndex = i; } } if (FontIndex == NOT_CREATED_NOR_FOUND) { /* * Didn't find the exact font, so try to create it */ ULONG ulOldEnumFilter; ulOldEnumFilter = SetFontEnumeration(FE_FILTER_NONE); if (Size.Y < 0) { Size.Y = -Size.Y; } bFontOK = DoFontEnum(pcpd, NULL, ptszFace, &Size.Y, 1); SetFontEnumeration(ulOldEnumFilter); if (bFontOK) { FontIndex = CREATED_BUT_NOT_FOUND; goto TryFindExactFont; } else { } } else if (FontIndex >= 0) { // a close Raster Font fit - only the name doesn't match. goto FoundFont; } /* * Failed to find exact match, even after enumeration, so now try * to find a font of same family and same size or bigger */ for (i=0; i < (int)pcpd->NumberOfFonts; i++) { if ((Family != 0) && ((BYTE)Family != pcpd->FontInfo[i].Family)) { continue; } if (!TM_IS_TT_FONT(pcpd->FontInfo[i].Family) && pcpd->FontInfo[i].tmCharSet != CharSet) { continue; } if (pcpd->FontInfo[i].Size.Y >= Size.Y && pcpd->FontInfo[i].Size.X >= Size.X) { // Same family, size >= desired. FontIndex = i; break; } } if (FontIndex < 0) { if (uCurrentCP == uDefaultCP) { FontIndex = pcpd->DefaultFontIndex; } else { FontIndex = AltFontIndex; } } FoundFont: return FontIndex; #undef NOT_CREATED_NOR_FOUND #undef CREATED_BUT_NOT_FOUND } LPTSTR TranslateConsoleTitle( LPTSTR 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; LPTSTR TranslatedTitle; ConsoleTitleLength = lstrlen(ConsoleTitle) + 1; TranslatedTitle = LocalAlloc(LPTR, ConsoleTitleLength * sizeof(TCHAR)); if (TranslatedTitle == NULL) { return NULL; } for (i = 0; i < ConsoleTitleLength; i++) { if (ConsoleTitle[i] == TEXT('\\')) { TranslatedTitle[i] = TEXT('_'); } else { TranslatedTitle[i] = ConsoleTitle[i]; } } return TranslatedTitle; } void InitRegistryValues( CONSOLEPROP_DATA *pcpd ) /*++ Routine Description: This routine allocates a state info structure and fill it in with default values. It then tries to load the default settings for console from the registry. Arguments: none Return Value: pStateInfo - pointer to structure to receive information --*/ { TCHAR chSave; pcpd->lpConsole->wFillAttribute = 0x07; // white on black pcpd->lpConsole->wPopupFillAttribute = 0xf5; // purple on white pcpd->lpConsole->bInsertMode = FALSE; pcpd->lpConsole->bQuickEdit = FALSE; pcpd->lpConsole->bFullScreen = FALSE; pcpd->lpConsole->dwScreenBufferSize.X = 80; pcpd->lpConsole->dwScreenBufferSize.Y = 25; pcpd->lpConsole->dwWindowSize.X = 80; pcpd->lpConsole->dwWindowSize.Y = 25; pcpd->lpConsole->dwWindowOrigin.X = 0; pcpd->lpConsole->dwWindowOrigin.Y = 0; pcpd->lpConsole->bAutoPosition = TRUE; pcpd->lpConsole->dwFontSize.X = 0; pcpd->lpConsole->dwFontSize.Y = 0; pcpd->lpConsole->uFontFamily = 0; pcpd->lpConsole->uFontWeight = 0; #ifdef UNICODE FillMemory( pcpd->lpConsole->FaceName, sizeof(pcpd->lpConsole->FaceName), 0 ); pcpd->lpFaceName = (LPTSTR)pcpd->lpConsole->FaceName; #else FillMemory( pcpd->szFaceName, sizeof(pcpd->szFaceName), 0 ); pcpd->lpFaceName = pcpd->szFaceName; #endif pcpd->lpConsole->uCursorSize = 25; pcpd->lpConsole->uHistoryBufferSize = 25; pcpd->lpConsole->uNumberOfHistoryBuffers = 4; pcpd->lpConsole->bHistoryNoDup = 0; pcpd->lpConsole->ColorTable[ 0] = RGB(0, 0, 0 ); pcpd->lpConsole->ColorTable[ 1] = RGB(0, 0, 0x80); pcpd->lpConsole->ColorTable[ 2] = RGB(0, 0x80,0 ); pcpd->lpConsole->ColorTable[ 3] = RGB(0, 0x80,0x80); pcpd->lpConsole->ColorTable[ 4] = RGB(0x80,0, 0 ); pcpd->lpConsole->ColorTable[ 5] = RGB(0x80,0, 0x80); pcpd->lpConsole->ColorTable[ 6] = RGB(0x80,0x80,0 ); pcpd->lpConsole->ColorTable[ 7] = RGB(0xC0,0xC0,0xC0); pcpd->lpConsole->ColorTable[ 8] = RGB(0x80,0x80,0x80); pcpd->lpConsole->ColorTable[ 9] = RGB(0, 0, 0xFF); pcpd->lpConsole->ColorTable[10] = RGB(0, 0xFF,0 ); pcpd->lpConsole->ColorTable[11] = RGB(0, 0xFF,0xFF); pcpd->lpConsole->ColorTable[12] = RGB(0xFF,0, 0 ); pcpd->lpConsole->ColorTable[13] = RGB(0xFF,0, 0xFF); pcpd->lpConsole->ColorTable[14] = RGB(0xFF,0xFF,0 ); pcpd->lpConsole->ColorTable[15] = RGB(0xFF,0xFF,0xFF); pcpd->lpFEConsole->uCodePage = pcpd->uOEMCP; // make console title NULL so we load the default settings for the console chSave = pcpd->ConsoleTitle[0]; pcpd->ConsoleTitle[0] = TEXT('\0'); GetRegistryValues( pcpd ); // restore the console title pcpd->ConsoleTitle[0] = chSave; } VOID GetTitleFromLinkName( LPTSTR szLinkName, LPTSTR szTitle, UINT cchTitle ) { LPTSTR pLnk, pDot; LPTSTR pPath = szLinkName; HRESULT hr; // Error checking if (!szTitle) return; if (!szLinkName) { szTitle[0] = TEXT('\0'); return; } // find filename at end of fully qualified link name and point pLnk to it for (pLnk = pPath; *pPath; pPath++) { if ( (pPath[0] == TEXT('\\') || pPath[0] == TEXT(':')) && pPath[1] && (pPath[1] != TEXT('\\')) ) pLnk = pPath + 1; } // find extension (.lnk) pPath = pLnk; for (pDot = NULL; *pPath; pPath++) { switch (*pPath) { case TEXT('.'): pDot = pPath; // remember the last dot break; case TEXT('\\'): case TEXT(' '): // extensions can't have spaces pDot = NULL; // forget last dot, it was in a directory break; } } // if we found the extension, pDot points to it, if not, pDot // is NULL. if (pDot) { hr = StringCchCopyN(szTitle, cchTitle, pLnk, pDot - pLnk); } else { hr = StringCchCopy(szTitle, cchTitle, pLnk); } if (FAILED(hr)) { szTitle[0] = TEXT('\0'); } } VOID GetRegistryValues( CONSOLEPROP_DATA *pcpd ) /*++ 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 --*/ { HKEY hConsoleKey; HKEY hTitleKey; LPTSTR TranslatedTitle; DWORD dwValue, dwSize; DWORD dwRet = 0; DWORD i; WCHAR awchBuffer[LF_FACESIZE]; // // Open the console registry key // if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER, CONSOLE_REGISTRY_STRING, 0, KEY_QUERY_VALUE, &hConsoleKey)) { return; } // // If there is no structure to fill out, just bail out // if ((!pcpd) || (!pcpd->lpConsole)) goto CloseKey; // // Open the console title subkey, if there is one // if (pcpd->ConsoleTitle[0] != TEXT('\0')) { TranslatedTitle = TranslateConsoleTitle(pcpd->ConsoleTitle); if (TranslatedTitle == NULL) goto GetDefaultConsole; dwValue = RegOpenKeyEx( hConsoleKey, TranslatedTitle, 0, KEY_QUERY_VALUE, &hTitleKey); LocalFree(TranslatedTitle); if (dwValue!=ERROR_SUCCESS) goto GetDefaultConsole; } else { GetDefaultConsole: hTitleKey = hConsoleKey; } // // Initial screen fill // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_FILLATTR, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->wFillAttribute = (WORD)dwValue; } // // Initial popup fill // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_POPUPATTR, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->wPopupFillAttribute = (WORD)dwValue; } // // Initial color table // for (i = 0; i < 16; i++) { StringCchPrintf(awchBuffer, ARRAYSIZE(awchBuffer), CONSOLE_REGISTRY_COLORTABLE, i); // ok to truncate - read will just fail dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, (LPTSTR)awchBuffer, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->ColorTable[i] = dwValue; } } // // Initial insert mode // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_INSERTMODE, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->bInsertMode = !!dwValue; } // // Initial quick edit mode // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_QUICKEDIT, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->bQuickEdit = !!dwValue; } #ifdef i386 // // Initial full screen mode // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_FULLSCR, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->bFullScreen = !!dwValue; } #endif // // Initial code page // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_CODEPAGE, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpFEConsole->uCodePage = (UINT)dwValue; } // // Initial screen buffer size // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_BUFFERSIZE, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->dwScreenBufferSize.X = LOWORD(dwValue); pcpd->lpConsole->dwScreenBufferSize.Y = HIWORD(dwValue); } // // Initial window size // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_WINDOWSIZE, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->dwWindowSize.X = LOWORD(dwValue); pcpd->lpConsole->dwWindowSize.Y = HIWORD(dwValue); } // // Initial window position // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_WINDOWPOS, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->dwWindowOrigin.X = (SHORT)LOWORD(dwValue); pcpd->lpConsole->dwWindowOrigin.Y = (SHORT)HIWORD(dwValue); pcpd->lpConsole->bAutoPosition = FALSE; } // // Initial font size // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_FONTSIZE, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->dwFontSize.X = LOWORD(dwValue); pcpd->lpConsole->dwFontSize.Y = HIWORD(dwValue); } // // Initial font family // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_FONTFAMILY, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->uFontFamily = dwValue; } // // Initial font weight // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_FONTWEIGHT, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->uFontWeight = dwValue; } // // Initial font face name // dwSize = sizeof(awchBuffer); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_FACENAME, NULL, NULL, (LPBYTE)awchBuffer, &dwSize ) == ERROR_SUCCESS) { CopyMemory((LPBYTE)pcpd->lpFaceName, (LPBYTE)awchBuffer, LF_FACESIZE*sizeof(TCHAR)); pcpd->lpFaceName[ARRAYSIZE(pcpd->lpFaceName)-1] = TEXT('\0'); } // // Initial cursor size // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_CURSORSIZE, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->uCursorSize = dwValue; } // // Initial history buffer size // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_HISTORYSIZE, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->uHistoryBufferSize = dwValue; } // // Initial number of history buffers // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_HISTORYBUFS, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->uNumberOfHistoryBuffers = dwValue; } // // Initial history duplication mode // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_HISTORYNODUP, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpConsole->bHistoryNoDup = dwValue; } // // Close the registry keys // if (hTitleKey != hConsoleKey) { RegCloseKey(hTitleKey); } CloseKey: RegCloseKey(hConsoleKey); } VOID SetRegistryValues( CONSOLEPROP_DATA *pcpd ) /*++ 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 --*/ { HKEY hConsoleKey; HKEY hTitleKey; LPTSTR TranslatedTitle; DWORD dwValue; DWORD i; WCHAR awchBuffer[LF_FACESIZE]; // // Open the console registry key // if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, CONSOLE_REGISTRY_STRING, 0, NULL, 0, KEY_SET_VALUE, NULL, &hConsoleKey, NULL)) { return; } // // If we only want to save the current page, bail out // if (pcpd == NULL) { goto CloseKey; } // // Open the console title subkey, if there is one // if (pcpd->ConsoleTitle[0] != TEXT('\0')) { TranslatedTitle = TranslateConsoleTitle(pcpd->ConsoleTitle); if (TranslatedTitle == NULL) { RegCloseKey(hConsoleKey); return; } dwValue = RegCreateKeyEx( hConsoleKey, TranslatedTitle, 0, NULL, 0, KEY_SET_VALUE, NULL, &hTitleKey, NULL); LocalFree(TranslatedTitle); if (dwValue!=ERROR_SUCCESS) { RegCloseKey(hConsoleKey); return; } } else { hTitleKey = hConsoleKey; } // // Save screen and popup colors and color table // dwValue = pcpd->lpConsole->wFillAttribute; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_FILLATTR, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); dwValue = pcpd->lpConsole->wPopupFillAttribute; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_POPUPATTR, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); for (i = 0; i < 16; i++) { dwValue = pcpd->lpConsole->ColorTable[i]; StringCchPrintf(awchBuffer, ARRAYSIZE(awchBuffer), CONSOLE_REGISTRY_COLORTABLE, i); // truncation will never happen RegSetValueEx( hTitleKey, (LPTSTR)awchBuffer, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); } // // Save insert, quickedit, and fullscreen mode settings // dwValue = pcpd->lpConsole->bInsertMode; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_INSERTMODE, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); dwValue = pcpd->lpConsole->bQuickEdit; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_QUICKEDIT, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); #ifdef i386 dwValue = pcpd->lpConsole->bFullScreen; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_FULLSCR, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); #endif // // Save screen buffer size // dwValue = MAKELONG(pcpd->lpConsole->dwScreenBufferSize.X, pcpd->lpConsole->dwScreenBufferSize.Y); RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_BUFFERSIZE, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); // // Save window size // dwValue = MAKELONG(pcpd->lpConsole->dwWindowSize.X, pcpd->lpConsole->dwWindowSize.Y); RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_WINDOWSIZE, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); // // Save window position // if (pcpd->lpConsole->bAutoPosition) { RegDeleteKey(hTitleKey, CONSOLE_REGISTRY_WINDOWPOS); } else { dwValue = MAKELONG(pcpd->lpConsole->dwWindowOrigin.X, pcpd->lpConsole->dwWindowOrigin.Y); RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_WINDOWPOS, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); } // // Save font size, family, weight, and face name // dwValue = MAKELONG(pcpd->lpConsole->dwFontSize.X, pcpd->lpConsole->dwFontSize.Y); RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_FONTSIZE, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); dwValue = pcpd->lpConsole->uFontFamily; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_FONTFAMILY, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); dwValue = pcpd->lpConsole->uFontWeight; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_FONTWEIGHT, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_FACENAME, 0, REG_SZ, (LPBYTE)pcpd->lpFaceName, (lstrlen(pcpd->lpFaceName) + 1) * sizeof(TCHAR) ); // // Save cursor size // dwValue = pcpd->lpConsole->uCursorSize; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_CURSORSIZE, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); // // Save history buffer size and number // dwValue = pcpd->lpConsole->uHistoryBufferSize; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_HISTORYSIZE, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); dwValue = pcpd->lpConsole->uNumberOfHistoryBuffers; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_HISTORYBUFS, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); dwValue = pcpd->lpConsole->bHistoryNoDup; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_HISTORYNODUP, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); // // Close the registry keys // if (hTitleKey != hConsoleKey) { RegCloseKey(hTitleKey); } CloseKey: RegCloseKey(hConsoleKey); } void InitFERegistryValues( CONSOLEPROP_DATA *pcpd ) /*++ Routine Description: This routine allocates a state info structure and fill it in with default values. It then tries to load the default settings for console from the registry. Arguments: none Return Value: pStateInfo - pointer to structure to receive information --*/ { /* * In this case: console reads a property of US version. * It doesn't have code page information. * Console should sets some code page as default. * However, I don't know right value. 437 is temporary value. */ pcpd->lpFEConsole->uCodePage = 437; GetFERegistryValues( pcpd ); } VOID GetFERegistryValues( CONSOLEPROP_DATA *pcpd ) /*++ 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 --*/ { HKEY hConsoleKey; HKEY hTitleKey; LPTSTR TranslatedTitle; DWORD dwValue, dwSize; DWORD dwRet = 0; // // Open the console registry key // if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER, CONSOLE_REGISTRY_STRING, 0, KEY_QUERY_VALUE, &hConsoleKey)) { return; } // // If there is no structure to fill out, just bail out // if ((!pcpd) || (!pcpd->lpFEConsole)) goto CloseKey; // // Open the console title subkey, if there is one // if (pcpd->ConsoleTitle[0] != TEXT('\0')) { TranslatedTitle = TranslateConsoleTitle(pcpd->ConsoleTitle); if (TranslatedTitle == NULL) goto CloseKey; dwValue = RegOpenKeyEx( hConsoleKey, TranslatedTitle, 0, KEY_QUERY_VALUE, &hTitleKey); LocalFree(TranslatedTitle); if (dwValue!=ERROR_SUCCESS) goto CloseKey; } else { goto CloseKey; } // // Initial code page // dwSize = sizeof(dwValue); if (SHQueryValueEx( hTitleKey, CONSOLE_REGISTRY_CODEPAGE, NULL, NULL, (LPBYTE)&dwValue, &dwSize ) == ERROR_SUCCESS) { pcpd->lpFEConsole->uCodePage = (UINT)dwValue; } // // Close the registry keys // if (hTitleKey != hConsoleKey) { RegCloseKey(hTitleKey); } CloseKey: RegCloseKey(hConsoleKey); } VOID SetFERegistryValues( CONSOLEPROP_DATA *pcpd ) /*++ 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 --*/ { HKEY hConsoleKey; HKEY hTitleKey; LPTSTR TranslatedTitle; DWORD dwValue; // // Open the console registry key // if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, CONSOLE_REGISTRY_STRING, 0, NULL, 0, KEY_SET_VALUE, NULL, &hConsoleKey, NULL)) { return; } // // If we only want to save the current page, bail out // if (pcpd == NULL) { goto CloseKey; } // // Open the console title subkey, if there is one // if (pcpd->ConsoleTitle[0] != TEXT('\0')) { TranslatedTitle = TranslateConsoleTitle(pcpd->ConsoleTitle); if (TranslatedTitle == NULL) { RegCloseKey(hConsoleKey); return; } dwValue = RegCreateKeyEx( hConsoleKey, TranslatedTitle, 0, NULL, 0, KEY_SET_VALUE, NULL, &hTitleKey, NULL); LocalFree(TranslatedTitle); if (dwValue!=ERROR_SUCCESS) { goto CloseKey; } } else { hTitleKey = hConsoleKey; } // scotthsu dwValue = pcpd->lpFEConsole->uCodePage; RegSetValueEx( hTitleKey, CONSOLE_REGISTRY_CODEPAGE, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue) ); // // Close the registry keys // if (hTitleKey != hConsoleKey) { RegCloseKey(hTitleKey); } CloseKey: RegCloseKey(hConsoleKey); }