Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2434aa2

Browse files
committed
Adds support for an unattend.xml file to control the Windows installer options.
1 parent a3d03ec commit 2434aa2

2 files changed

Lines changed: 106 additions & 1 deletion

File tree

Doc/using/windows.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,20 @@ display a simplified initial page and disallow customization::
171171
recommended for per-user installs when there is also a system-wide installation
172172
that included the launcher.)
173173

174+
The options listed above can also be provided in a file named ``unattend.xml``
175+
alongside the executable. This file specifies a list of options and values.
176+
When a value is provided as an attribute, it will be converted to a number if
177+
possible. Values provided as element text are always left as strings. This
178+
example file sets the same options and the previous example::
179+
180+
<Options>
181+
<Option Name="InstallAllUsers" Value="no" />
182+
<Option Name="Include_launcher" Value="0" />
183+
<Option Name="Include_test" Value="no" />
184+
<Option Name="SimpleInstall" Value="yes" />
185+
<Option Name="SimpleInstallDescription">Just for me, no test suite</Option>
186+
</Options>
187+
174188
.. _install-layout-option:
175189

176190
Installing Without Downloading

Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1249,6 +1249,92 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
12491249
return hr;
12501250
}
12511251

1252+
//
1253+
// ParseVariablesFromUnattendXml - reads options from unattend.xml if it
1254+
// exists
1255+
//
1256+
HRESULT ParseVariablesFromUnattendXml() {
1257+
HRESULT hr = S_OK;
1258+
LPWSTR sczUnattendXmlPath = nullptr;
1259+
IXMLDOMDocument *pixdUnattend = nullptr;
1260+
IXMLDOMNodeList *pNodes = nullptr;
1261+
IXMLDOMNode *pNode = nullptr;
1262+
long cNodes;
1263+
DWORD dwAttr;
1264+
LPWSTR scz = nullptr;
1265+
BOOL bValue;
1266+
int iValue;
1267+
BOOL tryConvert;
1268+
BSTR bstrValue = nullptr;
1269+
1270+
hr = BalFormatString(L"[WixBundleOriginalSourceFolder]unattend.xml", &sczUnattendXmlPath);
1271+
BalExitOnFailure(hr, "Failed to calculate path to unattend.xml");
1272+
1273+
if (!FileExistsEx(sczUnattendXmlPath, &dwAttr)) {
1274+
BalLog(BOOTSTRAPPER_LOG_LEVEL_VERBOSE, "Did not find %ls", sczUnattendXmlPath);
1275+
hr = S_FALSE;
1276+
goto LExit;
1277+
}
1278+
1279+
hr = XmlLoadDocumentFromFile(sczUnattendXmlPath, &pixdUnattend);
1280+
BalExitOnFailure1(hr, "Failed to read %ls", sczUnattendXmlPath);
1281+
1282+
// get the list of variables users have overridden
1283+
hr = XmlSelectNodes(pixdUnattend, L"/Options/Option", &pNodes);
1284+
if (S_FALSE == hr) {
1285+
ExitFunction1(hr = S_OK);
1286+
}
1287+
BalExitOnFailure(hr, "Failed to select option nodes.");
1288+
1289+
hr = pNodes->get_length((long*)&cNodes);
1290+
BalExitOnFailure(hr, "Failed to get option node count.");
1291+
1292+
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Reading settings from %ls", sczUnattendXmlPath);
1293+
1294+
for (DWORD i = 0; i < cNodes; ++i) {
1295+
hr = XmlNextElement(pNodes, &pNode, nullptr);
1296+
BalExitOnFailure(hr, "Failed to get next node.");
1297+
1298+
// @Name
1299+
hr = XmlGetAttributeEx(pNode, L"Name", &scz);
1300+
BalExitOnFailure(hr, "Failed to get @Name.");
1301+
1302+
tryConvert = TRUE;
1303+
hr = XmlGetAttribute(pNode, L"Value", &bstrValue);
1304+
if (FAILED(hr) || !bstrValue || !*bstrValue) {
1305+
hr = XmlGetText(pNode, &bstrValue);
1306+
tryConvert = FALSE;
1307+
}
1308+
BalExitOnFailure(hr, "Failed to get @Value.");
1309+
1310+
if (tryConvert &&
1311+
CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, bstrValue, -1, L"yes", -1)) {
1312+
_engine->SetVariableNumeric(scz, 1);
1313+
} else if (tryConvert &&
1314+
CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, bstrValue, -1, L"no", -1)) {
1315+
_engine->SetVariableNumeric(scz, 0);
1316+
} else if (tryConvert && ::StrToIntExW(bstrValue, STIF_DEFAULT, &iValue)) {
1317+
_engine->SetVariableNumeric(scz, iValue);
1318+
} else {
1319+
_engine->SetVariableString(scz, bstrValue);
1320+
}
1321+
1322+
ReleaseNullBSTR(bstrValue);
1323+
ReleaseNullStr(scz);
1324+
ReleaseNullObject(pNode);
1325+
}
1326+
1327+
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Finished reading from %ls", sczUnattendXmlPath);
1328+
1329+
LExit:
1330+
ReleaseObject(pNode);
1331+
ReleaseObject(pNodes);
1332+
ReleaseObject(pixdUnattend);
1333+
ReleaseStr(sczUnattendXmlPath);
1334+
1335+
return hr;
1336+
}
1337+
12521338

12531339
//
12541340
// InitializeData - initializes all the package information.
@@ -1264,6 +1350,9 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
12641350
hr = ParseOverridableVariablesFromXml(pixdManifest);
12651351
BalExitOnFailure(hr, "Failed to read overridable variables.");
12661352

1353+
hr = ParseVariablesFromUnattendXml();
1354+
ExitOnFailure(hr, "Failed to read unattend.ini file.");
1355+
12671356
hr = ProcessCommandLine(&_language);
12681357
ExitOnFailure(hr, "Unknown commandline parameters.");
12691358

@@ -1323,7 +1412,9 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
13231412

13241413
hr = StrAllocString(psczLanguage, &argv[i][0], 0);
13251414
BalExitOnFailure(hr, "Failed to copy language.");
1326-
}
1415+
} else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"simple", -1)) {
1416+
_engine->SetVariableNumeric(L"SimpleInstall", 1);
1417+
}
13271418
} else if (_overridableVariables) {
13281419
int value;
13291420
const wchar_t* pwc = wcschr(argv[i], L'=');

0 commit comments

Comments
 (0)