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.

474 lines
19 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. sxssfc_repairshortnames.cpp
  5. Abstract:
  6. after textmode setup extracts asms*.cab and write hivesxs.inf,
  7. write the correct shortnames into the registry
  8. Author:
  9. Jay Krell (Jaykrell) June 2002
  10. Revision History:
  11. --*/
  12. #include "stdinc.h"
  13. #include "recover.h"
  14. #include "cassemblyrecoveryinfo.h"
  15. #include "sxssfcscan.h"
  16. BOOL
  17. SxspSetupGetSourceInfo(
  18. HINF InfHandle, // handle to the INF file
  19. UINT SourceId, // ID of the source media
  20. UINT InfoDesired, // information to retrieve
  21. CBaseStringBuffer &buff,
  22. LPDWORD RequiredSize // optional, buffer size needed
  23. )
  24. {
  25. FN_PROLOG_WIN32
  26. CStringBufferAccessor acc;
  27. DWORD RequiredSize2 = 0;
  28. BOOL fTooSmall = FALSE;
  29. if (RequiredSize == NULL)
  30. {
  31. RequiredSize = &RequiredSize2;
  32. }
  33. acc.Attach(&buff);
  34. IFW32FALSE_EXIT_UNLESS2(
  35. ::SetupGetSourceInfoW(
  36. InfHandle,
  37. SourceId,
  38. InfoDesired,
  39. acc,
  40. acc.GetBufferCchAsDWORD(),
  41. RequiredSize
  42. ),
  43. LIST_1(ERROR_INSUFFICIENT_BUFFER),
  44. fTooSmall);
  45. if (fTooSmall)
  46. {
  47. acc.Detach();
  48. IFW32FALSE_EXIT(buff.Win32ResizeBuffer(*RequiredSize + 1, eDoNotPreserveBufferContents));
  49. acc.Attach(&buff);
  50. IFW32FALSE_EXIT(
  51. ::SetupGetSourceInfoW(
  52. InfHandle,
  53. SourceId,
  54. InfoDesired,
  55. acc,
  56. acc.GetBufferCchAsDWORD(),
  57. RequiredSize
  58. ));
  59. }
  60. FN_EPILOG
  61. }
  62. BOOL
  63. SxspGetWindowsSetupPrompt(
  64. CBaseStringBuffer &rbuffWinsxsRoot
  65. )
  66. //
  67. // This code is based closely on code in base\ntsetup\syssetup\copy.c
  68. // Legacy wfp is a little different, it opens layout.inf, but the results
  69. // should be the same.
  70. //
  71. {
  72. FN_PROLOG_WIN32
  73. CFusionSetupInfFile InfFile;
  74. CStringBuffer InfPath;
  75. const static UNICODE_STRING inf = RTL_CONSTANT_STRING(L"inf");
  76. const static UNICODE_STRING filename_inf = RTL_CONSTANT_STRING(L"layout.inf");
  77. UINT SourceId = 0;
  78. const PCWSTR SystemRoot = USER_SHARED_DATA->NtSystemRoot;
  79. IFW32FALSE_EXIT(InfPath.Win32Assign(SystemRoot, ::wcslen(SystemRoot)));
  80. IFW32FALSE_EXIT(InfPath.Win32AppendPathElement(&inf));
  81. IFW32FALSE_EXIT(InfPath.Win32AppendPathElement(&filename_inf));
  82. IFW32FALSE_EXIT(InfFile.Win32SetupOpenInfFileW(InfPath, NULL, INF_STYLE_WIN4, NULL));
  83. IFW32FALSE_EXIT(::SetupGetSourceFileLocationW(InfFile, NULL, L"shell32.dll", &SourceId, NULL, 0, NULL));
  84. IFW32FALSE_EXIT(::SxspSetupGetSourceInfo(InfFile, SourceId, SRCINFO_DESCRIPTION, rbuffWinsxsRoot, NULL));
  85. FN_EPILOG
  86. }
  87. BOOL
  88. SxspModifyRegistryData(
  89. DWORD Flags
  90. )
  91. {
  92. //
  93. // In postbuild we run sxsofflineinstall.
  94. // This includes creating hivesxs.inf to populate the registry
  95. // with data needed for windows file protection.
  96. //
  97. // The data includes short names, but we don't know the short names
  98. // until textmode setup. The code in textmode setup is fairly generic
  99. // and just expands .cabs.
  100. //
  101. // We do not need the short names to be correct until we expect
  102. // bogus file changes against short file names to induce recovery
  103. // of assemblies. It is reasonable to assume that these won't happen
  104. // until setup is done and the system is running.
  105. //
  106. // Therefore it is sufficient to fixup the shortnames after textmode setup,
  107. // such as in a RunOnce entry.
  108. //
  109. /*
  110. Here is an example of what we are fixing up.
  111. [AddReg]
  112. HKLM,"\Software\Microsoft\Windows\CurrentVersion\SideBySide\Installations
  113. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","Identity",0x00001000,"Microsoft.Windows.Common-Controls,processorArchitecture="IA64",publicKeyToken="6595b64144ccf1df",type="win32",version="5.82.0.0""
  114. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","Catalog",0x00011001,0x00000001
  115. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","ManifestSHA1Hash",0x00001001,3b,26,4a,90,08,0f,6a,dd,b6,00,55,5b,a5,a4,9e,21,ad,e3,90,84
  116. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","ShortName",0x00001000,"IA64_M~2.0_X"
  117. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","ShortCatalogName",0x00001000,"IA64_M~4.CAT"
  118. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","ShortManifestName",0x00001000,"IA64_M~4.MAN"
  119. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","PublicKeyToken",0x00001001,65,95,b6,41,44,cc,f1,df
  120. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5","Codebase",0x00001000,"x-ms-windows-source:W_fusi_bin.IA64chk/asms/58200/Msft/Windows/Common/Controls/Controls.man"
  121. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5\Codebases\OS","Prompt",0x00001000,"(textmode setup placeholder)"
  122. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5\Codebases\OS","URL",0x00001000,"x-ms-windows-source:W_fusi_bin.IA64chk/asms/58200/Msft/Windows/Common/Controls/Controls.man"
  123. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5\Files\0","",0x00001000,"comctl32.dll"
  124. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5\Files\0","SHA1",0x00001001,76,c3,6e,4c,c4,10,14,7f,38,c8,bc,cd,4b,4f,b2,90,d8,0a,7c,d7
  125. HKLM,"\...\IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5\References","OS",0x00001000,"Foom"
  126. IA64_Microsoft.Windows.Common-Controls_6595b64144ccf1df_5.82.0.0_x-ww_B9C4A0A5
  127. */
  128. BOOL fSuccess = FALSE;
  129. FN_TRACE_WIN32(fSuccess);
  130. CFusionRegKey regkeyInstallations;
  131. CFusionRegKey regkeyInstallation;
  132. DWORD dwRegSubKeyIndex = 0;
  133. BOOL fNoMoreItems = FALSE;
  134. FILETIME LastWriteFileTimeIgnored = { 0 };
  135. CTinyStringBuffer buffInstallationName;
  136. CTinyStringBuffer buffWinsxsRoot;
  137. CTinyStringBuffer *buffLongFullPath = NULL;
  138. CTinyStringBuffer buffShortFullPath;
  139. CTinyStringBuffer buffShortPathLastElement;
  140. CTinyStringBuffer buffTextualIdentity;
  141. CTinyStringBuffer buffEmpty;
  142. CTinyStringBuffer buffWindowsSetupPrompt;
  143. CTinyStringBuffer buffCurrentPromptInRegistry;
  144. CTinyStringBuffer buffFullPathToManifest;
  145. CTinyStringBuffer buffFullPathToCatalog;
  146. CTinyStringBuffer buffFullPathToPayloadDirectory;
  147. SIZE_T i = 0;
  148. const bool fRepairAll = ((Flags & SXSP_MODIFY_REGISTRY_DATA_FLAG_REPAIR_ALL) != 0);
  149. const bool fRepairShort = fRepairAll || ((Flags & SXSP_MODIFY_REGISTRY_DATA_FLAG_REPAIR_SHORT_NAMES) != 0);
  150. const bool fDeleteShort = ((Flags & SXSP_MODIFY_REGISTRY_DATA_FLAG_DELETE_SHORT_NAMES) != 0);
  151. const bool fRepairPrompt = fRepairAll || ((Flags & SXSP_MODIFY_REGISTRY_DATA_FLAG_REPAIR_OFFLINE_INSTALL_REFRESH_PROMPTS) != 0);
  152. const bool fValidate = ((Flags & SXSP_MODIFY_REGISTRY_DATA_VALIDATE) != 0);
  153. #if DBG
  154. bool fDbgPrintBecauseHashValidationFailed = false;
  155. #endif
  156. PARAMETER_CHECK(Flags != 0);
  157. PARAMETER_CHECK((Flags & ~SXSP_MODIFY_REGISTRY_DATA_FLAG_VALID_FLAGS) == 0);
  158. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(buffWinsxsRoot));
  159. IFW32FALSE_EXIT(::SxspOpenAssemblyInstallationKey(0, KEY_READ | KEY_SET_VALUE | FUSIONP_KEY_WOW64_64KEY, regkeyInstallations));
  160. if (fRepairPrompt)
  161. {
  162. IFW32FALSE_EXIT(::SxspGetWindowsSetupPrompt(buffWindowsSetupPrompt));
  163. }
  164. for ((dwRegSubKeyIndex = 0), (fNoMoreItems = FALSE); !fNoMoreItems ; ++dwRegSubKeyIndex)
  165. {
  166. bool fNotFound = false;
  167. CSmartAssemblyIdentity AssemblyIdentity;
  168. PROBING_ATTRIBUTE_CACHE AttributeCache = { 0 };
  169. CFusionRegKey codebase_os;
  170. IFW32FALSE_EXIT(
  171. regkeyInstallations.EnumKey(
  172. dwRegSubKeyIndex,
  173. buffInstallationName,
  174. &LastWriteFileTimeIgnored,
  175. &fNoMoreItems));
  176. if (fNoMoreItems)
  177. {
  178. break;
  179. }
  180. IFW32FALSE_EXIT(
  181. regkeyInstallations.OpenSubKey(
  182. regkeyInstallation,
  183. buffInstallationName,
  184. KEY_READ | KEY_SET_VALUE | ((fRepairPrompt || fValidate) ? KEY_ENUMERATE_SUB_KEYS : 0)
  185. ));
  186. IFW32FALSE_EXIT(
  187. regkeyInstallation.GetValue(
  188. CSMD_TOPLEVEL_IDENTITY,
  189. buffTextualIdentity
  190. ));
  191. IFW32FALSE_EXIT(::SxspCreateAssemblyIdentityFromTextualString(buffTextualIdentity, &AssemblyIdentity));
  192. typedef struct _SXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME
  193. {
  194. BOOL (*GeneratePathFunction)(
  195. IN const CBaseStringBuffer &AssemblyRootDirectory,
  196. IN PCASSEMBLY_IDENTITY pAssemblyIdentity,
  197. IN OUT PPROBING_ATTRIBUTE_CACHE ppac,
  198. IN OUT CBaseStringBuffer &PathBuffer
  199. );
  200. PCWSTR RegistryValueName;
  201. } SXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME, *PSXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME;
  202. typedef const SXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME *PCSXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME;
  203. const static SXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME s_rgFunctionRegistryValueName[] =
  204. {
  205. //
  206. // Note that policies are not currently wfp protected,
  207. // but it's easy and obvious to put reasonable data
  208. // in the registry for them.
  209. //
  210. { &::SxspGenerateSxsPath_FullPathToManifestOrPolicyFile, CSMD_TOPLEVEL_SHORTMANIFEST },
  211. { &::SxspGenerateSxsPath_FullPathToCatalogFile, CSMD_TOPLEVEL_SHORTCATALOG },
  212. { &::SxspGenerateSxsPath_FullPathToPayloadOrPolicyDirectory, CSMD_TOPLEVEL_SHORTNAME }
  213. };
  214. CBaseStringBuffer * const rgpbuffFullPaths[] =
  215. {
  216. &buffFullPathToManifest,
  217. &buffFullPathToCatalog,
  218. &buffFullPathToPayloadDirectory
  219. };
  220. //
  221. // first generate all three fullpaths
  222. //
  223. for (i = 0 ; i != NUMBER_OF(s_rgFunctionRegistryValueName) ; ++i)
  224. {
  225. const PCSXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME p = &s_rgFunctionRegistryValueName[i];
  226. CBaseStringBuffer * const pbuffLongFullPath = rgpbuffFullPaths[i];
  227. IFW32FALSE_EXIT((*p->GeneratePathFunction)(
  228. buffWinsxsRoot,
  229. AssemblyIdentity,
  230. &AttributeCache,
  231. *pbuffLongFullPath));
  232. IFW32FALSE_EXIT(pbuffLongFullPath->Win32RemoveTrailingPathSeparators());
  233. }
  234. //
  235. // optionally repair short names
  236. //
  237. if (fRepairShort)
  238. {
  239. for (i = 0 ; i != NUMBER_OF(s_rgFunctionRegistryValueName) ; ++i)
  240. {
  241. const PCSXSP_GENERATE_PATH_FUNCTION_REGISTRY_VALUE_NAME p = &s_rgFunctionRegistryValueName[i];
  242. CBaseStringBuffer * const pbuffLongFullPath = rgpbuffFullPaths[i];
  243. {
  244. DWORD dwWin32Error = NO_ERROR;
  245. IFW32FALSE_EXIT(
  246. ::SxspGetShortPathName(
  247. *pbuffLongFullPath,
  248. buffShortFullPath,
  249. dwWin32Error,
  250. static_cast<SIZE_T>(4),
  251. ERROR_PATH_NOT_FOUND,
  252. ERROR_FILE_NOT_FOUND,
  253. ERROR_BAD_NET_NAME,
  254. ERROR_BAD_NETPATH));
  255. if (dwWin32Error == NO_ERROR)
  256. {
  257. IFW32FALSE_EXIT(buffShortFullPath.Win32GetLastPathElement(buffShortPathLastElement));
  258. IFW32FALSE_EXIT(regkeyInstallation.SetValue(p->RegistryValueName, buffShortPathLastElement));
  259. }
  260. }
  261. }
  262. }
  263. //
  264. // optionally delete short names
  265. //
  266. if (fDeleteShort)
  267. {
  268. for (i = 0 ; i != NUMBER_OF(s_rgFunctionRegistryValueName) ; ++i)
  269. {
  270. IFW32FALSE_EXIT(regkeyInstallation.DeleteValue(s_rgFunctionRegistryValueName[i].RegistryValueName));
  271. }
  272. }
  273. //
  274. // validate hashes and repair prompts
  275. // BE SURE TO validate hashes first, as we filter what assemblies
  276. // to repair based on the placeholder prompt
  277. //
  278. IFW32FALSE_EXIT_UNLESS2(
  279. regkeyInstallation.OpenSubKey(
  280. codebase_os,
  281. CSMD_TOPLEVEL_CODEBASES L"\\" SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL_STRING,
  282. KEY_READ | KEY_SET_VALUE),
  283. LIST_2(ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND),
  284. fNotFound);
  285. //
  286. // OpenSubKey actually eats some errors, so you can't trust
  287. // fNotFound or the BOOL returned.
  288. //
  289. if (!fNotFound && codebase_os.IsValid())
  290. {
  291. fNotFound = false;
  292. IFW32FALSE_EXIT_UNLESS2(
  293. codebase_os.GetValue(
  294. CSMD_CODEBASES_PROMPTSTRING,
  295. buffCurrentPromptInRegistry),
  296. LIST_2(ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND),
  297. fNotFound);
  298. if (!fNotFound)
  299. {
  300. if (::FusionpEqualStringsI(
  301. buffCurrentPromptInRegistry,
  302. SXSP_OFFLINE_INSTALL_REFRESH_PROMPT_PLACEHOLDER,
  303. NUMBER_OF(SXSP_OFFLINE_INSTALL_REFRESH_PROMPT_PLACEHOLDER) - 1))
  304. {
  305. if (fValidate)
  306. {
  307. CAssemblyRecoveryInfo AssemblyRecoveryInfo;
  308. bool fNoAssembly = false;
  309. DWORD dwResult = 0;
  310. IFW32FALSE_EXIT(AssemblyRecoveryInfo.Initialize());
  311. IFW32FALSE_EXIT(AssemblyRecoveryInfo.AssociateWithAssembly(buffInstallationName, fNoAssembly));
  312. IFW32FALSE_EXIT(::SxspValidateEntireAssembly(
  313. SXS_VALIDATE_ASM_FLAG_CHECK_EVERYTHING,
  314. AssemblyRecoveryInfo,
  315. dwResult,
  316. AssemblyIdentity
  317. ));
  318. if (dwResult != SXS_VALIDATE_ASM_FLAG_VALID_PERFECT)
  319. {
  320. ::FusionpDbgPrintEx(
  321. FUSION_DBG_LEVEL_SETUPLOG,
  322. "The assembly %ls contains file hash errors.\n",
  323. static_cast<PCWSTR>(buffTextualIdentity));
  324. ::FusionpDbgPrintEx(
  325. FUSION_DBG_LEVEL_ERROR,
  326. "SXS.DLL %s: The assembly %ls contains file hash errors.\n",
  327. __FUNCTION__,
  328. static_cast<PCWSTR>(buffTextualIdentity));
  329. ::FusionpSetLastWin32Error(ERROR_SXS_FILE_HASH_MISMATCH);
  330. #if DBG
  331. fDbgPrintBecauseHashValidationFailed = true;
  332. #endif
  333. goto Exit;
  334. }
  335. }
  336. if (fRepairPrompt)
  337. {
  338. IFW32FALSE_EXIT(
  339. codebase_os.SetValue(
  340. CSMD_CODEBASES_PROMPTSTRING,
  341. buffWindowsSetupPrompt));
  342. }
  343. }
  344. }
  345. }
  346. }
  347. fSuccess = TRUE;
  348. Exit:
  349. if ((!fSuccess && ::FusionpDbgWouldPrintAtFilterLevel(FUSION_DBG_LEVEL_ERROR))
  350. #if DBG
  351. || fDbgPrintBecauseHashValidationFailed
  352. #endif
  353. )
  354. {
  355. //
  356. // multiple dbgprints due to 511 limit
  357. // use tick count to link together seperate prints
  358. //
  359. CSxsPreserveLastError ple;
  360. DWORD TickCount = ::GetTickCount();
  361. ::FusionpDbgPrintEx(
  362. FUSION_DBG_LEVEL_ERROR,
  363. "SXS.DLL: %s 0x%lx error 0x%lx\n", __FUNCTION__, TickCount, ple.LastError());
  364. ::FusionpDbgPrintEx(
  365. FUSION_DBG_LEVEL_ERROR,
  366. "SXS.DLL: %s 0x%lx dwRegSubKeyIndex 0x%lx\n", __FUNCTION__, TickCount, dwRegSubKeyIndex);
  367. ::FusionpDbgPrintEx(
  368. FUSION_DBG_LEVEL_ERROR,
  369. "SXS.DLL: %s 0x%lx i 0x%Ix\n", __FUNCTION__, TickCount, i);
  370. ::FusionpDbgPrintEx(
  371. FUSION_DBG_LEVEL_ERROR,
  372. "SXS.DLL: %s 0x%lx buffInstallationName %ls\n", __FUNCTION__, TickCount, static_cast<PCWSTR>(buffInstallationName));
  373. ::FusionpDbgPrintEx(
  374. FUSION_DBG_LEVEL_ERROR,
  375. "SXS.DLL: %s 0x%lx buffTextualIdentity %ls\n", __FUNCTION__, TickCount, static_cast<PCWSTR>(buffTextualIdentity));
  376. ::FusionpDbgPrintEx(
  377. FUSION_DBG_LEVEL_ERROR,
  378. "SXS.DLL: %s 0x%lx buffFullPathToManifest %ls\n", __FUNCTION__, TickCount, static_cast<PCWSTR>(buffFullPathToManifest));
  379. ::FusionpDbgPrintEx(
  380. FUSION_DBG_LEVEL_ERROR,
  381. "SXS.DLL: %s 0x%lx buffFullPathToCatalog %ls\n", __FUNCTION__, TickCount, static_cast<PCWSTR>(buffFullPathToCatalog));
  382. ::FusionpDbgPrintEx(
  383. FUSION_DBG_LEVEL_ERROR,
  384. "SXS.DLL: %s 0x%lx buffFullPathToPayloadDirectory %ls\n", __FUNCTION__, TickCount, static_cast<PCWSTR>(buffFullPathToPayloadDirectory));
  385. ::FusionpDbgPrintEx(
  386. FUSION_DBG_LEVEL_ERROR,
  387. "SXS.DLL: %s 0x%lx buffShortFullPath %ls\n", __FUNCTION__, TickCount, static_cast<PCWSTR>(buffShortFullPath));
  388. ::FusionpDbgPrintEx(
  389. FUSION_DBG_LEVEL_ERROR,
  390. "SXS.DLL: %s 0x%lx buffShortPathLastElement %ls\n", __FUNCTION__, TickCount, static_cast<PCWSTR>(buffShortPathLastElement));
  391. ple.Restore();
  392. }
  393. return fSuccess;
  394. }
  395. BOOL
  396. SxspDeleteShortNamesInRegistry(
  397. VOID
  398. )
  399. {
  400. return ::SxspModifyRegistryData(SXSP_MODIFY_REGISTRY_DATA_FLAG_DELETE_SHORT_NAMES);
  401. }
  402. STDAPI
  403. DllInstall(
  404. BOOL fInstall,
  405. PCWSTR pszCmdLine
  406. )
  407. {
  408. FN_PROLOG_HR
  409. //
  410. // Just ignore uninstall requests.
  411. //
  412. if (!fInstall)
  413. {
  414. FN_SUCCESSFUL_EXIT();
  415. }
  416. //
  417. // It doesn't look like guimode setup ever passes in
  418. // anything for pszCmdLine, so we don't look at it.
  419. //
  420. IFW32FALSE_EXIT(::SxspModifyRegistryData(SXSP_MODIFY_REGISTRY_DATA_FLAG_REPAIR_ALL | SXSP_MODIFY_REGISTRY_DATA_VALIDATE));
  421. FN_EPILOG
  422. }