Leaked source code of windows server 2003
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.

862 lines
25 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. keyboard.c
  5. Abstract:
  6. Implements routines to merge keyboard layouts from the upgraded win9x
  7. system and a clean win2k install. The result is that Windows 2000 has
  8. the base keyboard layout support it expects and any additional layouts
  9. (third party IMEs, newer Microsoft IMEs) that may have been present in
  10. the original operating system.
  11. This code was modified from a base originally in Rulehlpr.c
  12. Author:
  13. Marc R. Whitten (marcw) 26-Jan-1999
  14. Revision History:
  15. marcw 26-Apr-1999 Add support for mapping changed keyboard layouts.
  16. --*/
  17. #include "pch.h"
  18. #include "rulehlprp.h"
  19. FILTERRETURN
  20. pKeyboardLayoutsFilter (
  21. IN CPDATAOBJECT SrcObject,
  22. IN CPDATAOBJECT DstObject,
  23. IN FILTERTYPE FilterType,
  24. IN PVOID Arg
  25. )
  26. {
  27. FILTERRETURN rState = FILTER_RETURN_CONTINUE;
  28. DATAOBJECT object;
  29. BOOL freeObject = FALSE;
  30. TCHAR layoutFile[MAX_TCHAR_PATH];
  31. PTSTR extension = NULL;
  32. TCHAR key[MEMDB_MAX];
  33. DWORD unused;
  34. __try {
  35. rState = Standard9xSuppressFilter (SrcObject, DstObject, FilterType, Arg);
  36. if (rState != FILTER_RETURN_CONTINUE) {
  37. __leave;
  38. }
  39. //
  40. // Check to make sure we want to enumerate this entry.
  41. //
  42. if (FilterType == FILTER_KEY_ENUM) {
  43. //
  44. // If the Keyboard Layout begins with a '0' It is a locale specific keyboard layout. In these cases, we
  45. // use the NT value.
  46. //
  47. if (*SrcObject->ChildKey == TEXT('0')) {
  48. //
  49. // This is a standard locale keyboard layout. We want this to go to the NT default after migration.
  50. // Skip copying this over from win95.
  51. //
  52. rState = FILTER_RETURN_HANDLED;
  53. __leave;
  54. }
  55. if (*SrcObject->ChildKey != TEXT('E') && *SrcObject->ChildKey != TEXT('e')) {
  56. DEBUGMSG ((DBG_WHOOPS, "Unknown format. Skipping %s.", DEBUGENCODER(SrcObject)));
  57. rState = FILTER_RETURN_HANDLED;
  58. __leave;
  59. }
  60. }
  61. //
  62. // Don't create empty object. This may be suppressed.
  63. //
  64. if (FilterType == FILTER_CREATE_KEY) {
  65. rState = FILTER_RETURN_HANDLED;
  66. __leave;
  67. }
  68. if (FilterType == FILTER_PROCESS_VALUES) {
  69. //
  70. // We need to look at the value of Ime File.
  71. // This will determine what we do with this entry.
  72. //
  73. if (!DuplicateObjectStruct (&object, SrcObject)) {
  74. rState = FILTER_RETURN_FAIL;
  75. }
  76. freeObject = TRUE;
  77. FreeObjectVal (&object);
  78. SetRegistryValueName (&object, TEXT("IME File"));
  79. if (!ReadObject (&object) || object.Type != REG_SZ) {
  80. DEBUGMSG ((
  81. DBG_WARNING,
  82. "No usable IME File data for %s. It will be suppressed.",
  83. DEBUGENCODER(SrcObject)
  84. ));
  85. rState = FILTER_RETURN_HANDLED;
  86. __leave;
  87. }
  88. if (object.Value.Size > (MAX_PATH * sizeof (WCHAR))) {
  89. rState = FILTER_RETURN_HANDLED;
  90. __leave;
  91. }
  92. //
  93. // Suppress this setting unless we are going to leave the file alone
  94. // (or at worst move it around somewhere...)
  95. //
  96. MemDbBuildKey (key, MEMDB_CATEGORY_GOOD_IMES, (PCTSTR) object.Value.Buffer, NULL, NULL);
  97. if (!MemDbGetValue (key, &unused)) {
  98. rState = FILTER_RETURN_HANDLED;
  99. DEBUGMSG ((
  100. DBG_WARNING,
  101. "Ime Layout Entry for %s will be suppressed.",
  102. DEBUGENCODER(SrcObject)
  103. ));
  104. __leave;
  105. }
  106. }
  107. if (FilterType == FILTER_VALUE_COPY) {
  108. //
  109. // We need to massage the layout file if we are bringing this over.
  110. //
  111. if (StringIMatch (SrcObject->ValueName, S_LAYOUT_FILE)) {
  112. //
  113. // Convert layout file.
  114. //
  115. _tcssafecpy (layoutFile, (PTSTR) SrcObject->Value.Buffer, MAX_TCHAR_PATH);
  116. //
  117. // We must map kbdjp.kbd to kbdjpn.dll In all other cases, we simply replace the
  118. // .kbd extension with .dll.
  119. //
  120. if (StringIMatch (layoutFile, S_KBDJPDOTKBD)) {
  121. StringCopy (layoutFile, S_KBDJPNDOTDLL);
  122. }
  123. else if (IsPatternMatch (TEXT("*.KBD"), layoutFile)) {
  124. extension = _tcsrchr (layoutFile, TEXT('.'));
  125. if (extension) {
  126. StringCopy (extension, S_DLL);
  127. }
  128. }
  129. //
  130. // Now, we need to write this object.
  131. //
  132. if (!DuplicateObjectStruct (&object, DstObject)) {
  133. rState = FILTER_RETURN_FAIL;
  134. __leave;
  135. }
  136. freeObject = TRUE;
  137. if (!ReplaceValueWithString (&object, layoutFile)) {
  138. rState = FILTER_RETURN_FAIL;
  139. __leave;
  140. }
  141. SetRegistryType (&object, REG_SZ);
  142. if (!WriteObject (&object)) {
  143. rState = FILTER_RETURN_FAIL;
  144. __leave;
  145. }
  146. rState = FILTER_RETURN_HANDLED;
  147. }
  148. }
  149. }
  150. __finally {
  151. if (freeObject) {
  152. FreeObjectStruct (&object);
  153. }
  154. }
  155. return rState;
  156. }
  157. /*++
  158. Routine Description:
  159. Migrate Keyboard Layouts is responsible for doing a smart merge between the
  160. win9x and windows NT keyboard layout registry entries. The following rules
  161. are
  162. used:
  163. (1) For basic locale keyboard layouts, we always use the NT default e
  164. ntry.
  165. (2) For IME entries, we examine the IME File entry. If the IME file w
  166. as deleted, we will not use it and will skip the entry. Only if we leave
  167. the IME file alone do we bring across the
  168. setting.
  169. Arguments:
  170. None.
  171. Return Value:
  172. --*/
  173. BOOL
  174. RuleHlpr_MigrateKeyboardLayouts (
  175. IN PCTSTR SrcObjectStr,
  176. IN PCTSTR DestObjectStr,
  177. IN PCTSTR User,
  178. IN PVOID Data
  179. )
  180. {
  181. DATAOBJECT source;
  182. DATAOBJECT destination;
  183. BOOL rSuccess = FALSE;
  184. //
  185. // If not local machine, don't process
  186. //
  187. if (User) {
  188. SetLastError (ERROR_SUCCESS);
  189. return FALSE;
  190. }
  191. //
  192. // We need to enumerate all keys in SrcObjectStr. For each key,
  193. // we examine the default Win9x value, which may cause us to change
  194. // the default value, or skip the key altogether.
  195. //
  196. __try {
  197. ZeroMemory (&source, sizeof (DATAOBJECT));
  198. ZeroMemory (&destination, sizeof (DATAOBJECT));
  199. if (!CreateObjectStruct (SrcObjectStr, &source, WIN95OBJECT)) {
  200. DEBUGMSG ((DBG_WARNING, "MigrateKeyboardLayouts: %s is invalid", SrcObjectStr));
  201. __leave;
  202. }
  203. if (!(source.ObjectType & OT_TREE)) {
  204. DEBUGMSG ((DBG_WARNING, "MigrateKeyboardLayouts %s does not specify subkeys -- skipping rule", SrcObjectStr));
  205. rSuccess = TRUE;
  206. __leave;
  207. }
  208. //
  209. // Our filter function will do the real copying, removing any entries that need to be skipped.
  210. //
  211. DuplicateObjectStruct (&destination, &source);
  212. SetPlatformType (&destination, WINNTOBJECT);
  213. rSuccess = CopyObject (&source, &destination, pKeyboardLayoutsFilter, NULL);
  214. //
  215. // If there were no entries, return success
  216. //
  217. if (!rSuccess) {
  218. if (GetLastError() == ERROR_FILE_NOT_FOUND ||
  219. GetLastError() == ERROR_NO_MORE_ITEMS
  220. ) {
  221. rSuccess = TRUE;
  222. }
  223. }
  224. }
  225. __finally {
  226. FreeObjectStruct (&destination);
  227. FreeObjectStruct (&source);
  228. }
  229. return rSuccess;
  230. }
  231. #define S_KEYBOARD_LAYOUT_MAPPINGS TEXT("Keyboard.Layout.Mappings")
  232. PCTSTR
  233. pMapKeyboardLayoutIfNecessary (
  234. IN PCTSTR Layout
  235. )
  236. {
  237. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  238. PTSTR rData = NULL;
  239. PCTSTR p = NULL;
  240. if (InfFindFirstLine (g_UserMigInf, S_KEYBOARD_LAYOUT_MAPPINGS, Layout, &is)) {
  241. //
  242. // This keyboard layout should be mapped.
  243. //
  244. p = InfGetStringField (&is, 1);
  245. MYASSERT (p);
  246. }
  247. if (p) {
  248. rData = MemAlloc (g_hHeap, 0, SizeOfString (p));
  249. StringCopy (rData, p);
  250. }
  251. else {
  252. rData = (PTSTR) Layout;
  253. }
  254. InfCleanUpInfStruct (&is);
  255. return rData;
  256. }
  257. FILTERRETURN
  258. pMigrateKeyboardSubstitutesFilter (
  259. IN CPDATAOBJECT SrcObject,
  260. IN CPDATAOBJECT DstObject,
  261. IN FILTERTYPE Type,
  262. IN PVOID Arg
  263. )
  264. {
  265. DATAOBJECT newObject;
  266. PKEYTOVALUEARG keyToValueArgs = (PKEYTOVALUEARG) Arg;
  267. PCTSTR data;
  268. //
  269. // We want to create the initial key, but not any of the subkeys.
  270. //
  271. if (Type == FILTER_CREATE_KEY) {
  272. if (keyToValueArgs -> EnumeratingSubKeys) {
  273. return FILTER_RETURN_HANDLED;
  274. }
  275. else {
  276. return FILTER_RETURN_CONTINUE;
  277. }
  278. } else if (Type == FILTER_KEY_ENUM) {
  279. if (!keyToValueArgs -> EnumeratingSubKeys) {
  280. keyToValueArgs -> EnumeratingSubKeys = TRUE;
  281. }
  282. return FILTER_RETURN_CONTINUE;
  283. } else if (Type == FILTER_VALUENAME_ENUM && keyToValueArgs -> EnumeratingSubKeys) {
  284. if (!*SrcObject -> ValueName) {
  285. return FILTER_RETURN_CONTINUE;
  286. }
  287. ELSE_DEBUGMSG((DBG_WHOOPS,"Keyboard Substitutes: Unexpected value names."));
  288. return FILTER_RETURN_HANDLED;
  289. }
  290. else if (Type == FILTER_VALUE_COPY && keyToValueArgs -> EnumeratingSubKeys) {
  291. //
  292. // If this is the default value, we have the information we need to create the value for this.
  293. //
  294. if (!*SrcObject -> ValueName) {
  295. //
  296. // Create the object struct for the Nt setting.
  297. //
  298. DuplicateObjectStruct (&newObject, &(keyToValueArgs->Object));
  299. SetRegistryValueName (&newObject, _tcsrchr(SrcObject->KeyPtr->KeyString, TEXT('\\')) + 1);
  300. //
  301. // We need to see if this keyboard layout string needs to be mapped.
  302. //
  303. data = pMapKeyboardLayoutIfNecessary ((PTSTR) SrcObject->Value.Buffer);
  304. if (!data) {
  305. return FILTER_RETURN_FAIL;
  306. }
  307. //
  308. // Write this into the nt registry.
  309. //
  310. ReplaceValueWithString (&newObject, data);
  311. SetRegistryType (&newObject,REG_SZ);
  312. WriteObject (&newObject);
  313. //
  314. // Clean up resources.
  315. //
  316. if (!StringIMatch (data, (PTSTR) SrcObject->Value.Buffer)) {
  317. MemFree (g_hHeap, 0, data);
  318. }
  319. FreeObjectStruct (&newObject);
  320. }
  321. ELSE_DEBUGMSG((DBG_WHOOPS,"Keyboard Substitutes: Unexpected value names.."));
  322. return FILTER_RETURN_HANDLED;
  323. }
  324. return FILTER_RETURN_CONTINUE;
  325. }
  326. BOOL
  327. RuleHlpr_MigrateKeyboardSubstitutes (
  328. IN PCTSTR SrcObjectStr,
  329. IN PCTSTR DestObjectStr,
  330. IN PCTSTR User,
  331. IN PVOID Data
  332. )
  333. {
  334. BOOL rSuccess = TRUE;
  335. FILTERRETURN fr;
  336. DATAOBJECT srcObject;
  337. DATAOBJECT dstObject;
  338. KEYTOVALUEARG args;
  339. //
  340. // We need to enumerate all keys in SrcObjectStr. For each key,
  341. // we will change the subkey to a value.
  342. //
  343. __try {
  344. ZeroMemory (&srcObject, sizeof (DATAOBJECT));
  345. ZeroMemory (&dstObject, sizeof (DATAOBJECT));
  346. if (!CreateObjectStruct (SrcObjectStr, &srcObject, WIN95OBJECT)) {
  347. DEBUGMSG ((DBG_WARNING, "MigrateKeyboardSubstitutes: %s is invalid", SrcObjectStr));
  348. rSuccess = FALSE;
  349. __leave;
  350. }
  351. if (!(srcObject.ObjectType & OT_TREE)) {
  352. DEBUGMSG ((DBG_WARNING, "MigrateKeyboardSubstitutes: %s does not specify subkeys -- skipping rule", SrcObjectStr));
  353. __leave;
  354. }
  355. DuplicateObjectStruct (&dstObject, &srcObject);
  356. SetPlatformType (&dstObject, WINNTOBJECT);
  357. ZeroMemory(&args,sizeof(KEYTOVALUEARG));
  358. DuplicateObjectStruct(&(args.Object),&dstObject);
  359. fr = CopyObject (&srcObject, &dstObject, pMigrateKeyboardSubstitutesFilter,&args);
  360. FreeObjectStruct(&(args.Object));
  361. DEBUGMSG_IF((fr == FILTER_RETURN_FAIL,DBG_WHOOPS,"MigrateKeyboardSubstitutes: CopyObject returned false."));
  362. SetLastError(ERROR_SUCCESS);
  363. }
  364. __finally {
  365. FreeObjectStruct (&dstObject);
  366. FreeObjectStruct (&srcObject);
  367. }
  368. return rSuccess;
  369. }
  370. BOOL
  371. pGetKeyboardSubstitutes (
  372. IN PCTSTR LocaleID,
  373. OUT PGROWBUFFER Gb
  374. )
  375. {
  376. HINF inf;
  377. INFCONTEXT ic;
  378. DWORD fields;
  379. DWORD index;
  380. DWORD dLocaleID;
  381. PTSTR substLocaleID;
  382. DWORD dSubstLocaleID;
  383. TCHAR mapping[20];
  384. TCHAR key[MEMDB_MAX];
  385. TCHAR strLocaleID[10];
  386. PTSTR final;
  387. BOOL b = FALSE;
  388. inf = SetupOpenInfFile (TEXT("intl.inf"), NULL, INF_STYLE_WIN4, NULL);
  389. if (inf != INVALID_HANDLE_VALUE) {
  390. if (SetupFindFirstLine (inf, TEXT("Locales"), LocaleID, &ic)) {
  391. fields = SetupGetFieldCount (&ic);
  392. for (index = 5; index <= fields; index++) {
  393. if (SetupGetStringField (&ic, index, mapping, 20, NULL)) {
  394. //
  395. // the format is LCID:SubstituteKLID
  396. //
  397. dLocaleID = _tcstoul (mapping, &substLocaleID, 16);
  398. while (_istspace (*substLocaleID)) {
  399. substLocaleID++;
  400. }
  401. if (*substLocaleID != TEXT(':')) {
  402. //
  403. // unknown field format
  404. //
  405. continue;
  406. }
  407. substLocaleID++;
  408. dSubstLocaleID = _tcstoul (substLocaleID, &final, 16);
  409. if (*final) {
  410. //
  411. // unknown field format
  412. //
  413. continue;
  414. }
  415. if (dSubstLocaleID == dLocaleID) {
  416. continue;
  417. }
  418. //
  419. // record this pair
  420. //
  421. wsprintf (strLocaleID, TEXT("%08x"), dLocaleID);
  422. MemDbBuildKey (key, MEMDB_CATEGORY_KEYBOARD_LAYOUTS, strLocaleID, NULL, NULL);
  423. if (MemDbGetValue (key, NULL)) {
  424. MultiSzAppend (Gb, strLocaleID);
  425. MultiSzAppend (Gb, substLocaleID);
  426. b = TRUE;
  427. }
  428. }
  429. }
  430. }
  431. SetupCloseInfFile (inf);
  432. }
  433. return b;
  434. }
  435. #define S_KEYBOARD_LAYOUT_PRELOAD_REG TEXT("HKCU\\Keyboard Layout\\Preload")
  436. BOOL
  437. RuleHlpr_MigrateKeyboardPreloads (
  438. IN PCTSTR SrcObjectStr,
  439. IN PCTSTR DestObjectStr,
  440. IN PCTSTR User,
  441. IN PVOID Data
  442. )
  443. {
  444. DATAOBJECT source;
  445. DATAOBJECT destination;
  446. REGKEY_ENUM eKey;
  447. REGVALUE_ENUM eValue;
  448. PCTSTR data = NULL;
  449. TCHAR sequencerStr[MEMDB_MAX];
  450. UINT sequencer;
  451. PCTSTR imeFile = NULL;
  452. BOOL keepPreload = FALSE;
  453. TCHAR key[MEMDB_MAX];
  454. BOOL rSuccess = TRUE;
  455. MEMDB_ENUM e;
  456. UINT unused = 0;
  457. HKEY regKey;
  458. PTSTR regStr = NULL;
  459. PTSTR p;
  460. GROWBUFFER gb = GROWBUF_INIT;
  461. MULTISZ_ENUM sze;
  462. PTSTR localeIDStr;
  463. //
  464. // If not User, don't process.
  465. //
  466. if (!User) {
  467. SetLastError (ERROR_SUCCESS);
  468. return FALSE;
  469. }
  470. __try {
  471. ZeroMemory (&source, sizeof (DATAOBJECT));
  472. ZeroMemory (&destination, sizeof (DATAOBJECT));
  473. if (!CreateObjectStruct (SrcObjectStr, &source, WIN95OBJECT)) {
  474. DEBUGMSG ((DBG_WARNING, "MigrateKeyboardPreloads: %s is invalid", SrcObjectStr));
  475. rSuccess = FALSE;
  476. __leave;
  477. }
  478. if (!OpenObject (&source)) {
  479. DEBUGMSG ((DBG_WARNING, "MigrateKeyboardPreloads: Unable to open %s.", SrcObjectStr));
  480. rSuccess = FALSE;
  481. __leave;
  482. }
  483. if (!(source.ObjectType & OT_TREE)) {
  484. DEBUGMSG ((DBG_WARNING, "MigrateKeyboardPreloads %s does not specify subkeys -- skipping rule", SrcObjectStr));
  485. __leave;
  486. }
  487. //
  488. // First, enumerate the win9x preloads and throw them in memdb.
  489. //
  490. if (EnumFirstRegKey95 (&eKey, source.KeyPtr->OpenKey)) {
  491. do {
  492. keepPreload = FALSE;
  493. data = NULL;
  494. imeFile = NULL;
  495. regKey = OpenRegKey95 (eKey.KeyHandle, eKey.SubKeyName);
  496. if (regKey) {
  497. if(_tcslen(eKey.SubKeyName) >= ARRAYSIZE(sequencerStr)){
  498. MYASSERT(FALSE);
  499. LOG((LOG_WARNING, "MigrateKeyboardPreloads %s does not provide enough buffer for subkey %s-- skipping rule", SrcObjectStr, eKey.SubKeyName));
  500. __leave;
  501. }
  502. StringCopy (sequencerStr, eKey.SubKeyName);
  503. data = GetRegValueString95 (regKey, TEXT(""));
  504. CloseRegKey95 (regKey);
  505. }
  506. if (data) {
  507. keepPreload = TRUE;
  508. //
  509. // If this is an IME entry, we have to make sure it will be migrated.
  510. //
  511. if (*data == TEXT('E') || *data == TEXT('e')) {
  512. //
  513. // Determine if this IME will be migrated.
  514. //
  515. regStr = JoinPaths (S_KEYBOARD_LAYOUT_REG, data);
  516. regKey = OpenRegKeyStr95 (regStr);
  517. FreePathString (regStr);
  518. if (regKey) {
  519. imeFile = GetRegValueString95 (regKey, TEXT("IME File"));
  520. CloseRegKey95 (regKey);
  521. }
  522. if (imeFile) {
  523. MemDbBuildKey (key, MEMDB_CATEGORY_GOOD_IMES, imeFile, NULL, NULL);
  524. if (!MemDbGetValue (key, &unused)) {
  525. //
  526. // This layout entry will not be migrated. Blast the preload away.
  527. //
  528. keepPreload = FALSE;
  529. }
  530. MemFree (g_hHeap, 0, imeFile);
  531. }
  532. else {
  533. keepPreload = FALSE;
  534. }
  535. }
  536. //
  537. // See if we need to map the 9x keyboard layout to the proper NT layout.
  538. //
  539. data = pMapKeyboardLayoutIfNecessary (data);
  540. if (keepPreload) {
  541. //
  542. // Usable preload. Save this into memdb. We'll use it later to actually write
  543. // the user preload entries.
  544. //
  545. MemDbSetValueEx (MEMDB_CATEGORY_KEYBOARD_LAYOUTS, sequencerStr, data, NULL, 0, NULL);
  546. }
  547. if (data) {
  548. MemFree (g_hHeap, 0, data);
  549. }
  550. }
  551. } while (EnumNextRegKey95 (&eKey));
  552. }
  553. //
  554. // Now we need to look at what the NT default preloads are. We will move those preloads behind any preloads that will be migrated.
  555. //
  556. sequencer = 900;
  557. regKey = OpenRegKeyStr (S_KEYBOARD_LAYOUT_PRELOAD_REG);
  558. if (regKey) {
  559. if (EnumFirstRegValue (&eValue, regKey)) {
  560. do {
  561. data = GetRegValueString (eValue.KeyHandle, eValue.ValueName);
  562. if (data) {
  563. //
  564. // Check to see if we have already added this entry into memdb.
  565. //
  566. MemDbBuildKey (key, MEMDB_CATEGORY_KEYBOARD_LAYOUTS, TEXT("*"), data, NULL);
  567. if (!MemDbGetValueWithPattern (key, NULL)) {
  568. //
  569. // Preload that was *not* on Windows 9x. We need to add this to our list.
  570. //
  571. wsprintf (sequencerStr, TEXT("%d"), sequencer);
  572. MemDbSetValueEx (MEMDB_CATEGORY_KEYBOARD_LAYOUTS, sequencerStr, data, NULL, 1, NULL);
  573. sequencer++;
  574. }
  575. MemFree (g_hHeap, 0, data);
  576. }
  577. } while (EnumNextRegValue (&eValue));
  578. }
  579. CloseRegKey (regKey);
  580. }
  581. //
  582. // Now we have the complete list of preloads to migrate. We only need to enumerate through memdb and create
  583. // entries for all of the data collected.
  584. //
  585. sequencer = 1;
  586. if (MemDbGetValueEx (&e, MEMDB_CATEGORY_KEYBOARD_LAYOUTS, NULL, NULL)) {
  587. do {
  588. localeIDStr = _tcschr (e.szName, TEXT('\\'));
  589. if (localeIDStr) {
  590. localeIDStr = _tcsinc (localeIDStr);
  591. } else {
  592. MYASSERT (FALSE);
  593. }
  594. //
  595. // Create the object to write and fill in the valuename and data.
  596. //
  597. ZeroMemory (&destination, sizeof (DATAOBJECT));
  598. DuplicateObjectStruct (&destination, &source);
  599. SetPlatformType (&destination, WINNTOBJECT);
  600. wsprintf (sequencerStr, TEXT("%d"), sequencer);
  601. sequencer++;
  602. SetRegistryValueName (&destination, sequencerStr);
  603. SetRegistryType (&destination, REG_SZ);
  604. ReplaceValueWithString (&destination, localeIDStr);
  605. //
  606. // Write the object.
  607. //
  608. WriteObject (&destination);
  609. FreeObjectStruct (&destination);
  610. //
  611. // also write the corresponding substitute, if appropriate
  612. //
  613. if (pGetKeyboardSubstitutes (localeIDStr, &gb)) {
  614. StackStringCopy (key, DestObjectStr);
  615. p = _tcsrchr (key, TEXT('\\'));
  616. if (!p) {
  617. DEBUGMSG ((DBG_WARNING, "MigrateKeyboardPreloads: %s is invalid", DestObjectStr));
  618. continue;
  619. }
  620. StringCopyTcharCount (p + 1, TEXT("Substitutes"), ARRAYSIZE(key) - ((p + 1) - key));
  621. if (!CreateObjectStruct (key, &destination, WINNTOBJECT)) {
  622. DEBUGMSG ((DBG_WARNING, "MigrateKeyboardPreloads: CreateObjectStruct failed with %s", key));
  623. continue;
  624. }
  625. if (EnumFirstMultiSz (&sze, (PCTSTR)gb.Buf)) {
  626. SetRegistryValueName (&destination, sze.CurrentString);
  627. SetRegistryType (&destination, REG_SZ);
  628. if (EnumNextMultiSz (&sze)) {
  629. ReplaceValueWithString (&destination, sze.CurrentString);
  630. WriteObject (&destination);
  631. }
  632. }
  633. FreeObjectStruct (&destination);
  634. FreeGrowBuffer (&gb);
  635. }
  636. } while (MemDbEnumNextValue (&e));
  637. }
  638. }
  639. __finally {
  640. FreeObjectStruct (&source);
  641. FreeObjectStruct (&destination);
  642. }
  643. //
  644. // Delete this every time through.
  645. //
  646. MemDbDeleteTree (MEMDB_CATEGORY_KEYBOARD_LAYOUTS);
  647. SetLastError (ERROR_SUCCESS);
  648. return rSuccess;
  649. }