/*++ Copyright (c) 1992 Microsoft Corporation Module Name: dbcs.c Abstract: This module contains the code for console DBCS font dialog Author: kazum Feb-27-1995 Revision History: --*/ #include "shellprv.h" #pragma hdrstop #include "lnkcon.h" #ifdef DBCS // This definition shares in windows\inc\wincon.w file // #define MACHINE_REGISTRY_CONSOLE_TTFONT (L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Console\\TrueTypeFont") #define MACHINE_REGISTRY_CONSOLE_NLS (L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Console\\Nls") 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 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; } WORD ConvertStringToDec( LPWSTR lpch, LPWSTR *endptr ) { WCHAR ch; WORD val = 0; while ( (ch=*lpch) != L'\0') { if (L'0' <= ch && ch <= L'9') val = (val * 10) + (ch - L'0'); else break; lpch++; } if (endptr) *endptr = lpch; return val; } WORD ConvertStringToHex( LPWSTR lpch, LPWSTR *endptr ) { WCHAR ch; WORD val = 0; while ( (ch=*lpch) != L'\0') { if (L'0' <= ch && ch <= L'9') val = (val << 4) + (ch - L'0'); else if (L'A' <= ch && ch <= L'F') val = (val << 4) + (ch - L'A' + 10); else if (L'a' <= ch && ch <= L'f') val = (val << 4) + (ch - L'a' + 10); else break; lpch++; } if (endptr) *endptr = lpch; return val; } NTSTATUS MakeAltRasterFont( CONSOLEPROP_DATA * pcpd, UINT CodePage, COORD *AltFontSize, BYTE *AltFontFamily, ULONG *AltFontIndex, LPTSTR AltFaceName ) { DWORD i; DWORD Find; ULONG FontIndex; COORD FontSize = pcpd->FontInfo[pcpd->DefaultFontIndex].Size; COORD FontDelta; BOOL fDbcsCharSet = IS_ANY_DBCS_CHARSET( CodePageToCharSet( CodePage ) ); FontIndex = 0; Find = (DWORD)-1; for (i=0; i < pcpd->NumberOfFonts; i++) { if (!TM_IS_TT_FONT(pcpd->FontInfo[i].Family) && IS_ANY_DBCS_CHARSET(pcpd->FontInfo[i].tmCharSet) == fDbcsCharSet ) { FontDelta.X = (SHORT)abs(FontSize.X - pcpd->FontInfo[i].Size.X); FontDelta.Y = (SHORT)abs(FontSize.Y - pcpd->FontInfo[i].Size.Y); if (Find > (DWORD)(FontDelta.X + FontDelta.Y)) { Find = (DWORD)(FontDelta.X + FontDelta.Y); FontIndex = i; } } } *AltFontIndex = FontIndex; lstrcpy(AltFaceName, pcpd->FontInfo[*AltFontIndex].FaceName); *AltFontSize = pcpd->FontInfo[*AltFontIndex].Size; *AltFontFamily = pcpd->FontInfo[*AltFontIndex].Family; return STATUS_SUCCESS; } NTSTATUS InitializeDbcsMisc( CONSOLEPROP_DATA * pcpd ) { HANDLE hkRegistry = NULL; NTSTATUS Status; WCHAR awchValue[ 512 ]; WCHAR awchData[ 512 ]; DWORD dwIndex; LPWSTR pwsz; pcpd->gTTFontList.Next = NULL; Status = MyRegOpenKey(NULL, MACHINE_REGISTRY_CONSOLE_TTFONT, &hkRegistry); if (NT_SUCCESS( Status )) { TTFONTLIST *pTTFontList; for( dwIndex = 0; ; dwIndex++) { Status = MyRegEnumValue(hkRegistry, dwIndex, sizeof(awchValue), (LPWSTR)&awchValue, sizeof(awchData), (PBYTE)&awchData); if (!NT_SUCCESS( Status )) { break; } pTTFontList = LocalAlloc(LPTR, sizeof(TTFONTLIST)); if (pTTFontList == NULL) { break; } pTTFontList->List.Next = NULL; pTTFontList->CodePage = ConvertStringToDec(awchValue, NULL); pwsz = awchData; if (*pwsz == BOLD_MARK) { pTTFontList->fDisableBold = TRUE; pwsz++; } else pTTFontList->fDisableBold = FALSE; #ifdef UNICODE lstrcpyW(pTTFontList->FaceName1, pwsz); pwsz += lstrlenW(pwsz) + 1; if (*pwsz == BOLD_MARK) { pTTFontList->fDisableBold = TRUE; pwsz++; } lstrcpyW(pTTFontList->FaceName2, pwsz); #else // if we're the ANSI shell, we need to convert FACENAME // over to ASCII before saving... { CHAR szFaceName[LF_FACESIZE]; SHUnicodeToAnsi(pwsz, szFaceName, ARRAYSIZE(szFaceName)); lstrcpyA(pTTFontList->FaceName1, szFaceName); pwsz += lstrlenW(pwsz) + 1; if (*pwsz == BOLD_MARK) { pTTFontList->fDisableBold = TRUE; pwsz++; } SHUnicodeToAnsi(pwsz, szFaceName, ARRAYSIZE(szFaceName)); lstrcpyA(pTTFontList->FaceName2, szFaceName); } #endif PushEntryList(&pcpd->gTTFontList, &(pTTFontList->List)); } NtClose(hkRegistry); } pcpd->fChangeCodePage = FALSE; pcpd->uOEMCP = GetOEMCP(); return STATUS_SUCCESS; } BYTE CodePageToCharSet( UINT CodePage ) { CHARSETINFO csi; if (!TranslateCharsetInfo((DWORD *)UIntToPtr( CodePage ), &csi, TCI_SRCCODEPAGE)) // Sundown: valid zero-extension of CodePage for TCI_SRCCOPAGE. csi.ciCharset = OEM_CHARSET; return (BYTE)csi.ciCharset; } TTFONTLIST *SearchTTFont(CONSOLEPROP_DATA * pcpd, LPTSTR ptszFace, BOOL fCodePage, UINT CodePage) { PSINGLE_LIST_ENTRY pTemp = pcpd->gTTFontList.Next; if (ptszFace) { while (pTemp != NULL) { TTFONTLIST *pTTFontList = (TTFONTLIST *)pTemp; if (wcscmp(ptszFace, pTTFontList->FaceName1) == 0 || wcscmp(ptszFace, pTTFontList->FaceName2) == 0 ) { if (fCodePage) if (pTTFontList->CodePage == CodePage ) return pTTFontList; else return NULL; else return pTTFontList; } pTemp = pTemp->Next; } } return NULL; } BOOL IsAvailableTTFont( CONSOLEPROP_DATA * pcpd, LPTSTR ptszFace ) { if (SearchTTFont(pcpd, ptszFace, FALSE, 0)) return TRUE; else return FALSE; } BOOL IsAvailableTTFontCP( CONSOLEPROP_DATA * pcpd, LPTSTR ptszFace, UINT CodePage ) { if (SearchTTFont(pcpd, ptszFace, TRUE, CodePage)) return TRUE; else return FALSE; } BOOL IsDisableBoldTTFont( CONSOLEPROP_DATA * pcpd, LPTSTR ptszFace ) { TTFONTLIST *pTTFontList; pTTFontList = SearchTTFont(pcpd, ptszFace, FALSE, 0); if (pTTFontList != NULL) return pTTFontList->fDisableBold; else return FALSE; } LPTSTR GetAltFaceName( CONSOLEPROP_DATA * pcpd, LPTSTR ptszFace ) { TTFONTLIST *pTTFontList; pTTFontList = SearchTTFont(pcpd, ptszFace, FALSE, 0); if (pTTFontList) { if (wcscmp(ptszFace, pTTFontList->FaceName1) == 0) { return pTTFontList->FaceName2; } if (wcscmp(ptszFace, pTTFontList->FaceName2) == 0) { return pTTFontList->FaceName1; } return NULL; } else return NULL; } NTSTATUS DestroyDbcsMisc(CONSOLEPROP_DATA * pcpd) { while (pcpd->gTTFontList.Next != NULL) { TTFONTLIST *pTTFontList = (TTFONTLIST *)PopEntryList(&pcpd->gTTFontList); if (pTTFontList != NULL) LocalFree(pTTFontList); } return STATUS_SUCCESS; } typedef struct _LC_List { struct _LC_List* Next; BOOL FindFlag; WCHAR LC_String[9]; } LC_List, *PLC_List; static PLC_List LocaleList; BOOL CALLBACK EnumProc( LPWSTR LC_String ) { PLC_List TmpList; if (lstrlenW(LC_String) <= (sizeof(LocaleList->LC_String)/sizeof(WCHAR))-1) { TmpList = (PLC_List)&LocaleList; while(TmpList->Next != NULL) TmpList = TmpList->Next; TmpList->Next = LocalAlloc(LPTR, sizeof(LC_List)); if (TmpList->Next != NULL) { TmpList = TmpList->Next; lstrcpyW(TmpList->LC_String, LC_String); } } return TRUE; } int LanguageListCreate( HWND hDlg, UINT CodePage ) /*++ Initializes the Language list by enumerating all Locale Information. Returns --*/ { HWND hWndLanguageCombo; HANDLE hkRegistry = NULL; NTSTATUS Status; WCHAR awchValue[ 512 ]; WCHAR awchData[ 512 ]; DWORD dwIndex; PLC_List TmpList; WORD LangID; LCID Locale; int cchData; LONG lListIndex; UINT cp; ENTERCRITICAL; /* * Enumrate system locale information */ EnumSystemLocalesW( EnumProc, CP_INSTALLED ); /* * Enumrate registory key */ Status = MyRegOpenKey(NULL, MACHINE_REGISTRY_CONSOLE_NLS, &hkRegistry); if (NT_SUCCESS( Status )) { for( dwIndex = 0; ; dwIndex++) { Status = MyRegEnumValue(hkRegistry, dwIndex, sizeof(awchValue), (LPWSTR)&awchValue, sizeof(awchData), (PBYTE)&awchData); if (!NT_SUCCESS( Status )) { break; } TmpList = (PLC_List)&LocaleList; while(TmpList->Next != NULL) { TmpList = TmpList->Next; if (lstrcmpW(awchValue, TmpList->LC_String) == 0) { TmpList->FindFlag = TRUE; break; } } } NtClose(hkRegistry); } /* * Create ComboBox items */ hWndLanguageCombo = GetDlgItem(hDlg, IDC_CNSL_LANGUAGELIST); SendMessage(hWndLanguageCombo, CB_RESETCONTENT, 0, 0L); TmpList = (PLC_List)&LocaleList; while(TmpList->Next != NULL) { TmpList = TmpList->Next; if (TmpList->FindFlag) { LangID = ConvertStringToHex(TmpList->LC_String, NULL); Locale = MAKELCID( LangID, SORT_DEFAULT ); awchValue[0] = L'\0'; cp = 0; { #define KERNEL32 _T("KERNEL32.DLL") #ifdef UNICODE #define GETCPINFOEX "GetCPInfoExW" #else #define GETCPINFOEX "GetCPInfoExA" #endif typedef BOOL (CALLBACK *LPFNGETCPINFOEX)(UINT, DWORD, LPCPINFOEX); LPFNGETCPINFOEX lpfnGetCPInfoEx; BOOL fRet = FALSE; CPINFOEX cpinfo; HMODULE hMod; cchData = GetLocaleInfoW(Locale, LOCALE_IDEFAULTCODEPAGE, awchData, sizeof(awchData)/sizeof(TCHAR)); if (cchData) { cp = ConvertStringToDec(awchData, NULL); hMod = GetModuleHandle(KERNEL32); if (hMod) { lpfnGetCPInfoEx = (LPFNGETCPINFOEX)GetProcAddress(hMod,GETCPINFOEX); if (lpfnGetCPInfoEx) fRet = (*lpfnGetCPInfoEx)(cp, 0, &cpinfo); } if (fRet) { lListIndex = (LONG) SendMessageW(hWndLanguageCombo, CB_ADDSTRING, 0, (LPARAM)cpinfo.CodePageName); SendMessage(hWndLanguageCombo, CB_SETITEMDATA, (DWORD)lListIndex, cp); if (CodePage == cp) { SendMessage(hWndLanguageCombo, CB_SETCURSEL, lListIndex, 0L); } } } } if (CodePage == cp) { SendMessage(hWndLanguageCombo, CB_SETCURSEL, lListIndex, 0L); } } } { PLC_List Tmp; TmpList = (PLC_List)&LocaleList; while(TmpList->Next != NULL) { Tmp = TmpList; TmpList = TmpList->Next; if (Tmp != (PLC_List)&LocaleList) LocalFree(Tmp); } LocaleList = NULL; } LEAVECRITICAL; /* * Get the LocaleIndex from the currently selected item. * (i will be LB_ERR if no currently selected item). */ lListIndex = (LONG) SendMessage(hWndLanguageCombo, CB_GETCURSEL, 0, 0L); return (int) SendMessage(hWndLanguageCombo, CB_GETITEMDATA, lListIndex, 0L); } #endif // DBCS