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.

1633 lines
45 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. file.cpp
  5. Abstract:
  6. Contains the input file abstraction
  7. implementation
  8. Author:
  9. Mike Cirello
  10. Vijay Jayaseelan (vijayj)
  11. Revision History:
  12. 03 March 2001 :
  13. Rewamp the whole source to make it more maintainable
  14. (particularly readable)
  15. --*/
  16. #include <stdio.h>
  17. #include "File.h"
  18. #include "msginc.h"
  19. //
  20. // static data member initialization
  21. //
  22. TCHAR File::targetDirectory[1024] = {0};
  23. FileList File::files;
  24. int File::ctr = 0;
  25. //
  26. // constant strings
  27. //
  28. const std::wstring INTL_INF_FILENAME = TEXT("intl.inf");
  29. const std::wstring FONT_INF_FILENAME = TEXT("font.inf");
  30. const std::wstring REGIONAL_SECTION_NAME = TEXT("regionalsettings");
  31. const std::wstring LANGUAGE_GROUP_KEY = TEXT("languagegroup");
  32. const std::wstring LANGUAGE_KEY = TEXT("language");
  33. const std::wstring REGMAPPER_SECTION_NAME = TEXT("registrymapper");
  34. const std::wstring LANGGROUP_SECTION_PREFIX = TEXT("lg_install_");
  35. const std::wstring DEFAULT_LANGGROUP_NAME = TEXT("lg_install_1");
  36. const std::wstring ADDREG_KEY = TEXT("addreg");
  37. const std::wstring LOCALES_SECTION_NAME = TEXT("locales");
  38. const std::wstring FONT_CP_REGSECTION_FMT_STR = TEXT("font.cp%s.%d");
  39. const std::wstring CCS_SOURCE_KEY = TEXT("currentcontrolset");
  40. const std::wstring CCS_TARGET_KEY = TEXT("ControlSet001");
  41. //
  42. // other constant values
  43. //
  44. const DWORD LANG_GROUP1_INDEX = 2;
  45. const DWORD OEM_CP_INDEX = 1;
  46. const DWORD DEFAULT_FONT_SIZE = 96;
  47. //
  48. // Set the target file and intialize the registry writer
  49. // The luid makes sure each file gets a different registry key
  50. //
  51. // Arguments:
  52. // pszTargetfile - file name (without path) that this File will be saved to.
  53. // bModify - T - load the targetfile and modify it. F - create new file
  54. //
  55. File::File(
  56. IN PCTSTR pszTargetFile,
  57. IN bool bModify
  58. )
  59. {
  60. luid = ctr;
  61. ctr++;
  62. targetFile = pszTargetFile;
  63. modify = bModify;
  64. wcscpy(wKey,L"\\");
  65. if (!modify) {
  66. regWriter.Init(luid,0);
  67. } else {
  68. wstring full = targetDirectory;
  69. full += targetFile;
  70. regWriter.Init(luid, full.c_str());
  71. }
  72. //
  73. // by default no registry mapping
  74. //
  75. SetRegistryMapper(NULL);
  76. }
  77. //
  78. // Destructor
  79. //
  80. File::~File()
  81. {
  82. // TBD : clean up the memory allocated
  83. }
  84. //
  85. // Add a section from an .inf file into the 'to do' list
  86. //
  87. // Arguments:
  88. // fileName - path and name of the .inf file
  89. // section - name of the section in the .inf to be added
  90. // action - What to do with the section - Add, Delete, Etc.. (see process sections for list)
  91. //
  92. void File::AddInfSection(
  93. IN PCTSTR fileName,
  94. IN PCTSTR section,
  95. IN PCTSTR action,
  96. IN bool Prepend
  97. )
  98. {
  99. hFile = SetupOpenInfFile(fileName, 0, INF_STYLE_WIN4, 0);
  100. if (hFile == INVALID_HANDLE_VALUE) {
  101. throw new W32Error();
  102. }
  103. if (Prepend) {
  104. handleList.push_front(hFile);
  105. infList.push_front(action);
  106. infList.push_front(section);
  107. } else {
  108. handleList.push_back(hFile);
  109. //
  110. // NOTE the order of addition
  111. //
  112. infList.push_back(section);
  113. infList.push_back(action);
  114. }
  115. }
  116. //
  117. // Sets the directory the target file will be stored in
  118. //
  119. // Arguments:
  120. // section - section in the .inf containing the directory
  121. // h - handle to the .inf file with the directory
  122. //
  123. DWORD File::SetDirectory(
  124. IN PCTSTR section,
  125. HINF h)
  126. {
  127. INFCONTEXT ic,ic2;
  128. if (!(SetupFindFirstLine(h, section, 0, &ic))) {
  129. throw new W32Error();
  130. }
  131. memcpy(&ic2, &ic, sizeof(ic));
  132. ic2.Line = 0;
  133. if (!(SetupGetStringField(&ic2, 1, targetDirectory, ELEMENT_COUNT(targetDirectory), 0))) {
  134. throw new W32Error();
  135. }
  136. int len = wcslen(targetDirectory);
  137. if (len && targetDirectory[len - 1] != L'\\') {
  138. targetDirectory[len] = L'\\';
  139. targetDirectory[len + 1] = UNICODE_NULL;
  140. }
  141. return ERROR_SUCCESS;
  142. }
  143. //
  144. // Save information from the registry to file and
  145. // delete the registry keys (happens in the regwriter deconstructor)
  146. //
  147. DWORD File::Cleanup() {
  148. FileList::iterator i;
  149. File::SaveAll();
  150. while(files.size()!=0) {
  151. i = files.begin();
  152. delete (*i);
  153. files.pop_front();
  154. }
  155. return ERROR_SUCCESS;
  156. }
  157. //
  158. // Load existing registry hive into the registry, then add new keys to it
  159. //
  160. // Arguments:
  161. // section - section containing the keys to be added
  162. // h - handle to the .inf containing section
  163. //
  164. DWORD File::AddRegExisting(
  165. IN PCTSTR lpszSection,
  166. HINF h)
  167. {
  168. INFCONTEXT ic,ic2;
  169. int fields,lines,curLine,curField;
  170. File* curFile;
  171. if (!(SetupFindFirstLine(h, lpszSection, 0, &ic))) {
  172. return ERROR_SUCCESS;
  173. }
  174. memcpy(&ic2,&ic,sizeof(ic));
  175. lines = SetupGetLineCount(h, lpszSection);
  176. if (lines != -1) {
  177. for (curLine=0;curLine<lines;curLine++) {
  178. ic2.Line = curLine;
  179. fields = SetupGetFieldCount(&ic2);
  180. if (fields == 0) {
  181. continue;
  182. }
  183. TCHAR *target = new TCHAR[1024];
  184. SetupGetStringField(&ic2, 0, target, 1024, 0);
  185. curFile = GetFile(target, true);
  186. for(curField=1; curField < fields; curField += 2) {
  187. TCHAR *section = new TCHAR[1024],*inf = new TCHAR[1024];
  188. SetupGetStringField(&ic2, curField, inf, 1024, 0);
  189. SetupGetStringField(&ic2, curField + 1, section, 1024, 0);
  190. curFile->AddInfSection(inf, section, L"AddReg");
  191. }
  192. if (curFile->ProcessSections()) {
  193. _putws(GetFormattedMessage( ThisModule,
  194. FALSE,
  195. Message,
  196. sizeof(Message)/sizeof(Message[0]),
  197. MSG_ERROR_IN_LINE,
  198. target) );
  199. }
  200. }
  201. }
  202. return ERROR_SUCCESS;
  203. }
  204. //
  205. // Load existing registry hive into the registry, then delete new keys from it
  206. //
  207. // Arguments:
  208. // section - section containing the keys to be deleted
  209. // h - handle to the .inf containing section
  210. //
  211. DWORD
  212. File::DelRegExisting(
  213. PCTSTR lpszSection,
  214. HINF h)
  215. {
  216. INFCONTEXT ic,ic2;
  217. int fields,lines,curLine,curField;
  218. File* curFile;
  219. if (!(SetupFindFirstLine(h,lpszSection,0,&ic))) {
  220. return ERROR_SUCCESS;
  221. }
  222. memcpy(&ic2, &ic, sizeof(ic));
  223. lines = SetupGetLineCount(h, lpszSection);
  224. if (lines!=-1) {
  225. for (curLine=0;curLine<lines;curLine++) {
  226. ic2.Line = curLine;
  227. fields = SetupGetFieldCount(&ic2);
  228. if (fields == 0) {
  229. continue;
  230. }
  231. TCHAR *target = new TCHAR[1024];
  232. SetupGetStringField(&ic2,0,target,1024,0);
  233. //
  234. // got the target file, now do it
  235. //
  236. curFile = GetFile(target,true);
  237. for(curField=1;curField<fields;curField+=2) {
  238. TCHAR *section = new TCHAR[1024],*inf = new TCHAR[1024];
  239. SetupGetStringField(&ic2,curField,inf,1024,0);
  240. SetupGetStringField(&ic2,curField+1,section,1024,0);
  241. curFile->AddInfSection(inf,section,L"DelReg");
  242. }
  243. if (curFile->ProcessSections()) {
  244. _putws( GetFormattedMessage(ThisModule,
  245. FALSE,
  246. Message,
  247. sizeof(Message)/sizeof(Message[0]),
  248. MSG_ERROR_IN_LINE,
  249. target) );
  250. }
  251. }
  252. }
  253. return 0;
  254. }
  255. //
  256. // Load information from a .inf file into the registry
  257. //
  258. // Arguments:
  259. // section - section containing the keys to be added
  260. // h - handle to the .inf containing section
  261. //
  262. DWORD File::AddRegNew(
  263. PCTSTR lpszSection,
  264. HINF h)
  265. {
  266. INFCONTEXT ic,ic2;
  267. int fields,lines,curLine,curField;
  268. File* curFile;
  269. if (!(SetupFindFirstLine(h, lpszSection, 0, &ic))) {
  270. return ERROR_SUCCESS;
  271. }
  272. memcpy(&ic2, &ic, sizeof(ic));
  273. lines = SetupGetLineCount(h,lpszSection);
  274. if (lines!=-1) {
  275. for (curLine=0;curLine<lines;curLine++) {
  276. ic2.Line = curLine;
  277. fields = SetupGetFieldCount(&ic2);
  278. if (fields==0) continue;
  279. TCHAR *target = new TCHAR[1024];
  280. SetupGetStringField(&ic2,0,target,1024,0);
  281. //
  282. // got the target file, now do it
  283. //
  284. curFile = GetFile(target,false);
  285. for(curField=1;curField<fields;curField+=2) {
  286. TCHAR *section = new TCHAR[1024],*inf = new TCHAR[1024];
  287. SetupGetStringField(&ic2, curField, inf, 1024, 0);
  288. SetupGetStringField(&ic2, curField + 1, section, 1024, 0);
  289. curFile->AddInfSection(inf,section,L"AddReg");
  290. }
  291. if (curFile->ProcessSections()) {
  292. _putws( GetFormattedMessage(ThisModule,
  293. FALSE,
  294. Message,
  295. sizeof(Message)/sizeof(Message[0]),
  296. MSG_ERROR_IN_PROCESS_SECTIONS) );
  297. }
  298. }
  299. }
  300. return ERROR_SUCCESS;
  301. }
  302. //
  303. // Adds an .inf section (probably [AddReg]) to the registry
  304. //
  305. // Arguments:
  306. // pszSection - section containing the keys to be added
  307. // hInfFile - handle to the .inf containing section
  308. //
  309. DWORD
  310. File::AddSection(
  311. PCTSTR pszSection,
  312. HINF hInfFile
  313. )
  314. {
  315. INFCONTEXT ic,ic2;
  316. int nRet = 0;
  317. long nLines,curLine;
  318. TCHAR Buffer[1024],Root[1024],Subkey[1024],Value[1024],SubkeyFinal[1024];
  319. DWORD flags = 0,dwCount;
  320. BYTE* b;TCHAR* t;DWORD d,f;
  321. int bSize = 0;
  322. // cout << "AddSection : " << pszSection << endl;
  323. nLines = SetupGetLineCount(hInfFile,pszSection);
  324. if (!nLines) {
  325. //
  326. // there are no lines in the section
  327. //
  328. _putws( GetFormattedMessage(ThisModule,
  329. FALSE,
  330. Message,
  331. sizeof(Message)/sizeof(Message[0]),
  332. MSG_EMPTY_ADDREG_SECTION,
  333. pszSection) );
  334. return ERROR_SUCCESS;
  335. }
  336. if (!(SetupFindFirstLine(hInfFile,pszSection,0,&ic))) {
  337. _putws( GetFormattedMessage(ThisModule,
  338. FALSE,
  339. Message,
  340. sizeof(Message)/sizeof(Message[0]),
  341. MSG_FIND_FIRST_LINE_FAILED,
  342. pszSection,
  343. Error()) );
  344. throw errGENERAL_ERROR;
  345. }
  346. memcpy(&ic2, &ic, sizeof(ic));
  347. //
  348. // get all the parameters, key, value, type, flags
  349. //
  350. for (curLine=0;curLine<nLines;curLine++) {
  351. bool IsSystemHive = false;
  352. ic2.Line = curLine;
  353. dwCount = SetupGetFieldCount(&ic2);
  354. b = 0;
  355. t = 0;
  356. d = f = 0;
  357. bSize = 0;
  358. if (dwCount > 3) {
  359. if (!(SetupGetStringField(&ic2, 4, Buffer, ELEMENT_COUNT(Buffer), 0))) {
  360. _putws( GetFormattedMessage( ThisModule,
  361. FALSE,
  362. Message,
  363. sizeof(Message)/sizeof(Message[0]),
  364. MSG_SETUPGETSTRINGFIELD_FAILED,
  365. pszSection,
  366. Error()) );
  367. throw errGENERAL_ERROR;
  368. }
  369. if ((flags = GetFlags(Buffer)) == errBAD_FLAGS) {
  370. if (!(SetupGetStringField(&ic2, 2, Subkey, ELEMENT_COUNT(Subkey), 0))) {
  371. _putws( GetFormattedMessage(ThisModule,
  372. FALSE,
  373. Message,
  374. sizeof(Message)/sizeof(Message[0]),
  375. MSG_SETUPGETSTRINGFIELD_FAILED,
  376. pszSection,
  377. Error()) );
  378. throw errGENERAL_ERROR;
  379. }
  380. _putws( GetFormattedMessage(ThisModule,
  381. FALSE,
  382. Message,
  383. sizeof(Message)/sizeof(Message[0]),
  384. MSG_BAD_REG_FLAGS,
  385. pszSection,
  386. Subkey) );
  387. throw errBAD_FLAGS;
  388. }
  389. if (flags == FLG_ADDREG_KEYONLY) {
  390. dwCount = 2;
  391. }
  392. if (dwCount > 4) {
  393. if (!(flags ^ REG_BINARY)) {
  394. SetupGetBinaryField(&ic2,5,0,0,&f);
  395. b = new BYTE[f];
  396. bSize = f;
  397. SetupGetBinaryField(&ic2,5,b,f,0);
  398. f = 1;
  399. } else if (!(flags ^ REG_DWORD)) {
  400. SetupGetIntField(&ic2,5,(int*)&d);
  401. f = 2;
  402. } else if (flags ^ FLG_ADDREG_KEYONLY) {
  403. DWORD length;
  404. SetupGetStringField(&ic2,5,0,0,&length);
  405. t = new TCHAR[2048];
  406. SetupGetStringField(&ic2,5,t,length,0);
  407. if (flags==REG_MULTI_SZ) {
  408. for (int field = 6;field<=dwCount;field++) {
  409. t[length-1] = '\0';
  410. SetupGetStringField(&ic2,field,0,0,&f);
  411. SetupGetStringField(&ic2,field,t+length,f,&f);
  412. length += f;
  413. }
  414. t[length-1] = '\0';
  415. t[length] = '\0';
  416. f = 4;
  417. } else {
  418. f = 3;
  419. }
  420. }
  421. }
  422. }
  423. if (dwCount > 2) {
  424. if (!(SetupGetStringField(&ic2, 3, Value, ELEMENT_COUNT(Value), 0))) {
  425. _putws(GetFormattedMessage( ThisModule,
  426. FALSE,
  427. Message,
  428. sizeof(Message)/sizeof(Message[0]),
  429. MSG_SETUPGETSTRINGFIELD_FAILED,
  430. pszSection,
  431. Error()) );
  432. throw errGENERAL_ERROR;
  433. }
  434. }
  435. if (dwCount > 1) {
  436. if (!(SetupGetStringField(&ic2, 2, Subkey, ELEMENT_COUNT(Subkey), 0))) {
  437. _putws(GetFormattedMessage( ThisModule,
  438. FALSE,
  439. Message,
  440. sizeof(Message)/sizeof(Message[0]),
  441. MSG_SETUPGETSTRINGFIELD_FAILED,
  442. pszSection,
  443. Error()) );
  444. throw errGENERAL_ERROR;
  445. }
  446. }
  447. RegWriter *CurrRegWriter = &regWriter;
  448. if (dwCount > 0) {
  449. if (!(SetupGetStringField(&ic2, 1, Root, ELEMENT_COUNT(Root), 0))) {
  450. _putws(GetFormattedMessage( ThisModule,
  451. FALSE,
  452. Message,
  453. sizeof(Message)/sizeof(Message[0]),
  454. MSG_SETUPGETSTRINGFIELD_FAILED,
  455. pszSection,
  456. Error()) );
  457. throw errGENERAL_ERROR;
  458. }
  459. std::wstring RegFileSubKey = Subkey;
  460. //
  461. // Map the registry if needed
  462. //
  463. RegistryMapper *RegMapper = GetRegistryMapper();
  464. if (RegMapper && RegFileSubKey.length()) {
  465. std::wstring::size_type SlashPos = RegFileSubKey.find(L'\\');
  466. if (SlashPos != RegFileSubKey.npos) {
  467. std::wstring KeyName = Root;
  468. KeyName += TEXT("\\") + RegFileSubKey.substr(0, SlashPos);
  469. _wcslwr((PWSTR)KeyName.c_str());
  470. std::wstring RegistryName;
  471. //
  472. // get the file that this registry entry is mapped to
  473. // and get its regwriter to flush the current registry
  474. // entry
  475. //
  476. if (RegMapper->GetMappedRegistry(KeyName, RegistryName)) {
  477. File *CurrFile = GetFile(RegistryName.c_str(), true);
  478. if (CurrFile) {
  479. //std::cout << "Mapping to " << RegistryName << std::endl;
  480. CurrRegWriter = &(CurrFile->GetRegWriter());
  481. }
  482. }
  483. }
  484. }
  485. //
  486. // Adjust Subkey if necessary:
  487. // HKCR is a link to Software\Classes.
  488. // Anything stored in Software or System shouldn't have SOFTWARE or SYSTEM
  489. // as part of the subkey.
  490. //
  491. if (!wcscmp(Root, L"HKCR")) {
  492. TCHAR temp[1024];
  493. wcscpy(temp, L"Classes\\");
  494. wcscat(temp, Subkey);
  495. wcscpy(Subkey, temp);
  496. }
  497. if (!wcscmp(Root, L"HKLM")) {
  498. TCHAR temp[1024];
  499. if (Subkey[8] == '\\') {
  500. wcscpy(temp, Subkey);
  501. temp[8] = '\0';
  502. if (!_wcsicmp(temp, L"SOFTWARE")) {
  503. wcscpy(Subkey, temp+9);
  504. }
  505. } else if (Subkey[6]=='\\') {
  506. wcscpy(temp, Subkey);
  507. temp[6] = '\0';
  508. if (!_wcsicmp(temp, L"SYSTEM")) {
  509. wcscpy(Subkey, temp+7);
  510. IsSystemHive = true;
  511. }
  512. }
  513. }
  514. }
  515. wcscpy(SubkeyFinal, wKey);
  516. wcscat(SubkeyFinal, Subkey);
  517. //
  518. // Do we need to map CCS to CCS01 ?
  519. //
  520. // NOTE : Might want to extend this to generically map
  521. // any subkey.
  522. //
  523. if (IsSystemHive) {
  524. std::wstring CCSKey = SubkeyFinal;
  525. _wcslwr((PWSTR)CCSKey.c_str());
  526. PWSTR CurrentControlSet = wcsstr((PWSTR)CCSKey.c_str(),
  527. (PWSTR)CCS_SOURCE_KEY.c_str());
  528. if (CurrentControlSet) {
  529. PWSTR RemainingPart = CurrentControlSet + CCS_SOURCE_KEY.length();
  530. size_t CharsToSkip = CurrentControlSet - CCSKey.c_str();
  531. wcscpy(SubkeyFinal + CharsToSkip, (PWSTR)CCS_TARGET_KEY.c_str());
  532. wcscat(SubkeyFinal, RemainingPart);
  533. //std::cout << SubkeyFinal << std::endl;
  534. }
  535. }
  536. //
  537. // if there's a value
  538. //
  539. if (dwCount > 2) {
  540. CurrRegWriter->Write(Root, SubkeyFinal, Value, flags, new Data(b,d,t,f,bSize));
  541. } else {
  542. CurrRegWriter->Write(Root,SubkeyFinal, 0, 0, 0);
  543. }
  544. }
  545. return ERROR_SUCCESS;
  546. }
  547. DWORD
  548. File::DelSection(
  549. PCTSTR pszSection,
  550. HINF hInfFile
  551. )
  552. {
  553. INFCONTEXT ic,ic2;
  554. long nLines,curLine;
  555. TCHAR Buffer[1024],Root[1024],Subkey[1024],Value[1024],SubkeyFinal[1024];
  556. DWORD LastError = ERROR_SUCCESS, Result;
  557. //
  558. // get the section's first line context
  559. //
  560. if (!(SetupFindFirstLine(hInfFile,pszSection,0,&ic))) {
  561. _putws( GetFormattedMessage(ThisModule,
  562. FALSE,
  563. Message,
  564. sizeof(Message)/sizeof(Message[0]),
  565. MSG_FIND_FIRST_LINE_FAILED,
  566. pszSection,
  567. Error()) );
  568. throw errGENERAL_ERROR;
  569. }
  570. //
  571. // replicate the context
  572. //
  573. memcpy(&ic2, &ic, sizeof(ic));
  574. //
  575. // How many lines are there in the section which we need to process ?
  576. //
  577. if (!(nLines = SetupGetLineCount(hInfFile,pszSection))) {
  578. _putws(GetFormattedMessage( ThisModule,
  579. FALSE,
  580. Message,
  581. sizeof(Message)/sizeof(Message[0]),
  582. MSG_SETUPGETLINECOUNT_ERROR,
  583. pszSection,
  584. Error()) );
  585. throw errGENERAL_ERROR;
  586. }
  587. //
  588. // get all the parameters key & value
  589. //
  590. for (curLine=0;curLine<nLines;curLine++) {
  591. DWORD dwCount;
  592. ic2.Line = curLine;
  593. dwCount = SetupGetFieldCount(&ic2);
  594. Value[0] = NULL;
  595. //
  596. // if value field is present then get it
  597. //
  598. if (dwCount > 2) {
  599. if (!(SetupGetStringField(&ic2, 3, Value, ELEMENT_COUNT(Value), 0))) {
  600. _putws( GetFormattedMessage(ThisModule,
  601. FALSE,
  602. Message,
  603. sizeof(Message)/sizeof(Message[0]),
  604. MSG_SETUPGETSTRINGFIELD_FAILED,
  605. pszSection,
  606. Error()) );
  607. throw errGENERAL_ERROR;
  608. }
  609. }
  610. //
  611. // if key is present then get it
  612. //
  613. if (dwCount > 1) {
  614. if (!(SetupGetStringField(&ic2, 2, Subkey, ELEMENT_COUNT(Subkey), 0))) {
  615. _putws( GetFormattedMessage(ThisModule,
  616. FALSE,
  617. Message,
  618. sizeof(Message)/sizeof(Message[0]),
  619. MSG_SETUPGETSTRINGFIELD_FAILED,
  620. pszSection,
  621. Error()) );
  622. throw errGENERAL_ERROR;
  623. }
  624. //
  625. // get the root key
  626. //
  627. if (!(SetupGetStringField(&ic2, 1, Root, ELEMENT_COUNT(Root), 0))) {
  628. _putws( GetFormattedMessage(ThisModule,
  629. FALSE,
  630. Message,
  631. sizeof(Message)/sizeof(Message[0]),
  632. MSG_SETUPGETSTRINGFIELD_FAILED,
  633. pszSection,
  634. Error()) );
  635. throw errGENERAL_ERROR;
  636. }
  637. //
  638. // Adjust Subkey if necessary:
  639. // HKCR is a link to Software\Classes.
  640. // Anything stored in Software or System shouldn't have SOFTWARE or SYSTEM
  641. // as part of the subkey.
  642. //
  643. if (!wcscmp(Root, L"HKCR")) {
  644. TCHAR temp[1024];
  645. wcscpy(temp, L"Classes\\");
  646. wcscat(temp, Subkey);
  647. wcscpy(Subkey, temp);
  648. }
  649. if (!wcscmp(Root, L"HKLM")) {
  650. TCHAR temp[1024];
  651. if (Subkey[8] == '\\') {
  652. wcscpy(temp, Subkey);
  653. temp[8] = '\0';
  654. if (!_wcsicmp(temp, L"SOFTWARE")) {
  655. wcscpy(Subkey, temp+9);
  656. }
  657. } else if (Subkey[6]=='\\') {
  658. wcscpy(temp, Subkey);
  659. temp[6] = '\0';
  660. if (!_wcsicmp(temp, L"SYSTEM")) {
  661. wcscpy(Subkey, temp+7);
  662. }
  663. }
  664. }
  665. wcscpy(SubkeyFinal, wKey);
  666. wcscat(SubkeyFinal, Subkey);
  667. //
  668. // delete the entry
  669. //
  670. Result = regWriter.Delete(Root, SubkeyFinal, (Value[0] ? Value : NULL));
  671. if (ERROR_SUCCESS != Result) {
  672. LastError = Result;
  673. }
  674. }
  675. }
  676. return LastError;
  677. }
  678. //
  679. // Save the keys to files
  680. //
  681. DWORD File::SaveAll() {
  682. DWORD dwRet;
  683. FileList::iterator i = files.begin();
  684. TCHAR fullPath[1024];
  685. for (i = files.begin(); i!=files.end(); i++) {
  686. wcscpy(fullPath, targetDirectory);
  687. wcscat(fullPath, (*i)->targetFile.c_str());
  688. DeleteFile(fullPath);
  689. _putws( GetFormattedMessage(ThisModule,
  690. FALSE,
  691. Message,
  692. sizeof(Message)/sizeof(Message[0]),
  693. MSG_SAVING_KEYS,
  694. fullPath) );
  695. if (dwRet = (*i)->regWriter.Save((*i)->wKey,fullPath)) {
  696. throw dwRet;
  697. }
  698. }
  699. return ERROR_SUCCESS;
  700. }
  701. //
  702. // Process the 'to do' list for this file
  703. // This function goes through all the sections that have been
  704. // added to this file and calls the appropriate function to
  705. // deal with each one
  706. //
  707. DWORD File::ProcessSections() {
  708. DWORD dwRet = 0;
  709. StringList::iterator sSection,sAction;
  710. HandleList::iterator h = handleList.begin();
  711. StringList::iterator PrevSectionIter;
  712. HandleList::iterator PrevHandleIter;
  713. StringList::iterator PrevActionIter;
  714. sSection = sAction = infList.begin();
  715. sAction++;
  716. for (sSection = infList.begin();sSection!=infList.end();) {
  717. bool SectionProcessed = true;
  718. if (!(wcscmp(L"AddReg", *sAction))) {
  719. if (dwRet = AddSection(*sSection, *h)) {
  720. throw dwRet;
  721. }
  722. } else if (!(wcscmp(L"DelReg", *sAction))) {
  723. if (dwRet = DelSection(*sSection, *h)) {
  724. throw dwRet;
  725. }
  726. } else if (!(wcscmp(L"AddRegNew", *sAction))) {
  727. if (dwRet = AddRegNew(*sSection, *h)) {
  728. throw dwRet;
  729. }
  730. } else if (!(wcscmp(L"AddRegExisting", *sAction))) {
  731. if (dwRet = AddRegExisting(*sSection, *h)) {
  732. throw dwRet;
  733. }
  734. } else if (!(wcscmp(L"DelRegExisting", *sAction))) {
  735. if (dwRet = DelRegExisting(*sSection, *h)) {
  736. throw dwRet;
  737. }
  738. } else if (!(wcscmp(L"SetDirectory", *sAction))) {
  739. if (dwRet = SetDirectory(*sSection, *h)) {
  740. throw dwRet;
  741. }
  742. } else {
  743. SectionProcessed = false;
  744. }
  745. //
  746. // remember current element so that we can delete it
  747. //
  748. if (SectionProcessed) {
  749. PrevSectionIter = sSection;
  750. PrevHandleIter = h;
  751. PrevActionIter = sAction;
  752. }
  753. //
  754. // get hold of the next entry to process
  755. //
  756. sSection++;
  757. sSection++;
  758. sAction++;
  759. sAction++;
  760. h++;
  761. //
  762. // remove processed elements
  763. //
  764. if (SectionProcessed) {
  765. infList.erase(PrevSectionIter);
  766. infList.erase(PrevActionIter);
  767. handleList.erase(PrevHandleIter);
  768. }
  769. }
  770. return ERROR_SUCCESS;
  771. }
  772. DWORD
  773. File::GetFlags(
  774. PCTSTR FlagStr
  775. )
  776. /*++
  777. Routine Description:
  778. Converts the given string representation of flags into proper
  779. registery DWORD format
  780. Arguments:
  781. FlagStr : The flag represented in string format..
  782. Return Value:
  783. Appropriate registry DWORD type if successful, otherwise REG_NONE
  784. --*/
  785. {
  786. DWORD Flags = REG_NONE;
  787. if (FlagStr) {
  788. //
  789. // Check if the type if specified through string
  790. //
  791. if (!wcscmp(FlagStr, TEXT("REG_EXPAND_SZ"))) {
  792. Flags = REG_EXPAND_SZ;
  793. } else if (!wcscmp(FlagStr, TEXT("REG_DWORD"))) {
  794. Flags = REG_DWORD;
  795. } else if (!wcscmp(FlagStr, TEXT("REG_BINARY"))) {
  796. Flags = REG_BINARY;
  797. } else if (!wcscmp(FlagStr, TEXT("REG_MULTI_SZ"))) {
  798. Flags = REG_MULTI_SZ;
  799. } else if (!wcscmp(FlagStr, TEXT("REG_SZ"))) {
  800. Flags = REG_SZ;
  801. } else if (!wcscmp(FlagStr, TEXT(""))) {
  802. Flags = REG_SZ;
  803. }
  804. //
  805. // if still the flags were not found then convert the flags
  806. // into a DWORD and then interpret it
  807. //
  808. if (Flags == REG_NONE) {
  809. PTSTR EndChar = NULL;
  810. DWORD FlagsValue = _tcstoul(FlagStr, &EndChar, 0);
  811. if (!errno) {
  812. if ((FlagsValue & FLG_ADDREG_KEYONLY) == FLG_ADDREG_KEYONLY) {
  813. Flags = FLG_ADDREG_KEYONLY;
  814. } else if (HIWORD(FlagsValue) == REG_BINARY) {
  815. Flags = REG_BINARY;
  816. } else if ((FlagsValue & FLG_ADDREG_TYPE_EXPAND_SZ) == FLG_ADDREG_TYPE_EXPAND_SZ) {
  817. Flags = REG_EXPAND_SZ;
  818. } else if ((FlagsValue & FLG_ADDREG_TYPE_DWORD) == FLG_ADDREG_TYPE_DWORD) {
  819. Flags = REG_DWORD;
  820. } else if ((FlagsValue & FLG_ADDREG_TYPE_BINARY) == FLG_ADDREG_TYPE_BINARY) {
  821. Flags = REG_BINARY;
  822. } else if ((FlagsValue & FLG_ADDREG_TYPE_MULTI_SZ) == FLG_ADDREG_TYPE_MULTI_SZ) {
  823. Flags = REG_MULTI_SZ;
  824. } else if ((FlagsValue & FLG_ADDREG_TYPE_SZ) == FLG_ADDREG_TYPE_SZ) {
  825. Flags = REG_SZ;
  826. }
  827. }
  828. }
  829. }
  830. return Flags;
  831. }
  832. //
  833. // Either get pointer to existing file object or create new one
  834. //
  835. // Arguments:
  836. // fileName - name (w/o path) of target file
  837. // modify - T - load and modify an existing hive. F - Create new hive
  838. //
  839. File* File::GetFile(
  840. PCTSTR fileName,
  841. bool modify)
  842. {
  843. FileList::iterator i;
  844. for (i = files.begin(); i!=files.end(); i++) {
  845. if (!(wcscmp(fileName, (*i)->GetTarget()))) {
  846. return *i;
  847. }
  848. }
  849. files.insert(files.begin(), new File(fileName, modify));
  850. return (*(files.begin()));
  851. }
  852. void
  853. File::ProcessNlsRegistryEntriesForSection(
  854. IN InfFileW &ConfigInf,
  855. IN InfFileW &IntlInf,
  856. IN InfFileW &FontInf,
  857. IN const std::wstring &SectionName
  858. )
  859. /*++
  860. Routine Description:
  861. Given the configuration inf, intl.inf & font.inf files
  862. processes the given section name entries for registry
  863. changes.
  864. Arguments:
  865. ConfigInf - reference to config.inf InfFile object
  866. IntlInf - reference to intl.inf InfFile object
  867. FontInf - reference to font.inf InfFile object
  868. SectionName - name of the section to process
  869. Return Value:
  870. None, throws appropriate exception.
  871. --*/
  872. {
  873. //std::cout << "Processing : " << SectionName << std::endl;
  874. //
  875. // iterate through all the addreg sections calling
  876. // AddSection(...)
  877. //
  878. std::wstring LangSectionName = SectionName;
  879. _wcslwr((PWSTR)LangSectionName.c_str());
  880. //
  881. // Is the section present in intl.inf ?
  882. //
  883. Section<WCHAR> *LangSection = IntlInf.GetSection(LangSectionName);
  884. bool InFontInf = false;
  885. if (!LangSection) {
  886. //
  887. // Is the section present in font.inf ?
  888. //
  889. LangSection = FontInf.GetSection(LangSectionName);
  890. InFontInf = true;
  891. }
  892. if (!LangSection) {
  893. throw new InvalidInfSection<WCHAR>(LangSectionName,
  894. IntlInf.GetName());
  895. }
  896. Section<WCHAR>::Iterator Iter = LangSection->begin();
  897. SectionValues<WCHAR> *CurrValue;
  898. Section<WCHAR> *AddRegSection = NULL;
  899. //
  900. // go through each addreg section entry in the multivalue list
  901. // and process each section.
  902. //
  903. while (!Iter.end()) {
  904. CurrValue = *Iter;
  905. if (CurrValue) {
  906. //std::cout << CurrValue->GetName() << std::endl;
  907. if (_wcsicmp(CurrValue->GetName().c_str(),
  908. ADDREG_KEY.c_str()) == 0) {
  909. DWORD ValueCount = CurrValue->Count();
  910. for (DWORD Index = 0; Index < ValueCount; Index++) {
  911. std::wstring Value = CurrValue->GetValue(Index);
  912. HINF InfHandle = NULL;
  913. _wcslwr((PWSTR)Value.c_str());
  914. if (!InFontInf) {
  915. InfHandle = (HINF)IntlInf.GetInfHandle();
  916. AddRegSection = IntlInf.GetSection(Value);
  917. }
  918. if (!AddRegSection || InFontInf) {
  919. InfHandle = (HINF)FontInf.GetInfHandle();
  920. AddRegSection = FontInf.GetSection(Value);
  921. }
  922. if (!AddRegSection || (InfHandle == NULL)) {
  923. throw new InvalidInfSection<WCHAR>(Value,
  924. IntlInf.GetName());
  925. }
  926. //
  927. // process the AddReg section entries
  928. //
  929. // std::cout << "Processing AddReg : " << Value << std::endl;
  930. DWORD Result = AddSection(Value.c_str(),
  931. InfHandle);
  932. if (ERROR_SUCCESS != Result) {
  933. throw new W32Error(Result);
  934. }
  935. }
  936. }
  937. }
  938. Iter++;
  939. }
  940. }
  941. void
  942. File::ProcessNlsRegistryEntriesForLanguage(
  943. IN InfFileW &ConfigInf,
  944. IN InfFileW &IntlInf,
  945. IN InfFileW &FontInf,
  946. IN const std::wstring &Language
  947. )
  948. /*++
  949. Routine Description:
  950. Processes the registry sections for the given Language (locale Id)
  951. Arguments:
  952. ConfigInf - reference to config.inf InfFile object
  953. IntlInf - reference to intl.inf InfFile object
  954. FontInf - reference to font.inf InfFile object
  955. Language - locale ID of the language to process (e.g 0x411 for JPN)
  956. Return Value:
  957. None, throws appropriate exception.
  958. --*/
  959. {
  960. //
  961. // get the language section
  962. //
  963. WCHAR LanguageIdStr[64];
  964. PWSTR EndPtr;
  965. DWORD LanguageId;
  966. LanguageId = wcstoul(Language.c_str(), &EndPtr, 16);
  967. swprintf(LanguageIdStr, L"%08x", LanguageId);
  968. _wcslwr(LanguageIdStr);
  969. std::wstring LangSectionName = LanguageIdStr;
  970. ProcessNlsRegistryEntriesForSection(ConfigInf,
  971. IntlInf,
  972. FontInf,
  973. LangSectionName);
  974. }
  975. void
  976. File::ProcessNlsRegistryEntriesForLangGroup(
  977. IN InfFileW &ConfigInf,
  978. IN InfFileW &IntlInf,
  979. IN InfFileW &FontInf,
  980. IN const std::wstring &LangGroupIndex
  981. )
  982. /*++
  983. /*++
  984. Routine Description:
  985. Processes the registry sections for the given Language group
  986. Arguments:
  987. ConfigInf - reference to config.inf InfFile object
  988. IntlInf - reference to intl.inf InfFile object
  989. FontInf - reference to font.inf InfFile object
  990. LangGroupIndex - language group index (like 1, 7, 9 etc)
  991. Return Value:
  992. None, throws appropriate exception.
  993. --*/
  994. {
  995. //
  996. // get the language group section
  997. //
  998. std::wstring LangGroupName = LANGGROUP_SECTION_PREFIX + LangGroupIndex;
  999. //
  1000. // iterate through all the addreg sections calling
  1001. // AddSection(...)
  1002. //
  1003. _wcslwr((PWSTR)LangGroupName.c_str());
  1004. ProcessNlsRegistryEntriesForSection(ConfigInf,
  1005. IntlInf,
  1006. FontInf,
  1007. LangGroupName);
  1008. }
  1009. void
  1010. File::ProcessNlsRegistryEntries(
  1011. void
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. Top level method which munges intl.inf, font.inf and
  1016. config.inf to do the required registry modifications
  1017. to install a language.
  1018. config.inf's regionalsettings section controls the
  1019. behavior of this function for e.g.
  1020. [regionalsettings]
  1021. languagegroup=9
  1022. language=0x411
  1023. will do the necessary registry processing for language
  1024. group 9 and language group 7 (since 0x411 belongs to
  1025. language group 7). After processing the language
  1026. groups it sets the registry to make the requested
  1027. lanaguage active (0x411 in this case). Also processes
  1028. the font.inf for appropriate language group & language
  1029. font entries.
  1030. Arguments:
  1031. None.
  1032. Return Value:
  1033. None, throws appropriate exception.
  1034. --*/
  1035. {
  1036. DWORD Result = ERROR_CAN_NOT_COMPLETE;
  1037. try {
  1038. std::wstring IntlInfName = TEXT(".\\") + INTL_INF_FILENAME;
  1039. std::wstring FontInfName = TEXT(".\\") + FONT_INF_FILENAME;
  1040. //
  1041. // open the required inf files
  1042. //
  1043. InfFileW ConfigInf(targetFile);
  1044. InfFileW IntlInf(IntlInfName);
  1045. InfFileW FontInf(FontInfName);
  1046. //
  1047. // get hold of [regionalsettings] section
  1048. //
  1049. Section<WCHAR> *RegionalSection = ConfigInf.GetSection(REGIONAL_SECTION_NAME);
  1050. if (!RegionalSection) {
  1051. throw new InvalidInfSection<WCHAR>(REGIONAL_SECTION_NAME,
  1052. targetFile);
  1053. }
  1054. //
  1055. // get hold of the [registrymapper] section
  1056. //
  1057. Section<WCHAR> *RegMapperSection = ConfigInf.GetSection(REGMAPPER_SECTION_NAME);
  1058. if (!RegMapperSection) {
  1059. throw new InvalidInfSection<WCHAR>(REGMAPPER_SECTION_NAME,
  1060. targetFile);
  1061. }
  1062. //
  1063. // if [languagegroup] section is present the get hold of it also
  1064. //
  1065. SectionValues<WCHAR> *LangGroups;
  1066. try {
  1067. LangGroups = &(RegionalSection->GetValue(LANGUAGE_GROUP_KEY));
  1068. } catch (...) {
  1069. LangGroups = NULL;
  1070. }
  1071. //
  1072. // get hold of the active languauge
  1073. //
  1074. SectionValues<WCHAR> &Language = RegionalSection->GetValue(LANGUAGE_KEY);
  1075. ULONG LangGroupCount = LangGroups ? LangGroups->Count() : 0;
  1076. RegistryMapper RegMapper;
  1077. RegistryMapper *OldMapper;
  1078. //
  1079. // initialize the registry mapper map table
  1080. //
  1081. RegMapper.AddSection(*RegMapperSection);
  1082. //std::cout << RegMapper;
  1083. //
  1084. // make our registry mapper active
  1085. //
  1086. OldMapper = SetRegistryMapper(&RegMapper);
  1087. std::map< std::wstring, std::wstring > RegSectionsToProcess;
  1088. //
  1089. // process each language group specified
  1090. //
  1091. for (ULONG Index = 0; Index < LangGroupCount; Index++) {
  1092. //
  1093. // get the language group section
  1094. //
  1095. std::wstring LangGroupName = LANGGROUP_SECTION_PREFIX;
  1096. LangGroupName += LangGroups->GetValue(Index);
  1097. // std::cout << LangGroupName << std::endl;
  1098. _wcslwr((PWSTR)LangGroupName.c_str());
  1099. //
  1100. // if the section is not present then add it
  1101. //
  1102. if (RegSectionsToProcess.find(LangGroupName) == RegSectionsToProcess.end()) {
  1103. // std::cout << "Adding : " << LangGroupName << std::endl;
  1104. RegSectionsToProcess[LangGroupName] = LangGroupName;
  1105. }
  1106. }
  1107. //
  1108. // get the language section
  1109. //
  1110. WCHAR LanguageIdStr[64];
  1111. PWSTR EndPtr;
  1112. DWORD LanguageId;
  1113. LanguageId = wcstoul(Language.GetValue(0).c_str(), &EndPtr, 16);
  1114. swprintf(LanguageIdStr, L"%08x", LanguageId);
  1115. _wcslwr(LanguageIdStr);
  1116. std::wstring LangSectionName = LanguageIdStr;
  1117. RegSectionsToProcess[LangSectionName] = LangSectionName;
  1118. //
  1119. // make sure the required language groups for this
  1120. // language are also processed
  1121. //
  1122. Section<WCHAR> *LocaleSection = IntlInf.GetSection(LOCALES_SECTION_NAME);
  1123. if (!LocaleSection) {
  1124. throw new InvalidInfSection<WCHAR>(LOCALES_SECTION_NAME,
  1125. IntlInf.GetName());
  1126. }
  1127. SectionValues<WCHAR> &LocaleValues = LocaleSection->GetValue(LangSectionName);
  1128. std::wstring NeededLangGroup = LANGGROUP_SECTION_PREFIX + LocaleValues.GetValue(LANG_GROUP1_INDEX);
  1129. RegSectionsToProcess[NeededLangGroup] = NeededLangGroup;
  1130. //
  1131. // add the font registry entries also
  1132. //
  1133. WCHAR FontSectionName[MAX_PATH];
  1134. swprintf(FontSectionName,
  1135. FONT_CP_REGSECTION_FMT_STR.c_str(),
  1136. LocaleValues.GetValue(OEM_CP_INDEX).c_str(),
  1137. DEFAULT_FONT_SIZE);
  1138. RegSectionsToProcess[FontSectionName] = FontSectionName;
  1139. //
  1140. // we always process lg_install_1 language group section
  1141. //
  1142. std::map< std::wstring, std::wstring >::iterator Iter = RegSectionsToProcess.find(DEFAULT_LANGGROUP_NAME);
  1143. if (Iter == RegSectionsToProcess.end()) {
  1144. RegSectionsToProcess[DEFAULT_LANGGROUP_NAME] = DEFAULT_LANGGROUP_NAME;
  1145. }
  1146. //
  1147. // process each language group
  1148. //
  1149. Iter = RegSectionsToProcess.begin();
  1150. while (Iter != RegSectionsToProcess.end()) {
  1151. ProcessNlsRegistryEntriesForSection(ConfigInf,
  1152. IntlInf,
  1153. FontInf,
  1154. (*Iter).first);
  1155. Iter++;
  1156. }
  1157. //
  1158. // reset the old registry mapper
  1159. //
  1160. SetRegistryMapper(OldMapper);
  1161. Result = ERROR_SUCCESS;
  1162. }
  1163. catch (W32Exception<WCHAR> *Exp) {
  1164. if (Exp) {
  1165. Result = Exp->GetErrorCode();
  1166. Exp->Dump(std::cout);
  1167. delete Exp;
  1168. }
  1169. }
  1170. catch (BaseException<WCHAR> *BaseExp) {
  1171. if (BaseExp) {
  1172. BaseExp->Dump(std::cout);
  1173. delete BaseExp;
  1174. }
  1175. }
  1176. catch(...) {
  1177. }
  1178. if (ERROR_SUCCESS != Result) {
  1179. throw new W32Error(Result);
  1180. }
  1181. }
  1182. //
  1183. // RegistryMapper abstraction implementation
  1184. //
  1185. std::ostream&
  1186. operator<<(
  1187. std::ostream &os,
  1188. RegistryMapper &rhs
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. Helper method to dump registry mapper instance state
  1193. Arguments:
  1194. os - reference to ostream instance
  1195. rhs - reference to registry mapper whose state needs to be dumped
  1196. Return Value:
  1197. ostream reference for insertion of other outputs.
  1198. --*/
  1199. {
  1200. std::map< std::wstring, std::wstring >::iterator Iter = rhs.KeyToRegistryMap.begin();
  1201. while (Iter != rhs.KeyToRegistryMap.end()) {
  1202. os << (*Iter).first << "=>" << (*Iter).second << std::endl;
  1203. Iter++;
  1204. }
  1205. return os;
  1206. }
  1207. void
  1208. RegistryMapper::AddWorker(
  1209. SectionValues<WCHAR> &Values,
  1210. PVOID ContextData
  1211. )
  1212. /*++
  1213. Routine Description:
  1214. The worker routine which processes the section entries
  1215. and adds them to the map table.
  1216. Arguments:
  1217. Values - The section value entries which need to be processed
  1218. ContextData - receives RegistryMapper instance pointer in disguise.
  1219. Return Value:
  1220. None.
  1221. --*/
  1222. {
  1223. RegistryMapper *RegMap = (RegistryMapper *)ContextData;
  1224. std::wstring Key = Values.GetName();
  1225. std::wstring Value = Values.GetValue(0);
  1226. _wcslwr((PWSTR)Key.c_str());
  1227. RegMap->AddEntry(Key, Value);
  1228. }
  1229. void
  1230. RegistryMapper::AddSection(
  1231. Section<WCHAR> &MapSection
  1232. )
  1233. /*++
  1234. Routine Description:
  1235. Adds the given section entries to the internal map data structure
  1236. Arguments:
  1237. MapSection - reference to Section object that needs to be processed
  1238. Return Value:
  1239. None.
  1240. --*/
  1241. {
  1242. MapSection.DoForEach(RegistryMapper::AddWorker,
  1243. this);
  1244. }
  1245. void
  1246. RegistryMapper::AddEntry(
  1247. const std::wstring &Key,
  1248. const std::wstring &Value
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. Given a key and value adds it to the map maintained by
  1253. the registry mapper.
  1254. Arguments:
  1255. Key - The key i.e. fully qualified registry path name
  1256. Value - The file that has the backing storage for this
  1257. key.
  1258. Return Value:
  1259. None.
  1260. --*/
  1261. {
  1262. KeyToRegistryMap[Key] = Value;
  1263. }
  1264. bool
  1265. RegistryMapper::GetMappedRegistry(
  1266. const std::wstring &Key,
  1267. std::wstring &Registry
  1268. )
  1269. /*++
  1270. Routine Description:
  1271. Given a Key returns the mapped backing store file name for
  1272. it.
  1273. Arguments:
  1274. Key - The key i.e. fully qualified registry path name
  1275. Value - Place holder to receive the file that has the backing
  1276. storage for this key.
  1277. Return Value:
  1278. true if a mapping exists otherwise false.
  1279. --*/
  1280. {
  1281. bool Result = false;
  1282. //std::cout << "GetMappedRegistry(" << Key << ")" << std::endl;
  1283. std::wstring KeyLower = Key;
  1284. _wcslwr((PWSTR)KeyLower.c_str());
  1285. std::map< std::wstring, std::wstring >::iterator Iter = KeyToRegistryMap.find(KeyLower);
  1286. if (Iter != KeyToRegistryMap.end()) {
  1287. Registry = (*Iter).second;
  1288. Result = true;
  1289. }
  1290. return Result;
  1291. }