Adds support for an unattend.xml file to control the Windows installer options.

This commit is contained in:
Steve Dower 2015-07-18 09:28:19 -07:00
parent a3d03ec6b1
commit 2434aa24e0
2 changed files with 106 additions and 1 deletions

View File

@ -171,6 +171,20 @@ display a simplified initial page and disallow customization::
recommended for per-user installs when there is also a system-wide installation recommended for per-user installs when there is also a system-wide installation
that included the launcher.) that included the launcher.)
The options listed above can also be provided in a file named ``unattend.xml``
alongside the executable. This file specifies a list of options and values.
When a value is provided as an attribute, it will be converted to a number if
possible. Values provided as element text are always left as strings. This
example file sets the same options and the previous example::
<Options>
<Option Name="InstallAllUsers" Value="no" />
<Option Name="Include_launcher" Value="0" />
<Option Name="Include_test" Value="no" />
<Option Name="SimpleInstall" Value="yes" />
<Option Name="SimpleInstallDescription">Just for me, no test suite</Option>
</Options>
.. _install-layout-option: .. _install-layout-option:
Installing Without Downloading Installing Without Downloading

View File

@ -1249,6 +1249,92 @@ private:
return hr; return hr;
} }
//
// ParseVariablesFromUnattendXml - reads options from unattend.xml if it
// exists
//
HRESULT ParseVariablesFromUnattendXml() {
HRESULT hr = S_OK;
LPWSTR sczUnattendXmlPath = nullptr;
IXMLDOMDocument *pixdUnattend = nullptr;
IXMLDOMNodeList *pNodes = nullptr;
IXMLDOMNode *pNode = nullptr;
long cNodes;
DWORD dwAttr;
LPWSTR scz = nullptr;
BOOL bValue;
int iValue;
BOOL tryConvert;
BSTR bstrValue = nullptr;
hr = BalFormatString(L"[WixBundleOriginalSourceFolder]unattend.xml", &sczUnattendXmlPath);
BalExitOnFailure(hr, "Failed to calculate path to unattend.xml");
if (!FileExistsEx(sczUnattendXmlPath, &dwAttr)) {
BalLog(BOOTSTRAPPER_LOG_LEVEL_VERBOSE, "Did not find %ls", sczUnattendXmlPath);
hr = S_FALSE;
goto LExit;
}
hr = XmlLoadDocumentFromFile(sczUnattendXmlPath, &pixdUnattend);
BalExitOnFailure1(hr, "Failed to read %ls", sczUnattendXmlPath);
// get the list of variables users have overridden
hr = XmlSelectNodes(pixdUnattend, L"/Options/Option", &pNodes);
if (S_FALSE == hr) {
ExitFunction1(hr = S_OK);
}
BalExitOnFailure(hr, "Failed to select option nodes.");
hr = pNodes->get_length((long*)&cNodes);
BalExitOnFailure(hr, "Failed to get option node count.");
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Reading settings from %ls", sczUnattendXmlPath);
for (DWORD i = 0; i < cNodes; ++i) {
hr = XmlNextElement(pNodes, &pNode, nullptr);
BalExitOnFailure(hr, "Failed to get next node.");
// @Name
hr = XmlGetAttributeEx(pNode, L"Name", &scz);
BalExitOnFailure(hr, "Failed to get @Name.");
tryConvert = TRUE;
hr = XmlGetAttribute(pNode, L"Value", &bstrValue);
if (FAILED(hr) || !bstrValue || !*bstrValue) {
hr = XmlGetText(pNode, &bstrValue);
tryConvert = FALSE;
}
BalExitOnFailure(hr, "Failed to get @Value.");
if (tryConvert &&
CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, bstrValue, -1, L"yes", -1)) {
_engine->SetVariableNumeric(scz, 1);
} else if (tryConvert &&
CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, bstrValue, -1, L"no", -1)) {
_engine->SetVariableNumeric(scz, 0);
} else if (tryConvert && ::StrToIntExW(bstrValue, STIF_DEFAULT, &iValue)) {
_engine->SetVariableNumeric(scz, iValue);
} else {
_engine->SetVariableString(scz, bstrValue);
}
ReleaseNullBSTR(bstrValue);
ReleaseNullStr(scz);
ReleaseNullObject(pNode);
}
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Finished reading from %ls", sczUnattendXmlPath);
LExit:
ReleaseObject(pNode);
ReleaseObject(pNodes);
ReleaseObject(pixdUnattend);
ReleaseStr(sczUnattendXmlPath);
return hr;
}
// //
// InitializeData - initializes all the package information. // InitializeData - initializes all the package information.
@ -1264,6 +1350,9 @@ private:
hr = ParseOverridableVariablesFromXml(pixdManifest); hr = ParseOverridableVariablesFromXml(pixdManifest);
BalExitOnFailure(hr, "Failed to read overridable variables."); BalExitOnFailure(hr, "Failed to read overridable variables.");
hr = ParseVariablesFromUnattendXml();
ExitOnFailure(hr, "Failed to read unattend.ini file.");
hr = ProcessCommandLine(&_language); hr = ProcessCommandLine(&_language);
ExitOnFailure(hr, "Unknown commandline parameters."); ExitOnFailure(hr, "Unknown commandline parameters.");
@ -1323,7 +1412,9 @@ private:
hr = StrAllocString(psczLanguage, &argv[i][0], 0); hr = StrAllocString(psczLanguage, &argv[i][0], 0);
BalExitOnFailure(hr, "Failed to copy language."); BalExitOnFailure(hr, "Failed to copy language.");
} } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"simple", -1)) {
_engine->SetVariableNumeric(L"SimpleInstall", 1);
}
} else if (_overridableVariables) { } else if (_overridableVariables) {
int value; int value;
const wchar_t* pwc = wcschr(argv[i], L'='); const wchar_t* pwc = wcschr(argv[i], L'=');