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

/*
Copyright (c) Microsoft Corporation
This program performs "offline" setup of side-by-side assemblies.
"Offline" meaning to a directory other than the current windows directory.
*/
#include "stdinc.h"
#if DBG // free builds have known problems, not worth fixing
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "nt.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "windows.h"
#include "sxsapi.h"
#include "fusionlastwin32error.h"
#include "fusionbuffer.h"
#include "sxstest.h"
#include "cassemblyrecoveryinfo.h"
#define SXSP_TOOL_KNOWS_ABOUT_BUILD 0
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
extern "C" BOOL g_fForceInOsSetupMode; // this feature not available in free builds
extern BOOL g_SxsOfflineInstall; // this feature not available in free builds
BOOL
SxspQueryEnvironmentVariable(
PCWSTR pcwszName,
CBaseStringBuffer &Value,
bool &fFound
)
{
FN_PROLOG_WIN32;
CStringBufferAccessor sba;
SIZE_T cchRequired = 0;
DWORD dwLastError = 0;
fFound = false;
Value.Clear();
if (Value.GetBufferCch() < 2)
{
IFW32FALSE_EXIT(
Value.Win32ResizeBuffer(
2,
eDoNotPreserveBufferContents));
}
sba.Attach(&Value);
while (TRUE)
{
sba.GetBufferPtr()[sba.GetBufferCch() - 1] = 0;
cchRequired = ::GetEnvironmentVariableW(pcwszName, sba.GetBufferPtr(), sba.GetBufferCchAsDWORD() - 1);
if (
cchRequired != 0
&& cchRequired < sba.GetBufferCch()
&& sba.GetBufferPtr()[sba.GetBufferCch() - 1] == 0)
{
break;
}
dwLastError = ::FusionpGetLastWin32Error();
if (cchRequired == 0 && dwLastError != ERROR_ENVVAR_NOT_FOUND)
{
ORIGINATE_WIN32_FAILURE_AND_EXIT(GetEnvironmentVariableW, dwLastError);
}
if (cchRequired == 0)
{
cchRequired = (Value.GetBufferCch() + 1) * 2;
}
sba.Detach();
IFW32FALSE_EXIT(Value.Win32ResizeBuffer(cchRequired + 1, eDoNotPreserveBufferContents));
sba.Attach(&Value);
}
sba.Detach();
FN_EPILOG;
}
class CSxspOfflineInstall
{
public:
typedef CFusionArray<CStringBuffer, CBaseStringBuffer> CSourceDirectories;
CSxspOfflineInstall() : fIgnoreMissingDirectories(false), fDefaultInstall(false)
{
}
int
SxsOfflineInstall(
int argc,
wchar_t ** argv
);
CSmallStringBuffer buffToolnameFromArgv0;
CSmallStringBuffer buffWinsxs;
CSmallStringBuffer buffRegResultTarget;
CStringBuffer buffHostRegPathTemp;
CSmallStringBuffer buffCodeBaseURL;
CSourceDirectories DirectoriesToInstall;
CSmallStringBuffer buffNoncanonicalData;
bool fIgnoreMissingDirectories;
bool fDefaultInstall;
#if SXSP_TOOL_KNOWS_ABOUT_BUILD
CSmallStringBuffer buffBuildArch;
#endif
BOOL MiniSetupInstall(PCWSTR pcwszSourcePath);
BOOL Initialize()
{
FN_PROLOG_WIN32;
IFW32FALSE_EXIT(DirectoriesToInstall.Win32Initialize());
FN_EPILOG;
}
BOOL LoadParameters(int argc, wchar_t **argv);
void DisplayUsage();
BOOL
FindAndWriteRegistryResults(
const CBaseStringBuffer &OutputFile,
HKEY hkActualBase
);
private:
static const UNICODE_STRING opt_Winsxs;;
static const UNICODE_STRING opt_Sourcedir;
static const UNICODE_STRING opt_RegResult;
static const UNICODE_STRING opt_IgnoreMissingDirectories;
static const UNICODE_STRING opt_CodeBaseURL;
static const UNICODE_STRING opt_NoncanonicalData;
#if SXSP_TOOL_KNOWS_ABOUT_BUILD
static const UNICODE_STRING opt_BuildArch;
#endif
enum COption
{
eWinsxsOpt,
eSourceDirectoryOpt,
eRegistryOutputFile,
eBuildArchOpt,
eIgnoreMissingDirectoriesOpt,
eCodeBaseURL,
eNoncanonicalData,
eUnknownOption
};
class CMapOption
{
public:
PCUNICODE_STRING Str;
COption Option;
CMapOption(PCUNICODE_STRING src, COption o) : Str(src), Option(o) { }
};
static const CMapOption m_Options[];
static const SIZE_T m_cOptionCount;
COption MapOption(const UNICODE_STRING &str) const
{
for (SIZE_T c = 0; c < m_cOptionCount; c++)
{
if (::FusionpEqualStringsI(&str, m_Options[c].Str))
{
return m_Options[c].Option;
}
}
return eUnknownOption;
}
bool StartsWithSwitchChar(PCWSTR pcwsz)
{
return (pcwsz && (*pcwsz == L'-'));
}
PCWSTR GetPureOption(PCWSTR pcwsz)
{
PCWSTR pcwszOption = pcwsz;
while (StartsWithSwitchChar(pcwszOption))
{
pcwszOption++;
}
return pcwszOption;
}
};
const UNICODE_STRING CSxspOfflineInstall::opt_Winsxs = RTL_CONSTANT_STRING(L"windir");
const UNICODE_STRING CSxspOfflineInstall::opt_Sourcedir = RTL_CONSTANT_STRING(L"source");
const UNICODE_STRING CSxspOfflineInstall::opt_RegResult = RTL_CONSTANT_STRING(L"registryoutput");
const UNICODE_STRING CSxspOfflineInstall::opt_IgnoreMissingDirectories = RTL_CONSTANT_STRING(L"IgnoreMissingDirectories");
const UNICODE_STRING CSxspOfflineInstall::opt_CodeBaseURL = RTL_CONSTANT_STRING(L"CodebaseUrl");
const UNICODE_STRING CSxspOfflineInstall::opt_NoncanonicalData = RTL_CONSTANT_STRING(L"buffNoncanonicalData");
#if SXSP_TOOL_KNOWS_ABOUT_BUILD
const UNICODE_STRING CSxspOfflineInstall::opt_BuildArch = RTL_CONSTANT_STRING(L"buffBuildArch");
#endif
const CSxspOfflineInstall::CMapOption CSxspOfflineInstall::m_Options[] =
{
CMapOption(&opt_Winsxs, eWinsxsOpt),
CMapOption(&opt_Sourcedir, eSourceDirectoryOpt),
CMapOption(&opt_RegResult, eRegistryOutputFile),
CMapOption(&opt_IgnoreMissingDirectories, eIgnoreMissingDirectoriesOpt),
CMapOption(&opt_CodeBaseURL, eCodeBaseURL),
CMapOption(&opt_NoncanonicalData, eNoncanonicalData),
#if SXSP_TOOL_KNOWS_ABOUT_BUILD
CMapOption(&opt_BuildArch, eBuildArchOpt),
#endif
};
const SIZE_T CSxspOfflineInstall::m_cOptionCount = NUMBER_OF(CSxspOfflineInstall::m_Options);
void
CSxspOfflineInstall::DisplayUsage()
{
#define Lx(x) L##x
#define L(x) Lx(x)
static const WCHAR wchUsage[] =
L"Offline installer postbuild tool - mail WinFuse with problems\r\n"
L"Version: " L(__DATE__) L" " L(__TIME__) L" "
#if defined(_WIN64)
L"Win64"
#elif defined(_WIN32)
L"Win32"
#endif
L" "
#if DBG
L"chk"
#else
L"fre"
#endif
L"\r\n"
L"-source <path> : specifies where to pick up files, like %_nttree%\\asms\r\n"
L" You may specify it multiple times to pick up several asms trees,\r\n"
L" which is useful in the case of Wow/Win64\r\n"
L"\r\n"
L"-windir <path> : specifies the target WinSxS pseudo-root to be installed to.\r\n"
L" This directory should exist before running the tool.\r\n"
L"\r\n"
L"-registryoutput <file> : Specifies what file should contain the INF that\r\n"
L" contains all the registry manipulation done.\r\n"
L"\r\n"
L"-DefaultInstall : add a [DefaultInstall] section so that\r\n"
L" right clicking the .inf works in Explorer.\r\n"
L"\r\n"
L"-CodebaseUrl <url>\r\n"
L"\r\n"
L"-NoncanonicalData <text>\r\n"
;
wprintf(wchUsage);
}
BOOL
CSxspOfflineInstall::LoadParameters(
int argc,
wchar_t **argv
)
{
#if 0
if (argc == 0)
{
return FALSE;
}
#endif
FN_PROLOG_WIN32;
CStringBuffer NewItem;
bool fNotFound = false;
for (int i = 0; i < argc; i++)
{
UNICODE_STRING usThisOption;
PARAMETER_CHECK(StartsWithSwitchChar(argv[i]));
::FusionpRtlInitUnicodeString(&usThisOption, GetPureOption(argv[i]));
switch (MapOption(usThisOption))
{
case eIgnoreMissingDirectoriesOpt:
this->fIgnoreMissingDirectories = true;
break;
case eNoncanonicalData:
i++;
PARAMETER_CHECK(i < argc);
IFW32FALSE_EXIT(this->buffNoncanonicalData.Win32Assign(argv[i], ::wcslen(argv[i])));
break;
case eCodeBaseURL:
i++;
PARAMETER_CHECK(i < argc);
IFW32FALSE_EXIT(this->buffCodeBaseURL.Win32Assign(argv[i], ::wcslen(argv[i])));
break;
case eSourceDirectoryOpt:
i++;
PARAMETER_CHECK(i < argc);
IFW32FALSE_EXIT(NewItem.Win32Assign(argv[i], ::wcslen(argv[i])));
IFW32FALSE_EXIT(this->DirectoriesToInstall.Win32Append(NewItem));
break;
case eWinsxsOpt:
i++;
PARAMETER_CHECK(i < argc);
IFW32FALSE_EXIT(this->buffWinsxs.Win32Assign(argv[i], ::wcslen(argv[i])));
break;
case eRegistryOutputFile:
i++;
PARAMETER_CHECK(i < argc);
IFW32FALSE_EXIT(this->buffRegResultTarget.Win32Assign(argv[i], ::wcslen(argv[i])));
break;
default:
case eUnknownOption:
PARAMETER_CHECK(false);
break;
}
}
if (this->buffWinsxs.Cch() == 0)
{
IFW32FALSE_EXIT(::SxspGetAssemblyRootDirectory(this->buffWinsxs));
}
#if SXSP_TOOL_KNOWS_ABOUT_BUILD
fNotFound = false;
IFW32FALSE_EXIT(::SxspQueryEnvironmentVariable(L"_BuildArch", this->buffBuildArch, fNotFound));
if (this->DirectoriesToInstall.GetSize() == 0)
{
CTinyStringBuffer BasePath;
CTinyStringBuffer ToInstall;
fNotFound = false;
IFW32FALSE_EXIT(::SxspQueryEnvironmentVariable(L"_ntpostbld", BasePath, fNotFound));
if (fNotFound)
{
IFW32FALSE_EXIT(::SxspQueryEnvironmentVariable(L"_nttree", BasePath, fNotFound));
if (fNotFound)
{
wprintf(L"Unable to find environment variable _nttree, and no source directories set.\r\n");
ORIGINATE_WIN32_FAILURE_AND_EXIT(NoDirectories, ERROR_INVALID_PARAMETER);
}
}
IFW32FALSE_EXIT(ToInstall.Win32Assign(BasePath));
IFW32FALSE_EXIT(ToInstall.Win32AppendPathElement(L"asms", 4));
if (::GetFileAttributesW(ToInstall) != INVALID_FILE_ATTRIBUTES)
{
IFW32FALSE_EXIT(DirectoriesToInstall.Win32Append(ToInstall));
}
IFW32FALSE_EXIT(ToInstall.Win32Assign(BasePath));
IFW32FALSE_EXIT(ToInstall.Win32AppendPathElement(L"wowbins\\asms", NUMBER_OF(L"wowbins\\asms") - 1));
if (::GetFileAttributesW(ToInstall) != INVALID_FILE_ATTRIBUTES)
{
IFW32FALSE_EXIT(DirectoriesToInstall.Win32Append(ToInstall));
}
IFW32FALSE_EXIT(ToInstall.Win32Assign(BasePath));
IFW32FALSE_EXIT(ToInstall.Win32AppendPathElement(L"wowbins\\wasms", NUMBER_OF(L"wowbins\\wasms") - 1));
if (::GetFileAttributesW(ToInstall) != INVALID_FILE_ATTRIBUTES)
{
IFW32FALSE_EXIT(DirectoriesToInstall.Win32Append(ToInstall));
}
}
#endif
FN_EPILOG;
}
#if SXSP_TOOL_KNOWS_ABOUT_BUILD
__declspec(selectany) extern const UNICODE_STRING x86String = RTL_CONSTANT_STRING(L"x86");
__declspec(selectany) extern const UNICODE_STRING i386String = RTL_CONSTANT_STRING(L"i386");
__declspec(selectany) extern const UNICODE_STRING BackslashString = RTL_CONSTANT_STRING(L"\\");
__declspec(selectany) extern const UNICODE_STRING asms01_dot_cabString = RTL_CONSTANT_STRING(L"asms01.cab");
__declspec(selectany) extern const UNICODE_STRING ProcessorBuildObjString = RTL_CONSTANT_STRING(SXSP_PROCESSOR_BUILD_OBJ_DIRECTORY_W);
__declspec(selectany) extern const UNICODE_STRING ProcessorInstallDirectoryString = RTL_CONSTANT_STRING(SXSP_PROCESSOR_INSTALL_DIRECTORY_W);
inline
BOOL
SxspConvertX86ToI386(
CBaseStringBuffer & buffProcessor
)
{
FN_PROLOG_WIN32;
if (::FusionpEqualStringsI(buffProcessor, x86String.Buffer, RTL_STRING_GET_LENGTH_CHARS(&x86String)))
{
IFW32FALSE_EXIT(buffProcessor.Win32Assign(&i386String));
}
FN_EPILOG;
}
#endif
BOOL
CSxspOfflineInstall::MiniSetupInstall(PCWSTR pcwszSourcePath)
{
FN_PROLOG_WIN32;
SXS_INSTALLW InstallParameters = {sizeof(InstallParameters)};
SXS_INSTALL_REFERENCEW InstallReference = {sizeof(InstallReference)};
g_fForceInOsSetupMode = TRUE;
InstallReference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL;
InstallReference.lpNonCanonicalData = this->buffNoncanonicalData;
if (this->buffCodeBaseURL.Cch() != 0)
{
InstallParameters.lpCodebaseURL = this->buffCodeBaseURL;
}
else
{
#if SXSP_TOOL_KNOWS_ABOUT_BUILD
if (this->buffBuildArch.Cch() == 0)
#endif
{
InstallParameters.lpCodebaseURL = pcwszSourcePath;
}
#if SXSP_TOOL_KNOWS_ABOUT_BUILD
else
{
CTinyStringBuffer buffCompactDiskBuildArch;
IFW32FALSE_EXIT(buffCompactDiskBuildArch.Win32Assign(this->buffBuildArch));
::SxspConvertX86ToI386(buffCompactDiskBuildArch);
IFW32FALSE_EXIT(this->buffCodeBaseURL.Win32Assign(&UnicodeString_URLHEAD_WINSOURCE));
IFW32FALSE_EXIT(this->buffCodeBaseURL.Win32Append(buffCompactDiskBuildArch));
IFW32FALSE_EXIT(this->buffCodeBaseURL.Win32Append(&BackslashString));
IFW32FALSE_EXIT(this->buffCodeBaseURL.Win32Append(&asms01_dot_cabString));
InstallParameters.lpCodebaseURL = this->buffCodeBaseURL;
}
#endif
}
InstallParameters.lpManifestPath = pcwszSourcePath;
InstallParameters.lpRefreshPrompt = SXSP_OFFLINE_INSTALL_REFRESH_PROMPT_PLACEHOLDER;
InstallParameters.lpReference = &InstallReference;
InstallParameters.dwFlags = SXS_INSTALL_FLAG_FROM_DIRECTORY |
SXS_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE |
SXS_INSTALL_FLAG_REFERENCE_VALID |
SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID |
SXS_INSTALL_FLAG_INSTALLED_BY_OSSETUP |
SXS_INSTALL_FLAG_NOT_TRANSACTIONAL |
SXS_INSTALL_FLAG_CODEBASE_URL_VALID;
if (::SxsInstallW(&InstallParameters))
{
wprintf(
L"(%ls) SxsInstallW of %ls completed\r\n",
static_cast<PCWSTR>(this->buffToolnameFromArgv0),
pcwszSourcePath
);
FN_SUCCESSFUL_EXIT();
}
else
{
wprintf(
L"(%ls) SxsInstallW of %ls failed, lasterror 0x%lx\r\n",
static_cast<PCWSTR>(this->buffToolnameFromArgv0),
pcwszSourcePath,
::GetLastError()
);
ORIGINATE_WIN32_FAILURE_AND_EXIT(SxsInstallW, ::FusionpGetLastWin32Error());
}
FN_EPILOG;
}
HKEY g_hkRedirectionRoot;
SXSP_LOCALLY_UNIQUE_ID g_uuidRedirection;
BOOL SxspTurnOnRedirection(CStringBuffer &RegPath);
BOOL SxspTurnOffRedirection(const CStringBuffer &RegPath);
BOOL
WriteFileString(
HANDLE hFile,
PCSTR pcszFormat,
...
)
{
FN_PROLOG_WIN32;
CHAR cBuffer[2048];
PSTR pszBuffer = cBuffer;
DWORD dwBuffer = NUMBER_OF(cBuffer);
DWORD dwWritten;
CSmartArrayPtr<CHAR> SmartArray;
int iRequired = 0;
int iWritten = 0;
va_list va;
va_start(va, pcszFormat);
iRequired = ::_vscprintf(pcszFormat, va);
if (iRequired > dwBuffer)
{
IFW32FALSE_EXIT(SmartArray.Win32Allocate(iRequired + 1, __FILE__, __LINE__));
pszBuffer = SmartArray;
dwBuffer = iRequired;
}
iWritten = ::_vsnprintf(pszBuffer, dwBuffer - 1, pcszFormat, va);
pszBuffer[iWritten] = '\0';
pszBuffer[dwBuffer - 1] = '\0';
IFW32FALSE_EXIT(::WriteFile(hFile, pszBuffer, iWritten, &dwWritten, NULL));
FN_EPILOG;
}
BOOL
FindRegHelper(
HANDLE hFile,
CBaseStringBuffer &FullPath,
CBaseStringBuffer &Child,
CRegKey &hkSourceKey
)
{
FN_PROLOG_WIN32;
DWORD iIndex = 0;
CTinyStringBuffer tsb;
//
// First, enum the values in this key.
//
do
{
BOOL fDone = FALSE;
DWORD dwType = 0;
IFW32FALSE_EXIT(hkSourceKey.EnumValue(iIndex++, Child, &dwType, &fDone));
if (fDone)
{
break;
}
else
{
//
// Form up the output
//
::WriteFileString(hFile, "HKLM,\"%S\",\"%S\",",
static_cast<PCWSTR>(FullPath),
static_cast<PCWSTR>(Child));
if (dwType == REG_SZ)
{
IFW32FALSE_EXIT(::FusionpRegQuerySzValueEx(0, hkSourceKey, Child, tsb));
//
// if it contains any quotes, go one character at a time,
// doubling quotes
//
// if it has no quotes, write it all at once
//
if (::wcschr(tsb, '\"') != NULL)
{
IFW32FALSE_EXIT(::WriteFileString(hFile, "0x%08lx,\"",
FLG_ADDREG_TYPE_SZ | FLG_ADDREG_64BITKEY));
for (SIZE_T d = 0; d < tsb.Cch(); d++)
{
if (tsb[d] == '\"')
IFW32FALSE_EXIT(::WriteFileString(hFile, "\"\""));
else
IFW32FALSE_EXIT(::WriteFileString(hFile, "%c", tsb[d]));
}
IFW32FALSE_EXIT(::WriteFileString(hFile, "\"\r\n"));
}
else
{
IFW32FALSE_EXIT(::WriteFileString(hFile, "0x%08lx,\"%S\"\r\n",
FLG_ADDREG_TYPE_SZ | FLG_ADDREG_64BITKEY,
static_cast<PCWSTR>(tsb)));
}
}
else if (dwType == REG_DWORD)
{
DWORD dwValue = 0;
IFW32FALSE_EXIT(
::FusionpRegQueryDwordValueEx(
FUSIONP_REG_QUERY_DWORD_MISSING_VALUE_IS_FAILURE,
hkSourceKey,
Child,
&dwValue,
0));
IFW32FALSE_EXIT(::WriteFileString(hFile, "0x%08lx,0x%08lx\r\n",
FLG_ADDREG_TYPE_DWORD | FLG_ADDREG_64BITKEY,
dwValue));
}
else if (dwType == REG_BINARY)
{
CFusionArray<BYTE> bBytes;
IFW32FALSE_EXIT(::FusionpRegQueryBinaryValueEx(0, hkSourceKey, Child, bBytes));
IFW32FALSE_EXIT(::WriteFileString(
hFile,
"0x%08lx,",
FLG_ADDREG_TYPE_BINARY | FLG_ADDREG_64BITKEY));
for (SIZE_T c = 0; c < bBytes.GetSize(); c++)
{
if (c == 0)
IFW32FALSE_EXIT(::WriteFileString(hFile, "%02x", bBytes[c]));
else
IFW32FALSE_EXIT(::WriteFileString(hFile, ",%02x", bBytes[c]));
}
IFW32FALSE_EXIT(::WriteFileString(hFile, "\r\n"));
}
else
{
ORIGINATE_WIN32_FAILURE_AND_EXIT(ErrorInvalidType, ERROR_INVALID_PARAMETER);
}
}
}
while (true);
//
// Now enum the keys
//
iIndex = 0;
do
{
BOOL fDone = FALSE;
IFW32FALSE_EXIT(hkSourceKey.EnumKey(iIndex++, Child, NULL, &fDone));
if (fDone)
{
break;
}
//
// Append this to the current key,
else
{
const SIZE_T cch = FullPath.Cch();
CRegKey ThisKey;
//
// no leading slash
//
if (FullPath.Cch() == 0)
{
IFW32FALSE_EXIT(FullPath.Win32Append(Child));
}
else
{
IFW32FALSE_EXIT(FullPath.Win32AppendPathElement(Child));
}
IFW32FALSE_EXIT(hkSourceKey.OpenSubKey(ThisKey, Child, KEY_READ, 0));
IFW32FALSE_EXIT(::FindRegHelper(hFile, FullPath, Child, ThisKey));
FullPath.Left(cch);
}
}
while (true);
FN_EPILOG;
}
BOOL
CSxspOfflineInstall::FindAndWriteRegistryResults(
const CBaseStringBuffer &OutputFile,
HKEY hkActualBase
)
{
FN_PROLOG_WIN32;
CTinyStringBuffer Path;
CTinyStringBuffer ChildTemp;
CFusionFile hOutputFile;
CRegKey hkBase = hkActualBase;
IFW32FALSE_EXIT(hOutputFile.Win32CreateFile(OutputFile, GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS));
IFW32FALSE_EXIT(::WriteFileString(hOutputFile,
"[Version]\r\n"
"Signature = \"$Windows NT$\"\r\n\r\n"
// stampinf inserts DriverVer here, like other hiv*.inf
));
if (this->fDefaultInstall)
{
IFW32FALSE_EXIT(::WriteFileString(hOutputFile,
"[fDefaultInstall]\r\n"
"AddReg=AddReg\r\n\r\n"
));
}
IFW32FALSE_EXIT(::WriteFileString(hOutputFile,
"[AddReg]\r\n"
));
IFW32FALSE_EXIT(::FindRegHelper(hOutputFile, Path, ChildTemp, hkBase));
FN_EPILOG;
}
BOOL
CSxspOfflineInstall::SxsOfflineInstall(
int argc,
wchar_t ** argv
)
{
BOOL fSuccess = FALSE;
int i = 0;
DWORD FileAttributes = 0;
BOOLEAN AppendWinsxs = TRUE;
bool fFound = false;
CTinyStringBuffer buffArgv0;
CTinyStringBuffer CommandLineFromFileW;
g_SxsOfflineInstall = TRUE;
if (argc < 2)
{
this->DisplayUsage();
::FusionpSetLastWin32Error(ERROR_INVALID_PARAMETER);
goto Exit;
}
if (!::SxsDllMain(::GetModuleHandleW(NULL), DLL_PROCESS_ATTACH, NULL))
goto Exit;
if (!buffArgv0.Win32Assign(argv[0], ::wcslen(argv[0])))
goto Exit;
if (!buffArgv0.Win32GetLastPathElement(this->buffToolnameFromArgv0))
goto Exit;
if (!this->Initialize() || !this->LoadParameters(argc - 1, argv + 1))
{
this->DisplayUsage();
::FusionpSetLastWin32Error(ERROR_INVALID_PARAMETER);
goto Exit;
}
::SxspDebug(SXS_DEBUG_SET_ASSEMBLY_STORE_ROOT, 0, this->buffWinsxs, NULL);
g_WriteRegistryAnyway = TRUE;
::FusionpCreateDirectories(this->buffWinsxs, this->buffWinsxs.Cch());
::SxspTurnOnRedirection(this->buffHostRegPathTemp);
for (int i = 0; i < this->DirectoriesToInstall.GetSize(); i++)
{
CStringBuffer &Buffer = this->DirectoriesToInstall[i];
if (!this->fIgnoreMissingDirectories
|| ::GetFileAttributesW(Buffer) != INVALID_FILE_ATTRIBUTES)
{
this->MiniSetupInstall(Buffer);
}
}
::SxspDeleteShortNamesInRegistry();
if (this->buffRegResultTarget.Cch() != 0)
{
this->FindAndWriteRegistryResults(this->buffRegResultTarget, HKEY_LOCAL_MACHINE);
}
::SxspTurnOffRedirection(this->buffHostRegPathTemp);
fSuccess = TRUE;
Exit:
return fSuccess;
}
int
__cdecl
wmain(
int argc,
wchar_t ** argv
)
{
CSxspOfflineInstall This;
DWORD dwWin32Error = NO_ERROR;
::FusionpSetLastWin32Error(dwWin32Error);
if (!This.SxsOfflineInstall(argc, argv))
{
dwWin32Error = ::FusionpGetLastWin32Error();
if (dwWin32Error == NO_ERROR)
dwWin32Error = ERROR_INTERNAL_ERROR;
}
return dwWin32Error;
}
BOOL
SxspTurnOnRedirection(CStringBuffer &RegPath)
{
FN_PROLOG_WIN32;
CSmallStringBuffer UniqueId;
IFW32FALSE_EXIT(::SxspCreateLocallyUniqueId(&g_uuidRedirection));
IFW32FALSE_EXIT(::SxspFormatLocallyUniqueId(g_uuidRedirection, UniqueId));
IFW32FALSE_EXIT(RegPath.Win32Assign(L"SxsOfflineInstall", NUMBER_OF(L"SxsOfflineInstall") - 1));
IFW32FALSE_EXIT(RegPath.Win32AppendPathElement(UniqueId));
IFREGFAILED_EXIT(::RegCreateKeyExW(
HKEY_CURRENT_USER,
RegPath,
0,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
&g_hkRedirectionRoot,
NULL));
IFREGFAILED_EXIT(::RegOverridePredefKey(HKEY_LOCAL_MACHINE, g_hkRedirectionRoot));
FN_EPILOG;
}
BOOL
SxspTurnOffRedirection(const CStringBuffer &RegPath)
{
FN_PROLOG_WIN32;
CRegKey TempKey(g_hkRedirectionRoot);
CSmallStringBuffer Uid;
IFW32FALSE_EXIT(TempKey.DestroyKeyTree());
IFREGFAILED_EXIT(::RegOverridePredefKey(HKEY_LOCAL_MACHINE, NULL));
IFREGFAILED_EXIT(::RegDeleteKeyW(HKEY_CURRENT_USER, RegPath));
IFREGFAILED_EXIT(::RegDeleteKeyW(HKEY_CURRENT_USER, L"SxsOfflineInstall"));
FN_EPILOG;
}
#else // free builds have known problems
int __cdecl wmain(int argc, wchar_t ** argv)
{
fputs("free build does not work, sorry\n", stderr);
return -1;
}
#endif