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.

660 lines
19 KiB

  1. /* cmdkeyb.c - Keyboard layout support routines
  2. *
  3. *
  4. * Modification History:
  5. *
  6. * YST 14-Jan_1993 Created
  7. *
  8. * 08-Sept-1998, williamh, add third-party KDF support.
  9. */
  10. #include "cmd.h"
  11. #include <winconp.h>
  12. #include <cmdsvc.h>
  13. #include <softpc.h>
  14. #include <mvdm.h>
  15. #include <ctype.h>
  16. #include <string.H>
  17. #include "cmdkeyb.h"
  18. #include <winnls.h>
  19. CHAR szPrev[5] = "US";
  20. INT iPrevCP = 437;
  21. CHAR szPrevKbdID[8] = "";
  22. extern BOOL bPifFastPaste;
  23. /************************************************************************\
  24. *
  25. * FUNCTION: VOID cmdGetKbdLayout( VOID )
  26. *
  27. * Input Client (DX) = 0 - Keyb.com not installed
  28. * 1 - Keyb.com installed
  29. * Client (DS:SI) = pointer where exe name has to be placed
  30. * Client (DS:CX) = pointer where command options are placed
  31. *
  32. * Output
  33. * Success (DX = 1 )
  34. * Client (DS:SI) = Keyb.com execuatable string
  35. * Client (DS:CX) = command options
  36. *
  37. * Failure (DX = 0)
  38. *
  39. * COMMENTS: This function check KEYBOARD ID for Win session
  40. * and if ID != US then return lines with
  41. * filename and options to COMMAND.COM
  42. *
  43. * If bPifFastPaste is FALSE, then we always run kb16
  44. * for all keyboard ID including US, to give us a more
  45. * bios compatible Int 9 handler. 10-Jun-1993 Jonle
  46. *
  47. *
  48. * HISTORY: 01/05/93 YSt Created.
  49. *
  50. \************************************************************************/
  51. VOID cmdGetKbdLayout( VOID )
  52. {
  53. INT iSize,iSaveSize;
  54. CHAR szKeybCode[12];
  55. CHAR szDir[MAX_PATH+15];
  56. CHAR szBuf[28];
  57. CHAR szNewKbdID[8];
  58. CHAR szAutoLine[MAX_PATH+40];
  59. CHAR szKDF[MAX_PATH];
  60. PCHAR pVDMKeyb;
  61. INT iKeyb;
  62. HKEY hKey;
  63. HKEY hKeyLayout;
  64. DWORD dwType;
  65. DWORD retCode;
  66. INT iNewCP;
  67. DWORD cbData;
  68. WORD KeybID;
  69. OFSTRUCT ofstr;
  70. LANGID LcId = GetSystemDefaultLangID();
  71. int keytype;
  72. #if defined(NEC_98)
  73. setDX(0);
  74. return;
  75. #endif // NEC_98
  76. // Get information about 16 bit KEYB.COM from VDM
  77. iKeyb = getDX();
  78. // The whole logic here is to decide:
  79. // (1). if we have to run kb16.com at all.
  80. // (2). if we have to run kb16.com, what parameters we should pass along,
  81. // such as keyboard id, language id, code page id and kdf file name.
  82. // We do not load kb16.com at all if one of the following
  83. // conditions is met:
  84. // (1). We can not find the console keyboard layout id.
  85. // (2). The console keyvoard layout id is US and kb16.com is not loaded
  86. // and fast paste is disabled.
  87. // (3). We can not get the dos keyboard id/dos key code.
  88. // (4). The new (language id, keyboard id, code page id) is the same
  89. // as the one we loaded previously.
  90. // (5). we can not find kb16.com.
  91. // (6). we can not find the kdf file that supports the
  92. // (language id, keyboard id, code page id) combination.
  93. //
  94. // If everything goes as planned, we end up with a command
  95. // contains kb16.com fully qualified name and a command line contains
  96. // appropriate parameters to kb16.com
  97. //
  98. if (LcId == MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT)) {
  99. // JAPAN build. Language id is always "JP" and code page is either 932
  100. // or 437 depends on keyboard type.
  101. iNewCP = 437;
  102. if (7 == GetKeyboardType(0))
  103. {
  104. keytype = GetKeyboardType(1);
  105. if (keytype == 1 || keytype == 2 || keytype == 3 || (keytype & 0xff00) == 0x1200)
  106. iNewCP = 932;
  107. }
  108. szBuf[0] = 'J';
  109. szBuf[1] = 'P';
  110. szBuf[2] = '\0';
  111. // no keyboard id available.
  112. szNewKbdID[0] = '\0';
  113. }
  114. else {
  115. //
  116. // check point #1: see if we can get the console keyboard layout id
  117. //
  118. if (!GetConsoleKeyboardLayoutName(szKeybCode))
  119. goto NoInstallkb16;
  120. //
  121. // check point #2: see if the layout is US and kb16.com is loaded and
  122. // fast paste is disabled.
  123. // If kb16.com is loaded, we need to run it again
  124. // so that it will load the correct layout.
  125. // If fast paste is disable, we load kb16.com which
  126. // definitely will slow down keys delivery.
  127. //
  128. if( bPifFastPaste && !strcmp(szKeybCode, US_CODE) && !iKeyb)
  129. goto NoInstallkb16;
  130. //
  131. // check point #3: see if we can get the language id and keyboard id(if any)
  132. //
  133. // OPEN THE KEY.
  134. sprintf(szAutoLine, "%s%s", KBDLAYOUT_PATH, DOSCODES_PATH);
  135. if (ERROR_SUCCESS != RegOpenKeyEx (HKEY_LOCAL_MACHINE, // Key handle at root level.
  136. szAutoLine, // Path name of child key.
  137. 0, // Reserved.
  138. KEY_EXECUTE, // Requesting read access.
  139. &hKey)) // Address of key to be returned.
  140. goto NoInstallkb16;
  141. cbData = sizeof(szBuf);
  142. // Query for line from REGISTER file
  143. retCode = RegQueryValueEx(hKey, szKeybCode, NULL, &dwType, szBuf, &cbData);
  144. RegCloseKey(hKey);
  145. if (ERROR_SUCCESS != retCode || REG_SZ != dwType || !cbData)
  146. goto NoInstallkb16;
  147. //
  148. // szBuf now contains language id('SP' for spanish, for example).
  149. //
  150. // look for keyboard id number. For Daytona, Turkish and Italian both
  151. // have one key code and two layouts.
  152. szNewKbdID[0] = '\0';
  153. cbData = sizeof(szNewKbdID);
  154. sprintf(szAutoLine, "%s%s", KBDLAYOUT_PATH, DOSIDS_PATH);
  155. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  156. szAutoLine,
  157. 0,
  158. KEY_EXECUTE,
  159. &hKey
  160. ) == ERROR_SUCCESS)
  161. {
  162. retCode = RegQueryValueEx(hKey, szKeybCode, NULL, &dwType, szNewKbdID, &cbData);
  163. if (ERROR_SUCCESS != retCode || REG_SZ != dwType || !cbData)
  164. szNewKbdID[0] = '\0';
  165. RegCloseKey(hKey);
  166. }
  167. iNewCP = GetConsoleCP();
  168. }
  169. //
  170. // check point #4: see if there are any changes in ids
  171. //
  172. // see if there are changes in language id, keyboard id and code page id.
  173. if(bPifFastPaste && iNewCP == iPrevCP &&
  174. !_stricmp(szBuf, szPrev) &&
  175. !_stricmp(szNewKbdID, szPrevKbdID))
  176. {
  177. goto NoInstallkb16;
  178. }
  179. //
  180. // Check point #5: see if kb16.com can be found.
  181. //
  182. // kb16.com should be found in GetSystemDirectory()\system32 subdirectory.
  183. //
  184. iSaveSize = iSize = GetSystemDirectory(szDir, MAX_PATH);
  185. // can't get the system directory!
  186. if (!iSize || iSize > MAX_PATH)
  187. {
  188. goto NoInstallkb16;
  189. }
  190. // convert the system directory to short name
  191. cbData = GetShortPathName(szDir, szDir, MAX_PATH);
  192. if (!cbData || cbData >= MAX_PATH)
  193. goto NoInstallkb16;
  194. sprintf(szAutoLine, "%s%s",
  195. szDir, // System directory
  196. KEYB_COM // keyb.com
  197. );
  198. // if the fully qualified path name to kb16.com is too long
  199. // we must fail because Dos can not swallow a long path name.
  200. if (strlen(szAutoLine) > 128)
  201. goto NoInstallkb16;
  202. dwType = GetFileAttributes(szAutoLine);
  203. if (dwType == 0xFFFFFFFF || (dwType & FILE_ATTRIBUTE_DIRECTORY) != 0)
  204. {
  205. goto NoInstallkb16;
  206. }
  207. //
  208. // Check point #6: see if we can find kdf file that support the
  209. // (language id, keyboard id, code page id) combination
  210. //
  211. //
  212. // first, convert keyboard id from string to binary if we have one.
  213. //
  214. KeybID = (szNewKbdID[0]) ? (WORD)strtoul(szNewKbdID, NULL, 10) : 0;
  215. cbData = sizeof(szKDF) / sizeof(CHAR);
  216. // locate the kdf file.
  217. if (!LocateKDF(szBuf, KeybID, (WORD)iNewCP, szKDF, &cbData))
  218. {
  219. goto NoInstallkb16;
  220. }
  221. // convert the kdf name to short name
  222. cbData = GetShortPathName(szKDF, szKDF, sizeof(szKDF)/ sizeof(CHAR));
  223. if (!cbData || cbData >= sizeof(szKDF) / sizeof(CHAR))
  224. {
  225. goto NoInstallkb16;
  226. }
  227. //
  228. // everything is checked and in place. Now compose the command
  229. // line to execute kb16.com
  230. // first, the command
  231. pVDMKeyb = (PCHAR) GetVDMAddr((USHORT) getDS(), (USHORT) getSI());
  232. strcpy(pVDMKeyb, szAutoLine);
  233. // then the parameters
  234. // The format is: XX,YYY, <kdf file>, where XXX is the language id
  235. // and YYY is the code page id.
  236. pVDMKeyb = (PCHAR) GetVDMAddr((USHORT) getDS(), (USHORT) getCX());
  237. // The first byte is resevered for the length of the string.
  238. sprintf(szAutoLine, " %s,%d,%s",
  239. szBuf, // keyboard code
  240. iNewCP, // new code page
  241. szKDF // keyboard.sys
  242. );
  243. // if we have a keyboard id, pass it also
  244. if (szNewKbdID[0])
  245. {
  246. strcat(szAutoLine, " /id:");
  247. strcat(szAutoLine, szNewKbdID);
  248. }
  249. // standard parameter line has the format:
  250. // <length><line text><\0xd>, <length> is the length of <line text>
  251. //
  252. iSize = strlen(szAutoLine);
  253. szAutoLine[iSize] = 0xd;
  254. // Move the line to 16bits, including the terminated cr char
  255. RtlMoveMemory(pVDMKeyb + 1, szAutoLine, iSize + 1);
  256. *pVDMKeyb = (CHAR)iSize;
  257. // Save new layout ID and code page for next call
  258. strcpy(szPrev, szBuf);
  259. strcpy(szPrevKbdID, szNewKbdID);
  260. iPrevCP = iNewCP;
  261. setDX(1);
  262. return;
  263. NoInstallkb16:
  264. setDX(0);
  265. cmdInitConsole(); // make sure conoutput is on
  266. return;
  267. }
  268. //
  269. // This function locates the appropriate keyboard definition file from
  270. // the given language, keyboard and code page id. It searches the registry
  271. // for third-party installed KDF files first and then falls back to
  272. // the system default, %systemroot%\system32\keyboard.sys.
  273. //
  274. // INPUT:
  275. // LanguageID -- the language id
  276. // KeyboardID -- the optional keyboard id, 0 means do not care
  277. // CodePageID -- the code page id
  278. // Buffer -- the buffer to receive fully qualified kdf file name
  279. // BufferSize -- the size of Buffer in bytes
  280. //
  281. // OUTPUT:
  282. // TRUE -- Buffer is filled with the kdf fully qualified file name and
  283. // *BufferSize is set with the size of the file name, not including
  284. // the null terminated char. If no kdf file can be found,
  285. // the Buffer is terminated with NULL and *BufferSize if set to 0.
  286. // FALSE -- error. GetLastError() should return the error code
  287. // If the error occurs because the provided buffer is too small
  288. // *BufferSize will set to the required size(excluding null
  289. // terminated char) and error code will be set to
  290. // ERROR_INSUFFICIENT_BUFFER
  291. //
  292. BOOL
  293. LocateKDF(
  294. CHAR* LanguageID,
  295. WORD KeyboardID,
  296. WORD CodePageID,
  297. LPSTR Buffer,
  298. DWORD* BufferSize
  299. )
  300. {
  301. HKEY hKeyWow;
  302. BOOL Result;
  303. DWORD dw, Type;
  304. DWORD Attributes;
  305. DWORD ErrorCode;
  306. CHAR* KDFName;
  307. CHAR* LocalBuffer;
  308. CHAR* FinalKDFName;
  309. CHAR FullName[MAX_PATH + 1];
  310. // validate buffer parameter first
  311. if (!CodePageID || !LanguageID || !BufferSize || (*BufferSize && !Buffer))
  312. {
  313. SetLastError(ERROR_INVALID_PARAMETER);
  314. return FALSE;
  315. }
  316. // Open the registry to see if we have alternative kdf files avaialble.
  317. // We seach the file from atlternative file list in the registry first.
  318. // The first KDF in the list has the highest rank and the last one has
  319. // the lowest. The search starts from highest rank and then goes
  320. // on toward the lower ones. As soon as a KDF file is found, the search
  321. // stops. If no appropriate KDF can be found in the alternative list,
  322. // the default kdf, keyboard.sys, will be used.
  323. //
  324. // FinalKDFName serves as an indicator. If it is NULL,
  325. // we do not find any file that satisfies the request.
  326. FinalKDFName = NULL;
  327. LocalBuffer = NULL;
  328. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  329. REG_STR_WOW,
  330. 0,
  331. KEY_EXECUTE,
  332. &hKeyWow
  333. ) == ERROR_SUCCESS)
  334. {
  335. // first probe for size
  336. dw = 0;
  337. RegQueryValueEx(hKeyWow, REG_STR_ALTKDF_FILES, NULL, &Type, NULL, &dw);
  338. if (dw && (REG_MULTI_SZ == Type))
  339. {
  340. // we have something in the registry. Allocate a buffer to reteive
  341. // it. We want the value to be double null terminated,
  342. // so we add one more char in case it is a REG_SZ.
  343. // The returned size from RegQueryValueEx includes the
  344. // null terminated char(and the double null chars for
  345. // REG_MULTI_SZ. By adding one more char, we are in
  346. // good shape.
  347. ASSERT(!LocalBuffer);
  348. LocalBuffer = malloc((dw + 1)* sizeof(CHAR));
  349. if (LocalBuffer)
  350. {
  351. LocalBuffer[0] = '\0';
  352. if (RegQueryValueEx(hKeyWow, REG_STR_ALTKDF_FILES, NULL, &Type,
  353. LocalBuffer, &dw) == ERROR_SUCCESS && dw)
  354. {
  355. KDFName = LocalBuffer;
  356. while ('\0' != *KDFName)
  357. {
  358. // See if we can find the file first.
  359. Attributes = GetFileAttributesA(KDFName);
  360. if (0xFFFFFFFF == Attributes)
  361. {
  362. // file not found, do a search
  363. if (SearchPathA(NULL, // no path
  364. KDFName,
  365. NULL, // no extension
  366. sizeof(FullName) / sizeof(CHAR),
  367. FullName,
  368. NULL
  369. ))
  370. {
  371. FinalKDFName = FullName;
  372. }
  373. }
  374. else
  375. {
  376. FinalKDFName = KDFName;
  377. }
  378. if (MatchKDF(LanguageID, KeyboardID, CodePageID, FinalKDFName))
  379. break;
  380. KDFName += strlen(KDFName) + 1;
  381. FinalKDFName = NULL;
  382. }
  383. }
  384. }
  385. else
  386. {
  387. // not enough memory
  388. RcMessageBox(EG_MALLOC_FAILURE, NULL, NULL,
  389. RMB_ICON_BANG | RMB_ABORT);
  390. TerminateVDM();
  391. }
  392. }
  393. if (!FinalKDFName)
  394. {
  395. // either no alternative kdf files are specified in the registry
  396. // or none of them contains the required specification,
  397. // use the default kdf file
  398. FullName[0] = '\0';
  399. GetSystemDirectory(FullName, sizeof(FullName) / sizeof(CHAR));
  400. if (!_stricmp(LanguageID, "JP") &&
  401. 7 == GetKeyboardType(0)
  402. ) {
  403. // For Japanese language ID, different keyboard types have different
  404. // default kdf.
  405. int Keytype;
  406. Keytype = GetKeyboardType(1);
  407. if (Keytype == 1)
  408. strcat(FullName, KDF_AX);
  409. else if (Keytype == 2)
  410. strcat(FullName, KDF_106);
  411. else if (Keytype == 3)
  412. strcat(FullName, KDF_IBM5576_02_03);
  413. else if ((Keytype & 0xFF00) == 0x1200)
  414. strcat(FullName, KDF_TOSHIBA_J3100);
  415. else
  416. strcat(FullName, KEYBOARD_SYS);
  417. }
  418. else
  419. strcat(FullName, KEYBOARD_SYS);
  420. FinalKDFName = FullName;
  421. }
  422. RegCloseKey(hKeyWow);
  423. }
  424. if (FinalKDFName)
  425. {
  426. dw = strlen(FinalKDFName);
  427. if (dw && dw < *BufferSize)
  428. {
  429. strcpy(Buffer, FinalKDFName);
  430. *BufferSize = dw;
  431. Result = TRUE;
  432. }
  433. else
  434. {
  435. *BufferSize = dw;
  436. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  437. Result = FALSE;
  438. }
  439. }
  440. else
  441. {
  442. Result = FALSE;
  443. *BufferSize = 0;
  444. SetLastError(ERROR_FILE_NOT_FOUND);
  445. }
  446. //
  447. // finally, free the buffer we allocated
  448. //
  449. if (LocalBuffer)
  450. free(LocalBuffer);
  451. return Result;
  452. }
  453. //
  454. // This function determines if the given kdf supports the given
  455. // (language id, keyboard id, code page id) combination
  456. //
  457. // INPUT:
  458. // LanguageID -- the language.
  459. // KeyboardID -- optional keyboard id. 0 if do not care
  460. // CodePageID -- code page id
  461. // KDFPath -- fully qualified kdf file
  462. // OUTPUT:
  463. // TRUE -- The kdf contains the given combination
  464. // FALSE -- either the kdf does not contain the combination or
  465. // can not determine.
  466. //
  467. BOOL
  468. MatchKDF(
  469. CHAR* LanguageID,
  470. WORD KeyboardID,
  471. WORD CodePageID,
  472. LPCSTR KDFPath
  473. )
  474. {
  475. HANDLE hKDF;
  476. KDF_HEADER Header;
  477. KDF_LANGID_ENTRY LangIdEntry;
  478. DWORD BytesRead, BufferSize;
  479. WORD Index;
  480. DWORD LangIdEntryOffset;
  481. PKDF_CODEPAGEID_OFFSET pCodePageIdOffset;
  482. BOOL Matched;
  483. if (!KDFPath || !LanguageID || !CodePageID)
  484. {
  485. SetLastError(ERROR_INVALID_PARAMETER);
  486. return FALSE;
  487. }
  488. Matched = FALSE;
  489. LangIdEntryOffset = 0;
  490. // open the kdf file.
  491. hKDF = CreateFile(KDFPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  492. NULL, OPEN_EXISTING, 0, NULL);
  493. if (INVALID_HANDLE_VALUE != hKDF &&
  494. ReadFile(hKDF, &Header, sizeof(Header),&BytesRead, NULL) &&
  495. BytesRead == sizeof(Header) && Header.TotalLangIDs &&
  496. Header.TotalKeybIDs &&
  497. !strncmp(Header.Signature, KDF_SIGNATURE, sizeof(Header.Signature))
  498. )
  499. {
  500. // The file header is loaded, the signature checked and sanity check
  501. // on language and keyboard id counts is also done.
  502. // We are now ready to verfiy if the given language id, keyboard id
  503. // and code page id is supported in this file.
  504. // A KDF has two sets of offset table. One is based on language ID
  505. // while the other one is based on keyboard id. Since a language ID
  506. // may contain multiple keyboard id, the keyboard id set is always
  507. // encompass the language id table.
  508. // If the caller gives us a keyboard id, we use the id as the
  509. // key for search and verify language id when we found the keyboard
  510. // id. If no keyboard id is provided, we use the language id as the
  511. // key.
  512. if (KeyboardID)
  513. {
  514. // move the file pointer to the keyboard id offset array
  515. BufferSize = sizeof(KDF_LANGID_OFFSET) * Header.TotalLangIDs;
  516. BufferSize = SetFilePointer(hKDF, BufferSize, NULL, FILE_CURRENT);
  517. if (0xFFFFFFFF != BufferSize)
  518. {
  519. PKDF_KEYBOARDID_OFFSET pKeybIdOffset;
  520. BufferSize = sizeof(KDF_KEYBOARDID_OFFSET) * Header.TotalKeybIDs;
  521. pKeybIdOffset = (PKDF_KEYBOARDID_OFFSET)malloc(BufferSize);
  522. if (!pKeybIdOffset)
  523. {
  524. // not enough memory
  525. RcMessageBox(EG_MALLOC_FAILURE, NULL, NULL,
  526. RMB_ICON_BANG | RMB_ABORT);
  527. TerminateVDM();
  528. }
  529. if (ReadFile(hKDF, pKeybIdOffset, BufferSize, &BytesRead, NULL) &&
  530. BytesRead == BufferSize)
  531. {
  532. // loop though each KDF_KEYBOARDID_OFFSET to see
  533. // if the keyboard id matches.
  534. for (Index = 0; Index < Header.TotalKeybIDs; Index++)
  535. {
  536. if (pKeybIdOffset[Index].ID == KeyboardID)
  537. {
  538. // got it. Remeber the file offset to
  539. // the KDF_LANGID_ENTRY
  540. LangIdEntryOffset = pKeybIdOffset[Index].DataOffset;
  541. break;
  542. }
  543. }
  544. }
  545. free(pKeybIdOffset);
  546. }
  547. }
  548. else
  549. {
  550. PKDF_LANGID_OFFSET pLangIdOffset;
  551. BufferSize = sizeof(KDF_LANGID_OFFSET) * Header.TotalLangIDs;
  552. pLangIdOffset = (PKDF_LANGID_OFFSET)malloc(BufferSize);
  553. if (!pLangIdOffset)
  554. {
  555. // not enough memory
  556. RcMessageBox(EG_MALLOC_FAILURE, NULL, NULL,
  557. RMB_ICON_BANG | RMB_ABORT);
  558. TerminateVDM();
  559. }
  560. if (ReadFile(hKDF, pLangIdOffset, BufferSize, &BytesRead, NULL) &&
  561. BytesRead == BufferSize)
  562. {
  563. // loop through each KDF_LANGID_OFFSET to see if
  564. // language id matches
  565. for (Index = 0; Index < Header.TotalLangIDs; Index++)
  566. {
  567. if (IS_LANGID_EQUAL(pLangIdOffset[Index].ID, LanguageID))
  568. {
  569. LangIdEntryOffset = pLangIdOffset[Index].DataOffset;
  570. break;
  571. }
  572. }
  573. }
  574. free(pLangIdOffset);
  575. }
  576. if (LangIdEntryOffset)
  577. {
  578. BufferSize = SetFilePointer(hKDF, LangIdEntryOffset, NULL, FILE_BEGIN);
  579. if (0xFFFFFFFF != BufferSize &&
  580. ReadFile(hKDF, &LangIdEntry, sizeof(LangIdEntry), &BytesRead, NULL) &&
  581. BytesRead == sizeof(LangIdEntry))
  582. {
  583. // sanity checks
  584. if (IS_LANGID_EQUAL(LangIdEntry.ID, LanguageID) &&
  585. LangIdEntry.TotalCodePageIDs)
  586. {
  587. // the KDF_LANGID_ENTRY looks fine. Now retrieve
  588. // its code page offset table and search the given
  589. // code page id
  590. BufferSize = LangIdEntry.TotalCodePageIDs * sizeof(KDF_CODEPAGEID_OFFSET);
  591. pCodePageIdOffset = (PKDF_CODEPAGEID_OFFSET)malloc(BufferSize);
  592. if (!pCodePageIdOffset)
  593. {
  594. // not enough memory
  595. RcMessageBox(EG_MALLOC_FAILURE, NULL, NULL,
  596. RMB_ICON_BANG | RMB_ABORT);
  597. TerminateVDM();
  598. }
  599. if (ReadFile(hKDF, pCodePageIdOffset, BufferSize, &BytesRead, NULL) &&
  600. BytesRead == BufferSize)
  601. {
  602. for (Index = 0; Index < LangIdEntry.TotalCodePageIDs; Index++)
  603. {
  604. if (CodePageID == pCodePageIdOffset[Index].ID)
  605. {
  606. Matched = TRUE;
  607. break;
  608. }
  609. }
  610. }
  611. free(pCodePageIdOffset);
  612. }
  613. }
  614. }
  615. CloseHandle(hKDF);
  616. }
  617. return Matched;
  618. }