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.

853 lines
25 KiB

  1. /*
  2. Copyright (c) Microsoft Corporation
  3. This program performs "offline" setup of side-by-side assemblies.
  4. "Offline" meaning to a directory other than the current windows directory.
  5. */
  6. #include "stdinc.h"
  7. #if DBG // free builds have known problems, not worth fixing
  8. #include <stddef.h>
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <stdarg.h>
  12. #include "nt.h"
  13. #include "ntrtl.h"
  14. #include "nturtl.h"
  15. #include "windows.h"
  16. #include "sxsapi.h"
  17. #include "fusionlastwin32error.h"
  18. #include "fusionbuffer.h"
  19. #include "sxstest.h"
  20. #include "cassemblyrecoveryinfo.h"
  21. #define SXSP_TOOL_KNOWS_ABOUT_BUILD 0
  22. #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
  23. extern "C" BOOL g_fForceInOsSetupMode; // this feature not available in free builds
  24. extern BOOL g_SxsOfflineInstall; // this feature not available in free builds
  25. BOOL
  26. SxspQueryEnvironmentVariable(
  27. PCWSTR pcwszName,
  28. CBaseStringBuffer &Value,
  29. bool &fFound
  30. )
  31. {
  32. FN_PROLOG_WIN32;
  33. CStringBufferAccessor sba;
  34. SIZE_T cchRequired = 0;
  35. DWORD dwLastError = 0;
  36. fFound = false;
  37. Value.Clear();
  38. if (Value.GetBufferCch() < 2)
  39. {
  40. IFW32FALSE_EXIT(
  41. Value.Win32ResizeBuffer(
  42. 2,
  43. eDoNotPreserveBufferContents));
  44. }
  45. sba.Attach(&Value);
  46. while (TRUE)
  47. {
  48. sba.GetBufferPtr()[sba.GetBufferCch() - 1] = 0;
  49. cchRequired = ::GetEnvironmentVariableW(pcwszName, sba.GetBufferPtr(), sba.GetBufferCchAsDWORD() - 1);
  50. if (
  51. cchRequired != 0
  52. && cchRequired < sba.GetBufferCch()
  53. && sba.GetBufferPtr()[sba.GetBufferCch() - 1] == 0)
  54. {
  55. break;
  56. }
  57. dwLastError = ::FusionpGetLastWin32Error();
  58. if (cchRequired == 0 && dwLastError != ERROR_ENVVAR_NOT_FOUND)
  59. {
  60. ORIGINATE_WIN32_FAILURE_AND_EXIT(GetEnvironmentVariableW, dwLastError);
  61. }
  62. if (cchRequired == 0)
  63. {
  64. cchRequired = (Value.GetBufferCch() + 1) * 2;
  65. }
  66. sba.Detach();
  67. IFW32FALSE_EXIT(Value.Win32ResizeBuffer(cchRequired + 1, eDoNotPreserveBufferContents));
  68. sba.Attach(&Value);
  69. }
  70. sba.Detach();
  71. FN_EPILOG;
  72. }
  73. class CSxspOfflineInstall
  74. {
  75. public:
  76. typedef CFusionArray<CStringBuffer, CBaseStringBuffer> CSourceDirectories;
  77. CSxspOfflineInstall() : fIgnoreMissingDirectories(false), fDefaultInstall(false)
  78. {
  79. }
  80. int
  81. SxsOfflineInstall(
  82. int argc,
  83. wchar_t ** argv
  84. );
  85. CSmallStringBuffer buffToolnameFromArgv0;
  86. CSmallStringBuffer buffWinsxs;
  87. CSmallStringBuffer buffRegResultTarget;
  88. CStringBuffer buffHostRegPathTemp;
  89. CSmallStringBuffer buffCodeBaseURL;
  90. CSourceDirectories DirectoriesToInstall;
  91. CSmallStringBuffer buffNoncanonicalData;
  92. bool fIgnoreMissingDirectories;
  93. bool fDefaultInstall;
  94. #if SXSP_TOOL_KNOWS_ABOUT_BUILD
  95. CSmallStringBuffer buffBuildArch;
  96. #endif
  97. BOOL MiniSetupInstall(PCWSTR pcwszSourcePath);
  98. BOOL Initialize()
  99. {
  100. FN_PROLOG_WIN32;
  101. IFW32FALSE_EXIT(DirectoriesToInstall.Win32Initialize());
  102. FN_EPILOG;
  103. }
  104. BOOL LoadParameters(int argc, wchar_t **argv);
  105. void DisplayUsage();
  106. BOOL
  107. FindAndWriteRegistryResults(
  108. const CBaseStringBuffer &OutputFile,
  109. HKEY hkActualBase
  110. );
  111. private:
  112. static const UNICODE_STRING opt_Winsxs;;
  113. static const UNICODE_STRING opt_Sourcedir;
  114. static const UNICODE_STRING opt_RegResult;
  115. static const UNICODE_STRING opt_IgnoreMissingDirectories;
  116. static const UNICODE_STRING opt_CodeBaseURL;
  117. static const UNICODE_STRING opt_NoncanonicalData;
  118. #if SXSP_TOOL_KNOWS_ABOUT_BUILD
  119. static const UNICODE_STRING opt_BuildArch;
  120. #endif
  121. enum COption
  122. {
  123. eWinsxsOpt,
  124. eSourceDirectoryOpt,
  125. eRegistryOutputFile,
  126. eBuildArchOpt,
  127. eIgnoreMissingDirectoriesOpt,
  128. eCodeBaseURL,
  129. eNoncanonicalData,
  130. eUnknownOption
  131. };
  132. class CMapOption
  133. {
  134. public:
  135. PCUNICODE_STRING Str;
  136. COption Option;
  137. CMapOption(PCUNICODE_STRING src, COption o) : Str(src), Option(o) { }
  138. };
  139. static const CMapOption m_Options[];
  140. static const SIZE_T m_cOptionCount;
  141. COption MapOption(const UNICODE_STRING &str) const
  142. {
  143. for (SIZE_T c = 0; c < m_cOptionCount; c++)
  144. {
  145. if (::FusionpEqualStringsI(&str, m_Options[c].Str))
  146. {
  147. return m_Options[c].Option;
  148. }
  149. }
  150. return eUnknownOption;
  151. }
  152. bool StartsWithSwitchChar(PCWSTR pcwsz)
  153. {
  154. return (pcwsz && (*pcwsz == L'-'));
  155. }
  156. PCWSTR GetPureOption(PCWSTR pcwsz)
  157. {
  158. PCWSTR pcwszOption = pcwsz;
  159. while (StartsWithSwitchChar(pcwszOption))
  160. {
  161. pcwszOption++;
  162. }
  163. return pcwszOption;
  164. }
  165. };
  166. const UNICODE_STRING CSxspOfflineInstall::opt_Winsxs = RTL_CONSTANT_STRING(L"windir");
  167. const UNICODE_STRING CSxspOfflineInstall::opt_Sourcedir = RTL_CONSTANT_STRING(L"source");
  168. const UNICODE_STRING CSxspOfflineInstall::opt_RegResult = RTL_CONSTANT_STRING(L"registryoutput");
  169. const UNICODE_STRING CSxspOfflineInstall::opt_IgnoreMissingDirectories = RTL_CONSTANT_STRING(L"IgnoreMissingDirectories");
  170. const UNICODE_STRING CSxspOfflineInstall::opt_CodeBaseURL = RTL_CONSTANT_STRING(L"CodebaseUrl");
  171. const UNICODE_STRING CSxspOfflineInstall::opt_NoncanonicalData = RTL_CONSTANT_STRING(L"buffNoncanonicalData");
  172. #if SXSP_TOOL_KNOWS_ABOUT_BUILD
  173. const UNICODE_STRING CSxspOfflineInstall::opt_BuildArch = RTL_CONSTANT_STRING(L"buffBuildArch");
  174. #endif
  175. const CSxspOfflineInstall::CMapOption CSxspOfflineInstall::m_Options[] =
  176. {
  177. CMapOption(&opt_Winsxs, eWinsxsOpt),
  178. CMapOption(&opt_Sourcedir, eSourceDirectoryOpt),
  179. CMapOption(&opt_RegResult, eRegistryOutputFile),
  180. CMapOption(&opt_IgnoreMissingDirectories, eIgnoreMissingDirectoriesOpt),
  181. CMapOption(&opt_CodeBaseURL, eCodeBaseURL),
  182. CMapOption(&opt_NoncanonicalData, eNoncanonicalData),
  183. #if SXSP_TOOL_KNOWS_ABOUT_BUILD
  184. CMapOption(&opt_BuildArch, eBuildArchOpt),
  185. #endif
  186. };
  187. const SIZE_T CSxspOfflineInstall::m_cOptionCount = NUMBER_OF(CSxspOfflineInstall::m_Options);
  188. void
  189. CSxspOfflineInstall::DisplayUsage()
  190. {
  191. #define Lx(x) L##x
  192. #define L(x) Lx(x)
  193. static const WCHAR wchUsage[] =
  194. L"Offline installer postbuild tool - mail WinFuse with problems\r\n"
  195. L"Version: " L(__DATE__) L" " L(__TIME__) L" "
  196. #if defined(_WIN64)
  197. L"Win64"
  198. #elif defined(_WIN32)
  199. L"Win32"
  200. #endif
  201. L" "
  202. #if DBG
  203. L"chk"
  204. #else
  205. L"fre"
  206. #endif
  207. L"\r\n"
  208. L"-source <path> : specifies where to pick up files, like %_nttree%\\asms\r\n"
  209. L" You may specify it multiple times to pick up several asms trees,\r\n"
  210. L" which is useful in the case of Wow/Win64\r\n"
  211. L"\r\n"
  212. L"-windir <path> : specifies the target WinSxS pseudo-root to be installed to.\r\n"
  213. L" This directory should exist before running the tool.\r\n"
  214. L"\r\n"
  215. L"-registryoutput <file> : Specifies what file should contain the INF that\r\n"
  216. L" contains all the registry manipulation done.\r\n"
  217. L"\r\n"
  218. L"-DefaultInstall : add a [DefaultInstall] section so that\r\n"
  219. L" right clicking the .inf works in Explorer.\r\n"
  220. L"\r\n"
  221. L"-CodebaseUrl <url>\r\n"
  222. L"\r\n"
  223. L"-NoncanonicalData <text>\r\n"
  224. ;
  225. wprintf(wchUsage);
  226. }
  227. BOOL
  228. CSxspOfflineInstall::LoadParameters(
  229. int argc,
  230. wchar_t **argv
  231. )
  232. {
  233. #if 0
  234. if (argc == 0)
  235. {
  236. return FALSE;
  237. }
  238. #endif
  239. FN_PROLOG_WIN32;
  240. CStringBuffer NewItem;
  241. bool fNotFound = false;
  242. for (int i = 0; i < argc; i++)
  243. {
  244. UNICODE_STRING usThisOption;
  245. PARAMETER_CHECK(StartsWithSwitchChar(argv[i]));
  246. ::FusionpRtlInitUnicodeString(&usThisOption, GetPureOption(argv[i]));
  247. switch (MapOption(usThisOption))
  248. {
  249. case eIgnoreMissingDirectoriesOpt:
  250. this->fIgnoreMissingDirectories = true;
  251. break;
  252. case eNoncanonicalData:
  253. i++;
  254. PARAMETER_CHECK(i < argc);
  255. IFW32FALSE_EXIT(this->buffNoncanonicalData.Win32Assign(argv[i], ::wcslen(argv[i])));
  256. break;
  257. case eCodeBaseURL:
  258. i++;
  259. PARAMETER_CHECK(i < argc);
  260. IFW32FALSE_EXIT(this->buffCodeBaseURL.Win32Assign(argv[i], ::wcslen(argv[i])));
  261. break;
  262. case eSourceDirectoryOpt:
  263. i++;
  264. PARAMETER_CHECK(i < argc);
  265. IFW32FALSE_EXIT(NewItem.Win32Assign(argv[i], ::wcslen(argv[i])));
  266. IFW32FALSE_EXIT(this->DirectoriesToInstall.Win32Append(NewItem));
  267. break;
  268. case eWinsxsOpt:
  269. i++;
  270. PARAMETER_CHECK(i < argc);
  271. IFW32FALSE_EXIT(this->buffWinsxs.Win32Assign(argv[i], ::wcslen(argv[i])));
  272. break;
  273. case eRegistryOutputFile:
  274. i++;
  275. PARAMETER_CHECK(i < argc);
  276. IFW32FALSE_EXIT(this->buffRegResultTarget.Win32Assign(argv[i], ::wcslen(argv[i])));
  277. break;
  278. default:
  279. case eUnknownOption:
  280. PARAMETER_CHECK(false);
  281. break;
  282. }
  283. }
  284. if (this->buffWinsxs.Cch() == 0)
  285. {
  286. IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(this->buffWinsxs));
  287. }
  288. #if SXSP_TOOL_KNOWS_ABOUT_BUILD
  289. fNotFound = false;
  290. IFW32FALSE_EXIT(::SxspQueryEnvironmentVariable(L"_BuildArch", this->buffBuildArch, fNotFound));
  291. if (this->DirectoriesToInstall.GetSize() == 0)
  292. {
  293. CTinyStringBuffer BasePath;
  294. CTinyStringBuffer ToInstall;
  295. fNotFound = false;
  296. IFW32FALSE_EXIT(::SxspQueryEnvironmentVariable(L"_ntpostbld", BasePath, fNotFound));
  297. if (fNotFound)
  298. {
  299. IFW32FALSE_EXIT(::SxspQueryEnvironmentVariable(L"_nttree", BasePath, fNotFound));
  300. if (fNotFound)
  301. {
  302. wprintf(L"Unable to find environment variable _nttree, and no source directories set.\r\n");
  303. ORIGINATE_WIN32_FAILURE_AND_EXIT(NoDirectories, ERROR_INVALID_PARAMETER);
  304. }
  305. }
  306. IFW32FALSE_EXIT(ToInstall.Win32Assign(BasePath));
  307. IFW32FALSE_EXIT(ToInstall.Win32AppendPathElement(L"asms", 4));
  308. if (::GetFileAttributesW(ToInstall) != INVALID_FILE_ATTRIBUTES)
  309. {
  310. IFW32FALSE_EXIT(DirectoriesToInstall.Win32Append(ToInstall));
  311. }
  312. IFW32FALSE_EXIT(ToInstall.Win32Assign(BasePath));
  313. IFW32FALSE_EXIT(ToInstall.Win32AppendPathElement(L"wowbins\\asms", NUMBER_OF(L"wowbins\\asms") - 1));
  314. if (::GetFileAttributesW(ToInstall) != INVALID_FILE_ATTRIBUTES)
  315. {
  316. IFW32FALSE_EXIT(DirectoriesToInstall.Win32Append(ToInstall));
  317. }
  318. IFW32FALSE_EXIT(ToInstall.Win32Assign(BasePath));
  319. IFW32FALSE_EXIT(ToInstall.Win32AppendPathElement(L"wowbins\\wasms", NUMBER_OF(L"wowbins\\wasms") - 1));
  320. if (::GetFileAttributesW(ToInstall) != INVALID_FILE_ATTRIBUTES)
  321. {
  322. IFW32FALSE_EXIT(DirectoriesToInstall.Win32Append(ToInstall));
  323. }
  324. }
  325. #endif
  326. FN_EPILOG;
  327. }
  328. #if SXSP_TOOL_KNOWS_ABOUT_BUILD
  329. __declspec(selectany) extern const UNICODE_STRING x86String = RTL_CONSTANT_STRING(L"x86");
  330. __declspec(selectany) extern const UNICODE_STRING i386String = RTL_CONSTANT_STRING(L"i386");
  331. __declspec(selectany) extern const UNICODE_STRING BackslashString = RTL_CONSTANT_STRING(L"\\");
  332. __declspec(selectany) extern const UNICODE_STRING asms01_dot_cabString = RTL_CONSTANT_STRING(L"asms01.cab");
  333. __declspec(selectany) extern const UNICODE_STRING ProcessorBuildObjString = RTL_CONSTANT_STRING(SXSP_PROCESSOR_BUILD_OBJ_DIRECTORY_W);
  334. __declspec(selectany) extern const UNICODE_STRING ProcessorInstallDirectoryString = RTL_CONSTANT_STRING(SXSP_PROCESSOR_INSTALL_DIRECTORY_W);
  335. inline
  336. BOOL
  337. SxspConvertX86ToI386(
  338. CBaseStringBuffer & buffProcessor
  339. )
  340. {
  341. FN_PROLOG_WIN32;
  342. if (::FusionpEqualStringsI(buffProcessor, x86String.Buffer, RTL_STRING_GET_LENGTH_CHARS(&x86String)))
  343. {
  344. IFW32FALSE_EXIT(buffProcessor.Win32Assign(&i386String));
  345. }
  346. FN_EPILOG;
  347. }
  348. #endif
  349. BOOL
  350. CSxspOfflineInstall::MiniSetupInstall(PCWSTR pcwszSourcePath)
  351. {
  352. FN_PROLOG_WIN32;
  353. SXS_INSTALLW InstallParameters = {sizeof(InstallParameters)};
  354. SXS_INSTALL_REFERENCEW InstallReference = {sizeof(InstallReference)};
  355. g_fForceInOsSetupMode = TRUE;
  356. InstallReference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL;
  357. InstallReference.lpNonCanonicalData = this->buffNoncanonicalData;
  358. if (this->buffCodeBaseURL.Cch() != 0)
  359. {
  360. InstallParameters.lpCodebaseURL = this->buffCodeBaseURL;
  361. }
  362. else
  363. {
  364. #if SXSP_TOOL_KNOWS_ABOUT_BUILD
  365. if (this->buffBuildArch.Cch() == 0)
  366. #endif
  367. {
  368. InstallParameters.lpCodebaseURL = pcwszSourcePath;
  369. }
  370. #if SXSP_TOOL_KNOWS_ABOUT_BUILD
  371. else
  372. {
  373. CTinyStringBuffer buffCompactDiskBuildArch;
  374. IFW32FALSE_EXIT(buffCompactDiskBuildArch.Win32Assign(this->buffBuildArch));
  375. ::SxspConvertX86ToI386(buffCompactDiskBuildArch);
  376. IFW32FALSE_EXIT(this->buffCodeBaseURL.Win32Assign(&UnicodeString_URLHEAD_WINSOURCE));
  377. IFW32FALSE_EXIT(this->buffCodeBaseURL.Win32Append(buffCompactDiskBuildArch));
  378. IFW32FALSE_EXIT(this->buffCodeBaseURL.Win32Append(&BackslashString));
  379. IFW32FALSE_EXIT(this->buffCodeBaseURL.Win32Append(&asms01_dot_cabString));
  380. InstallParameters.lpCodebaseURL = this->buffCodeBaseURL;
  381. }
  382. #endif
  383. }
  384. InstallParameters.lpManifestPath = pcwszSourcePath;
  385. InstallParameters.lpRefreshPrompt = SXSP_OFFLINE_INSTALL_REFRESH_PROMPT_PLACEHOLDER;
  386. InstallParameters.lpReference = &InstallReference;
  387. InstallParameters.dwFlags = SXS_INSTALL_FLAG_FROM_DIRECTORY |
  388. SXS_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE |
  389. SXS_INSTALL_FLAG_REFERENCE_VALID |
  390. SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID |
  391. SXS_INSTALL_FLAG_INSTALLED_BY_OSSETUP |
  392. SXS_INSTALL_FLAG_NOT_TRANSACTIONAL |
  393. SXS_INSTALL_FLAG_CODEBASE_URL_VALID;
  394. if (::SxsInstallW(&InstallParameters))
  395. {
  396. wprintf(
  397. L"(%ls) SxsInstallW of %ls completed\r\n",
  398. static_cast<PCWSTR>(this->buffToolnameFromArgv0),
  399. pcwszSourcePath
  400. );
  401. FN_SUCCESSFUL_EXIT();
  402. }
  403. else
  404. {
  405. wprintf(
  406. L"(%ls) SxsInstallW of %ls failed, lasterror 0x%lx\r\n",
  407. static_cast<PCWSTR>(this->buffToolnameFromArgv0),
  408. pcwszSourcePath,
  409. ::GetLastError()
  410. );
  411. ORIGINATE_WIN32_FAILURE_AND_EXIT(SxsInstallW, ::FusionpGetLastWin32Error());
  412. }
  413. FN_EPILOG;
  414. }
  415. HKEY g_hkRedirectionRoot;
  416. SXSP_LOCALLY_UNIQUE_ID g_uuidRedirection;
  417. BOOL SxspTurnOnRedirection(CStringBuffer &RegPath);
  418. BOOL SxspTurnOffRedirection(const CStringBuffer &RegPath);
  419. BOOL
  420. WriteFileString(
  421. HANDLE hFile,
  422. PCSTR pcszFormat,
  423. ...
  424. )
  425. {
  426. FN_PROLOG_WIN32;
  427. CHAR cBuffer[2048];
  428. PSTR pszBuffer = cBuffer;
  429. DWORD dwBuffer = NUMBER_OF(cBuffer);
  430. DWORD dwWritten;
  431. CSmartArrayPtr<CHAR> SmartArray;
  432. int iRequired = 0;
  433. int iWritten = 0;
  434. va_list va;
  435. va_start(va, pcszFormat);
  436. iRequired = ::_vscprintf(pcszFormat, va);
  437. if (iRequired > dwBuffer)
  438. {
  439. IFW32FALSE_EXIT(SmartArray.Win32Allocate(iRequired + 1, __FILE__, __LINE__));
  440. pszBuffer = SmartArray;
  441. dwBuffer = iRequired;
  442. }
  443. iWritten = ::_vsnprintf(pszBuffer, dwBuffer - 1, pcszFormat, va);
  444. pszBuffer[iWritten] = '\0';
  445. pszBuffer[dwBuffer - 1] = '\0';
  446. IFW32FALSE_EXIT(::WriteFile(hFile, pszBuffer, iWritten, &dwWritten, NULL));
  447. FN_EPILOG;
  448. }
  449. BOOL
  450. FindRegHelper(
  451. HANDLE hFile,
  452. CBaseStringBuffer &FullPath,
  453. CBaseStringBuffer &Child,
  454. CRegKey &hkSourceKey
  455. )
  456. {
  457. FN_PROLOG_WIN32;
  458. DWORD iIndex = 0;
  459. CTinyStringBuffer tsb;
  460. //
  461. // First, enum the values in this key.
  462. //
  463. do
  464. {
  465. BOOL fDone = FALSE;
  466. DWORD dwType = 0;
  467. IFW32FALSE_EXIT(hkSourceKey.EnumValue(iIndex++, Child, &dwType, &fDone));
  468. if (fDone)
  469. {
  470. break;
  471. }
  472. else
  473. {
  474. //
  475. // Form up the output
  476. //
  477. ::WriteFileString(hFile, "HKLM,\"%S\",\"%S\",",
  478. static_cast<PCWSTR>(FullPath),
  479. static_cast<PCWSTR>(Child));
  480. if (dwType == REG_SZ)
  481. {
  482. IFW32FALSE_EXIT(::FusionpRegQuerySzValueEx(0, hkSourceKey, Child, tsb));
  483. //
  484. // if it contains any quotes, go one character at a time,
  485. // doubling quotes
  486. //
  487. // if it has no quotes, write it all at once
  488. //
  489. if (::wcschr(tsb, '\"') != NULL)
  490. {
  491. IFW32FALSE_EXIT(::WriteFileString(hFile, "0x%08lx,\"",
  492. FLG_ADDREG_TYPE_SZ | FLG_ADDREG_64BITKEY));
  493. for (SIZE_T d = 0; d < tsb.Cch(); d++)
  494. {
  495. if (tsb[d] == '\"')
  496. IFW32FALSE_EXIT(::WriteFileString(hFile, "\"\""));
  497. else
  498. IFW32FALSE_EXIT(::WriteFileString(hFile, "%c", tsb[d]));
  499. }
  500. IFW32FALSE_EXIT(::WriteFileString(hFile, "\"\r\n"));
  501. }
  502. else
  503. {
  504. IFW32FALSE_EXIT(::WriteFileString(hFile, "0x%08lx,\"%S\"\r\n",
  505. FLG_ADDREG_TYPE_SZ | FLG_ADDREG_64BITKEY,
  506. static_cast<PCWSTR>(tsb)));
  507. }
  508. }
  509. else if (dwType == REG_DWORD)
  510. {
  511. DWORD dwValue = 0;
  512. IFW32FALSE_EXIT(
  513. ::FusionpRegQueryDwordValueEx(
  514. FUSIONP_REG_QUERY_DWORD_MISSING_VALUE_IS_FAILURE,
  515. hkSourceKey,
  516. Child,
  517. &dwValue,
  518. 0));
  519. IFW32FALSE_EXIT(::WriteFileString(hFile, "0x%08lx,0x%08lx\r\n",
  520. FLG_ADDREG_TYPE_DWORD | FLG_ADDREG_64BITKEY,
  521. dwValue));
  522. }
  523. else if (dwType == REG_BINARY)
  524. {
  525. CFusionArray<BYTE> bBytes;
  526. IFW32FALSE_EXIT(::FusionpRegQueryBinaryValueEx(0, hkSourceKey, Child, bBytes));
  527. IFW32FALSE_EXIT(::WriteFileString(
  528. hFile,
  529. "0x%08lx,",
  530. FLG_ADDREG_TYPE_BINARY | FLG_ADDREG_64BITKEY));
  531. for (SIZE_T c = 0; c < bBytes.GetSize(); c++)
  532. {
  533. if (c == 0)
  534. IFW32FALSE_EXIT(::WriteFileString(hFile, "%02x", bBytes[c]));
  535. else
  536. IFW32FALSE_EXIT(::WriteFileString(hFile, ",%02x", bBytes[c]));
  537. }
  538. IFW32FALSE_EXIT(::WriteFileString(hFile, "\r\n"));
  539. }
  540. else
  541. {
  542. ORIGINATE_WIN32_FAILURE_AND_EXIT(ErrorInvalidType, ERROR_INVALID_PARAMETER);
  543. }
  544. }
  545. }
  546. while (true);
  547. //
  548. // Now enum the keys
  549. //
  550. iIndex = 0;
  551. do
  552. {
  553. BOOL fDone = FALSE;
  554. IFW32FALSE_EXIT(hkSourceKey.EnumKey(iIndex++, Child, NULL, &fDone));
  555. if (fDone)
  556. {
  557. break;
  558. }
  559. //
  560. // Append this to the current key,
  561. else
  562. {
  563. const SIZE_T cch = FullPath.Cch();
  564. CRegKey ThisKey;
  565. //
  566. // no leading slash
  567. //
  568. if (FullPath.Cch() == 0)
  569. {
  570. IFW32FALSE_EXIT(FullPath.Win32Append(Child));
  571. }
  572. else
  573. {
  574. IFW32FALSE_EXIT(FullPath.Win32AppendPathElement(Child));
  575. }
  576. IFW32FALSE_EXIT(hkSourceKey.OpenSubKey(ThisKey, Child, KEY_READ, 0));
  577. IFW32FALSE_EXIT(::FindRegHelper(hFile, FullPath, Child, ThisKey));
  578. FullPath.Left(cch);
  579. }
  580. }
  581. while (true);
  582. FN_EPILOG;
  583. }
  584. BOOL
  585. CSxspOfflineInstall::FindAndWriteRegistryResults(
  586. const CBaseStringBuffer &OutputFile,
  587. HKEY hkActualBase
  588. )
  589. {
  590. FN_PROLOG_WIN32;
  591. CTinyStringBuffer Path;
  592. CTinyStringBuffer ChildTemp;
  593. CFusionFile hOutputFile;
  594. CRegKey hkBase = hkActualBase;
  595. IFW32FALSE_EXIT(hOutputFile.Win32CreateFile(OutputFile, GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS));
  596. IFW32FALSE_EXIT(::WriteFileString(hOutputFile,
  597. "[Version]\r\n"
  598. "Signature = \"$Windows NT$\"\r\n\r\n"
  599. // stampinf inserts DriverVer here, like other hiv*.inf
  600. ));
  601. if (this->fDefaultInstall)
  602. {
  603. IFW32FALSE_EXIT(::WriteFileString(hOutputFile,
  604. "[fDefaultInstall]\r\n"
  605. "AddReg=AddReg\r\n\r\n"
  606. ));
  607. }
  608. IFW32FALSE_EXIT(::WriteFileString(hOutputFile,
  609. "[AddReg]\r\n"
  610. ));
  611. IFW32FALSE_EXIT(::FindRegHelper(hOutputFile, Path, ChildTemp, hkBase));
  612. FN_EPILOG;
  613. }
  614. BOOL
  615. CSxspOfflineInstall::SxsOfflineInstall(
  616. int argc,
  617. wchar_t ** argv
  618. )
  619. {
  620. BOOL fSuccess = FALSE;
  621. int i = 0;
  622. DWORD FileAttributes = 0;
  623. BOOLEAN AppendWinsxs = TRUE;
  624. bool fFound = false;
  625. CTinyStringBuffer buffArgv0;
  626. CTinyStringBuffer CommandLineFromFileW;
  627. g_SxsOfflineInstall = TRUE;
  628. if (argc < 2)
  629. {
  630. this->DisplayUsage();
  631. ::FusionpSetLastWin32Error(ERROR_INVALID_PARAMETER);
  632. goto Exit;
  633. }
  634. if (!::SxsDllMain(::GetModuleHandleW(NULL), DLL_PROCESS_ATTACH, NULL))
  635. goto Exit;
  636. if (!buffArgv0.Win32Assign(argv[0], ::wcslen(argv[0])))
  637. goto Exit;
  638. if (!buffArgv0.Win32GetLastPathElement(this->buffToolnameFromArgv0))
  639. goto Exit;
  640. if (!this->Initialize() || !this->LoadParameters(argc - 1, argv + 1))
  641. {
  642. this->DisplayUsage();
  643. ::FusionpSetLastWin32Error(ERROR_INVALID_PARAMETER);
  644. goto Exit;
  645. }
  646. ::SxspDebug(SXS_DEBUG_SET_ASSEMBLY_STORE_ROOT, 0, this->buffWinsxs, NULL);
  647. g_WriteRegistryAnyway = TRUE;
  648. ::FusionpCreateDirectories(this->buffWinsxs, this->buffWinsxs.Cch());
  649. ::SxspTurnOnRedirection(this->buffHostRegPathTemp);
  650. for (int i = 0; i < this->DirectoriesToInstall.GetSize(); i++)
  651. {
  652. CStringBuffer &Buffer = this->DirectoriesToInstall[i];
  653. if (!this->fIgnoreMissingDirectories
  654. || ::GetFileAttributesW(Buffer) != INVALID_FILE_ATTRIBUTES)
  655. {
  656. this->MiniSetupInstall(Buffer);
  657. }
  658. }
  659. ::SxspDeleteShortNamesInRegistry();
  660. if (this->buffRegResultTarget.Cch() != 0)
  661. {
  662. this->FindAndWriteRegistryResults(this->buffRegResultTarget, HKEY_LOCAL_MACHINE);
  663. }
  664. ::SxspTurnOffRedirection(this->buffHostRegPathTemp);
  665. fSuccess = TRUE;
  666. Exit:
  667. return fSuccess;
  668. }
  669. int
  670. __cdecl
  671. wmain(
  672. int argc,
  673. wchar_t ** argv
  674. )
  675. {
  676. CSxspOfflineInstall This;
  677. DWORD dwWin32Error = NO_ERROR;
  678. ::FusionpSetLastWin32Error(dwWin32Error);
  679. if (!This.SxsOfflineInstall(argc, argv))
  680. {
  681. dwWin32Error = ::FusionpGetLastWin32Error();
  682. if (dwWin32Error == NO_ERROR)
  683. dwWin32Error = ERROR_INTERNAL_ERROR;
  684. }
  685. return dwWin32Error;
  686. }
  687. BOOL
  688. SxspTurnOnRedirection(CStringBuffer &RegPath)
  689. {
  690. FN_PROLOG_WIN32;
  691. CSmallStringBuffer UniqueId;
  692. IFW32FALSE_EXIT(::SxspCreateLocallyUniqueId(&g_uuidRedirection));
  693. IFW32FALSE_EXIT(::SxspFormatLocallyUniqueId(g_uuidRedirection, UniqueId));
  694. IFW32FALSE_EXIT(RegPath.Win32Assign(L"SxsOfflineInstall", NUMBER_OF(L"SxsOfflineInstall") - 1));
  695. IFW32FALSE_EXIT(RegPath.Win32AppendPathElement(UniqueId));
  696. IFREGFAILED_EXIT(::RegCreateKeyExW(
  697. HKEY_CURRENT_USER,
  698. RegPath,
  699. 0,
  700. NULL,
  701. 0,
  702. KEY_ALL_ACCESS,
  703. NULL,
  704. &g_hkRedirectionRoot,
  705. NULL));
  706. IFREGFAILED_EXIT(::RegOverridePredefKey(HKEY_LOCAL_MACHINE, g_hkRedirectionRoot));
  707. FN_EPILOG;
  708. }
  709. BOOL
  710. SxspTurnOffRedirection(const CStringBuffer &RegPath)
  711. {
  712. FN_PROLOG_WIN32;
  713. CRegKey TempKey(g_hkRedirectionRoot);
  714. CSmallStringBuffer Uid;
  715. IFW32FALSE_EXIT(TempKey.DestroyKeyTree());
  716. IFREGFAILED_EXIT(::RegOverridePredefKey(HKEY_LOCAL_MACHINE, NULL));
  717. IFREGFAILED_EXIT(::RegDeleteKeyW(HKEY_CURRENT_USER, RegPath));
  718. IFREGFAILED_EXIT(::RegDeleteKeyW(HKEY_CURRENT_USER, L"SxsOfflineInstall"));
  719. FN_EPILOG;
  720. }
  721. #else // free builds have known problems
  722. int __cdecl wmain(int argc, wchar_t ** argv)
  723. {
  724. fputs("free build does not work, sorry\n", stderr);
  725. return -1;
  726. }
  727. #endif