Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

618 lines
15 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. dbcs.c
  5. Abstract:
  6. This module contains the code for console DBCS font dialog
  7. Author:
  8. kazum Feb-27-1995
  9. Revision History:
  10. --*/
  11. #include "shellprv.h"
  12. #pragma hdrstop
  13. #include "lnkcon.h"
  14. #ifdef DBCS
  15. // This definition shares in windows\inc\wincon.w file
  16. //
  17. #define MACHINE_REGISTRY_CONSOLE_TTFONT (L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Console\\TrueTypeFont")
  18. #define MACHINE_REGISTRY_CONSOLE_NLS (L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Console\\Nls")
  19. NTSTATUS
  20. MyRegOpenKey(
  21. IN HANDLE hKey,
  22. IN LPWSTR lpSubKey,
  23. OUT PHANDLE phResult
  24. )
  25. {
  26. OBJECT_ATTRIBUTES Obja;
  27. UNICODE_STRING SubKey;
  28. //
  29. // Convert the subkey to a counted Unicode string.
  30. //
  31. RtlInitUnicodeString( &SubKey, lpSubKey );
  32. //
  33. // Initialize the OBJECT_ATTRIBUTES structure and open the key.
  34. //
  35. InitializeObjectAttributes(
  36. &Obja,
  37. &SubKey,
  38. OBJ_CASE_INSENSITIVE,
  39. hKey,
  40. NULL
  41. );
  42. return NtOpenKey(
  43. phResult,
  44. KEY_READ,
  45. &Obja
  46. );
  47. }
  48. NTSTATUS
  49. MyRegEnumValue(
  50. IN HANDLE hKey,
  51. IN DWORD dwIndex,
  52. OUT DWORD dwValueLength,
  53. OUT LPWSTR lpValueName,
  54. OUT DWORD dwDataLength,
  55. OUT LPBYTE lpData
  56. )
  57. {
  58. ULONG BufferLength;
  59. ULONG ResultLength;
  60. PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
  61. NTSTATUS Status;
  62. //
  63. // Convert the subkey to a counted Unicode string.
  64. //
  65. BufferLength = sizeof(KEY_VALUE_FULL_INFORMATION) + dwValueLength + dwDataLength;
  66. KeyValueInformation = LocalAlloc(LPTR,BufferLength);
  67. if (KeyValueInformation == NULL)
  68. return STATUS_NO_MEMORY;
  69. Status = NtEnumerateValueKey(
  70. hKey,
  71. dwIndex,
  72. KeyValueFullInformation,
  73. KeyValueInformation,
  74. BufferLength,
  75. &ResultLength
  76. );
  77. if (NT_SUCCESS(Status)) {
  78. ASSERT(KeyValueInformation->NameLength <= dwValueLength);
  79. RtlMoveMemory(lpValueName,
  80. KeyValueInformation->Name,
  81. KeyValueInformation->NameLength);
  82. lpValueName[ KeyValueInformation->NameLength >> 1 ] = UNICODE_NULL;
  83. ASSERT(KeyValueInformation->DataLength <= dwDataLength);
  84. RtlMoveMemory(lpData,
  85. (PBYTE)KeyValueInformation + KeyValueInformation->DataOffset,
  86. KeyValueInformation->DataLength);
  87. if (KeyValueInformation->Type == REG_SZ ||
  88. KeyValueInformation->Type == REG_MULTI_SZ
  89. ) {
  90. if (KeyValueInformation->DataLength + sizeof(WCHAR) > dwDataLength) {
  91. KeyValueInformation->DataLength -= sizeof(WCHAR);
  92. }
  93. lpData[KeyValueInformation->DataLength++] = 0;
  94. lpData[KeyValueInformation->DataLength] = 0;
  95. }
  96. }
  97. LocalFree(KeyValueInformation);
  98. return Status;
  99. }
  100. WORD
  101. ConvertStringToDec(
  102. LPWSTR lpch,
  103. LPWSTR *endptr
  104. )
  105. {
  106. WCHAR ch;
  107. WORD val = 0;
  108. while ( (ch=*lpch) != L'\0')
  109. {
  110. if (L'0' <= ch && ch <= L'9')
  111. val = (val * 10) + (ch - L'0');
  112. else
  113. break;
  114. lpch++;
  115. }
  116. if (endptr)
  117. *endptr = lpch;
  118. return val;
  119. }
  120. WORD
  121. ConvertStringToHex(
  122. LPWSTR lpch,
  123. LPWSTR *endptr
  124. )
  125. {
  126. WCHAR ch;
  127. WORD val = 0;
  128. while ( (ch=*lpch) != L'\0')
  129. {
  130. if (L'0' <= ch && ch <= L'9')
  131. val = (val << 4) + (ch - L'0');
  132. else if (L'A' <= ch && ch <= L'F')
  133. val = (val << 4) + (ch - L'A' + 10);
  134. else if (L'a' <= ch && ch <= L'f')
  135. val = (val << 4) + (ch - L'a' + 10);
  136. else
  137. break;
  138. lpch++;
  139. }
  140. if (endptr)
  141. *endptr = lpch;
  142. return val;
  143. }
  144. NTSTATUS
  145. MakeAltRasterFont(
  146. CONSOLEPROP_DATA * pcpd,
  147. UINT CodePage,
  148. COORD *AltFontSize,
  149. BYTE *AltFontFamily,
  150. ULONG *AltFontIndex,
  151. LPTSTR AltFaceName
  152. )
  153. {
  154. DWORD i;
  155. DWORD Find;
  156. ULONG FontIndex;
  157. COORD FontSize = pcpd->FontInfo[pcpd->DefaultFontIndex].Size;
  158. COORD FontDelta;
  159. BOOL fDbcsCharSet = IS_ANY_DBCS_CHARSET( CodePageToCharSet( CodePage ) );
  160. FontIndex = 0;
  161. Find = (DWORD)-1;
  162. for (i=0; i < pcpd->NumberOfFonts; i++)
  163. {
  164. if (!TM_IS_TT_FONT(pcpd->FontInfo[i].Family) &&
  165. IS_ANY_DBCS_CHARSET(pcpd->FontInfo[i].tmCharSet) == fDbcsCharSet
  166. )
  167. {
  168. FontDelta.X = (SHORT)abs(FontSize.X - pcpd->FontInfo[i].Size.X);
  169. FontDelta.Y = (SHORT)abs(FontSize.Y - pcpd->FontInfo[i].Size.Y);
  170. if (Find > (DWORD)(FontDelta.X + FontDelta.Y))
  171. {
  172. Find = (DWORD)(FontDelta.X + FontDelta.Y);
  173. FontIndex = i;
  174. }
  175. }
  176. }
  177. *AltFontIndex = FontIndex;
  178. lstrcpy(AltFaceName, pcpd->FontInfo[*AltFontIndex].FaceName);
  179. *AltFontSize = pcpd->FontInfo[*AltFontIndex].Size;
  180. *AltFontFamily = pcpd->FontInfo[*AltFontIndex].Family;
  181. return STATUS_SUCCESS;
  182. }
  183. NTSTATUS
  184. InitializeDbcsMisc(
  185. CONSOLEPROP_DATA * pcpd
  186. )
  187. {
  188. HANDLE hkRegistry = NULL;
  189. NTSTATUS Status;
  190. WCHAR awchValue[ 512 ];
  191. WCHAR awchData[ 512 ];
  192. DWORD dwIndex;
  193. LPWSTR pwsz;
  194. pcpd->gTTFontList.Next = NULL;
  195. Status = MyRegOpenKey(NULL,
  196. MACHINE_REGISTRY_CONSOLE_TTFONT,
  197. &hkRegistry);
  198. if (NT_SUCCESS( Status )) {
  199. TTFONTLIST *pTTFontList;
  200. for( dwIndex = 0; ; dwIndex++) {
  201. Status = MyRegEnumValue(hkRegistry,
  202. dwIndex,
  203. sizeof(awchValue), (LPWSTR)&awchValue,
  204. sizeof(awchData), (PBYTE)&awchData);
  205. if (!NT_SUCCESS( Status )) {
  206. break;
  207. }
  208. pTTFontList = LocalAlloc(LPTR, sizeof(TTFONTLIST));
  209. if (pTTFontList == NULL) {
  210. break;
  211. }
  212. pTTFontList->List.Next = NULL;
  213. pTTFontList->CodePage = ConvertStringToDec(awchValue, NULL);
  214. pwsz = awchData;
  215. if (*pwsz == BOLD_MARK) {
  216. pTTFontList->fDisableBold = TRUE;
  217. pwsz++;
  218. }
  219. else
  220. pTTFontList->fDisableBold = FALSE;
  221. #ifdef UNICODE
  222. lstrcpyW(pTTFontList->FaceName1, pwsz);
  223. pwsz += lstrlenW(pwsz) + 1;
  224. if (*pwsz == BOLD_MARK)
  225. {
  226. pTTFontList->fDisableBold = TRUE;
  227. pwsz++;
  228. }
  229. lstrcpyW(pTTFontList->FaceName2, pwsz);
  230. #else
  231. // if we're the ANSI shell, we need to convert FACENAME
  232. // over to ASCII before saving...
  233. {
  234. CHAR szFaceName[LF_FACESIZE];
  235. SHUnicodeToAnsi(pwsz, szFaceName, ARRAYSIZE(szFaceName));
  236. lstrcpyA(pTTFontList->FaceName1, szFaceName);
  237. pwsz += lstrlenW(pwsz) + 1;
  238. if (*pwsz == BOLD_MARK)
  239. {
  240. pTTFontList->fDisableBold = TRUE;
  241. pwsz++;
  242. }
  243. SHUnicodeToAnsi(pwsz, szFaceName, ARRAYSIZE(szFaceName));
  244. lstrcpyA(pTTFontList->FaceName2, szFaceName);
  245. }
  246. #endif
  247. PushEntryList(&pcpd->gTTFontList, &(pTTFontList->List));
  248. }
  249. NtClose(hkRegistry);
  250. }
  251. pcpd->fChangeCodePage = FALSE;
  252. pcpd->uOEMCP = GetOEMCP();
  253. return STATUS_SUCCESS;
  254. }
  255. BYTE
  256. CodePageToCharSet(
  257. UINT CodePage
  258. )
  259. {
  260. CHARSETINFO csi;
  261. if (!TranslateCharsetInfo((DWORD *)UIntToPtr( CodePage ), &csi, TCI_SRCCODEPAGE)) // Sundown: valid zero-extension of CodePage for TCI_SRCCOPAGE.
  262. csi.ciCharset = OEM_CHARSET;
  263. return (BYTE)csi.ciCharset;
  264. }
  265. TTFONTLIST *SearchTTFont(CONSOLEPROP_DATA * pcpd, LPTSTR ptszFace, BOOL fCodePage, UINT CodePage)
  266. {
  267. PSINGLE_LIST_ENTRY pTemp = pcpd->gTTFontList.Next;
  268. if (ptszFace) {
  269. while (pTemp != NULL) {
  270. TTFONTLIST *pTTFontList = (TTFONTLIST *)pTemp;
  271. if (wcscmp(ptszFace, pTTFontList->FaceName1) == 0 ||
  272. wcscmp(ptszFace, pTTFontList->FaceName2) == 0 ) {
  273. if (fCodePage)
  274. if (pTTFontList->CodePage == CodePage )
  275. return pTTFontList;
  276. else
  277. return NULL;
  278. else
  279. return pTTFontList;
  280. }
  281. pTemp = pTemp->Next;
  282. }
  283. }
  284. return NULL;
  285. }
  286. BOOL
  287. IsAvailableTTFont(
  288. CONSOLEPROP_DATA * pcpd,
  289. LPTSTR ptszFace
  290. )
  291. {
  292. if (SearchTTFont(pcpd, ptszFace, FALSE, 0))
  293. return TRUE;
  294. else
  295. return FALSE;
  296. }
  297. BOOL
  298. IsAvailableTTFontCP(
  299. CONSOLEPROP_DATA * pcpd,
  300. LPTSTR ptszFace,
  301. UINT CodePage
  302. )
  303. {
  304. if (SearchTTFont(pcpd, ptszFace, TRUE, CodePage))
  305. return TRUE;
  306. else
  307. return FALSE;
  308. }
  309. BOOL
  310. IsDisableBoldTTFont(
  311. CONSOLEPROP_DATA * pcpd,
  312. LPTSTR ptszFace
  313. )
  314. {
  315. TTFONTLIST *pTTFontList;
  316. pTTFontList = SearchTTFont(pcpd, ptszFace, FALSE, 0);
  317. if (pTTFontList != NULL)
  318. return pTTFontList->fDisableBold;
  319. else
  320. return FALSE;
  321. }
  322. LPTSTR
  323. GetAltFaceName(
  324. CONSOLEPROP_DATA * pcpd,
  325. LPTSTR ptszFace
  326. )
  327. {
  328. TTFONTLIST *pTTFontList;
  329. pTTFontList = SearchTTFont(pcpd, ptszFace, FALSE, 0);
  330. if (pTTFontList) {
  331. if (wcscmp(ptszFace, pTTFontList->FaceName1) == 0) {
  332. return pTTFontList->FaceName2;
  333. }
  334. if (wcscmp(ptszFace, pTTFontList->FaceName2) == 0) {
  335. return pTTFontList->FaceName1;
  336. }
  337. return NULL;
  338. }
  339. else
  340. return NULL;
  341. }
  342. NTSTATUS DestroyDbcsMisc(CONSOLEPROP_DATA * pcpd)
  343. {
  344. while (pcpd->gTTFontList.Next != NULL)
  345. {
  346. TTFONTLIST *pTTFontList = (TTFONTLIST *)PopEntryList(&pcpd->gTTFontList);
  347. if (pTTFontList != NULL)
  348. LocalFree(pTTFontList);
  349. }
  350. return STATUS_SUCCESS;
  351. }
  352. typedef struct _LC_List {
  353. struct _LC_List* Next;
  354. BOOL FindFlag;
  355. WCHAR LC_String[9];
  356. } LC_List, *PLC_List;
  357. static PLC_List LocaleList;
  358. BOOL CALLBACK
  359. EnumProc(
  360. LPWSTR LC_String
  361. )
  362. {
  363. PLC_List TmpList;
  364. if (lstrlenW(LC_String) <= (sizeof(LocaleList->LC_String)/sizeof(WCHAR))-1)
  365. {
  366. TmpList = (PLC_List)&LocaleList;
  367. while(TmpList->Next != NULL)
  368. TmpList = TmpList->Next;
  369. TmpList->Next = LocalAlloc(LPTR, sizeof(LC_List));
  370. if (TmpList->Next != NULL)
  371. {
  372. TmpList = TmpList->Next;
  373. lstrcpyW(TmpList->LC_String, LC_String);
  374. }
  375. }
  376. return TRUE;
  377. }
  378. int
  379. LanguageListCreate(
  380. HWND hDlg,
  381. UINT CodePage
  382. )
  383. /*++
  384. Initializes the Language list by enumerating all Locale Information.
  385. Returns
  386. --*/
  387. {
  388. HWND hWndLanguageCombo;
  389. HANDLE hkRegistry = NULL;
  390. NTSTATUS Status;
  391. WCHAR awchValue[ 512 ];
  392. WCHAR awchData[ 512 ];
  393. DWORD dwIndex;
  394. PLC_List TmpList;
  395. WORD LangID;
  396. LCID Locale;
  397. int cchData;
  398. LONG lListIndex;
  399. UINT cp;
  400. ENTERCRITICAL;
  401. /*
  402. * Enumrate system locale information
  403. */
  404. EnumSystemLocalesW( EnumProc, CP_INSTALLED );
  405. /*
  406. * Enumrate registory key
  407. */
  408. Status = MyRegOpenKey(NULL,
  409. MACHINE_REGISTRY_CONSOLE_NLS,
  410. &hkRegistry);
  411. if (NT_SUCCESS( Status )) {
  412. for( dwIndex = 0; ; dwIndex++)
  413. {
  414. Status = MyRegEnumValue(hkRegistry,
  415. dwIndex,
  416. sizeof(awchValue), (LPWSTR)&awchValue,
  417. sizeof(awchData), (PBYTE)&awchData);
  418. if (!NT_SUCCESS( Status ))
  419. {
  420. break;
  421. }
  422. TmpList = (PLC_List)&LocaleList;
  423. while(TmpList->Next != NULL)
  424. {
  425. TmpList = TmpList->Next;
  426. if (lstrcmpW(awchValue, TmpList->LC_String) == 0)
  427. {
  428. TmpList->FindFlag = TRUE;
  429. break;
  430. }
  431. }
  432. }
  433. NtClose(hkRegistry);
  434. }
  435. /*
  436. * Create ComboBox items
  437. */
  438. hWndLanguageCombo = GetDlgItem(hDlg, IDC_CNSL_LANGUAGELIST);
  439. SendMessage(hWndLanguageCombo, CB_RESETCONTENT, 0, 0L);
  440. TmpList = (PLC_List)&LocaleList;
  441. while(TmpList->Next != NULL)
  442. {
  443. TmpList = TmpList->Next;
  444. if (TmpList->FindFlag)
  445. {
  446. LangID = ConvertStringToHex(TmpList->LC_String, NULL);
  447. Locale = MAKELCID( LangID, SORT_DEFAULT );
  448. awchValue[0] = L'\0';
  449. cp = 0;
  450. {
  451. #define KERNEL32 _T("KERNEL32.DLL")
  452. #ifdef UNICODE
  453. #define GETCPINFOEX "GetCPInfoExW"
  454. #else
  455. #define GETCPINFOEX "GetCPInfoExA"
  456. #endif
  457. typedef BOOL (CALLBACK *LPFNGETCPINFOEX)(UINT, DWORD, LPCPINFOEX);
  458. LPFNGETCPINFOEX lpfnGetCPInfoEx;
  459. BOOL fRet = FALSE;
  460. CPINFOEX cpinfo;
  461. HMODULE hMod;
  462. cchData = GetLocaleInfoW(Locale, LOCALE_IDEFAULTCODEPAGE,
  463. awchData, sizeof(awchData)/sizeof(TCHAR));
  464. if (cchData)
  465. {
  466. cp = ConvertStringToDec(awchData, NULL);
  467. hMod = GetModuleHandle(KERNEL32);
  468. if (hMod) {
  469. lpfnGetCPInfoEx = (LPFNGETCPINFOEX)GetProcAddress(hMod,GETCPINFOEX);
  470. if (lpfnGetCPInfoEx)
  471. fRet = (*lpfnGetCPInfoEx)(cp, 0, &cpinfo);
  472. }
  473. if (fRet) {
  474. lListIndex = (LONG) SendMessageW(hWndLanguageCombo, CB_ADDSTRING, 0, (LPARAM)cpinfo.CodePageName);
  475. SendMessage(hWndLanguageCombo, CB_SETITEMDATA, (DWORD)lListIndex, cp);
  476. if (CodePage == cp) {
  477. SendMessage(hWndLanguageCombo, CB_SETCURSEL, lListIndex, 0L);
  478. }
  479. }
  480. }
  481. }
  482. if (CodePage == cp) {
  483. SendMessage(hWndLanguageCombo, CB_SETCURSEL, lListIndex, 0L);
  484. }
  485. }
  486. }
  487. {
  488. PLC_List Tmp;
  489. TmpList = (PLC_List)&LocaleList;
  490. while(TmpList->Next != NULL)
  491. {
  492. Tmp = TmpList;
  493. TmpList = TmpList->Next;
  494. if (Tmp != (PLC_List)&LocaleList)
  495. LocalFree(Tmp);
  496. }
  497. LocaleList = NULL;
  498. }
  499. LEAVECRITICAL;
  500. /*
  501. * Get the LocaleIndex from the currently selected item.
  502. * (i will be LB_ERR if no currently selected item).
  503. */
  504. lListIndex = (LONG) SendMessage(hWndLanguageCombo, CB_GETCURSEL, 0, 0L);
  505. return (int) SendMessage(hWndLanguageCombo, CB_GETITEMDATA, lListIndex, 0L);
  506. }
  507. #endif // DBCS