main
cpp 670 lines 24.2 KB
Raw
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 #include "precomp.h"
4
5 // prototypes
6 static HRESULT ParsePackagesFromXml(
7 __in BAL_INFO_PACKAGES* pPackages,
8 __in IXMLDOMDocument* pixdManifest
9 );
10 static HRESULT ParseBalPackageInfoFromXml(
11 __in BAL_INFO_PACKAGES* pPackages,
12 __in IXMLDOMDocument* pixdManifest
13 );
14 static HRESULT ParseOverridableVariablesFromXml(
15 __in BAL_INFO_OVERRIDABLE_VARIABLES* pOverridableVariables,
16 __in IXMLDOMDocument* pixdManifest
17 );
18
19
20 DAPI_(HRESULT) BalInfoParseCommandLine(
21 __in BAL_INFO_COMMAND* pCommand,
22 __in const BOOTSTRAPPER_COMMAND* pBootstrapperCommand
23 )
24 {
25 HRESULT hr = S_OK;
26 int argc = 0;
27 LPWSTR* argv = NULL;
28 BOOL fUnknownArg = FALSE;
29
30 BalInfoUninitializeCommandLine(pCommand);
31
32 if (!pBootstrapperCommand->wzCommandLine || !*pBootstrapperCommand->wzCommandLine)
33 {
34 ExitFunction();
35 }
36
37 hr = AppParseCommandLine(pBootstrapperCommand->wzCommandLine, &argc, &argv);
38 BalExitOnFailure(hr, "Failed to parse command line.");
39
40 for (int i = 0; i < argc; ++i)
41 {
42 fUnknownArg = FALSE;
43
44 if (argv[i][0] == L'-' || argv[i][0] == L'/')
45 {
46 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"norestart", -1))
47 {
48 if (BAL_INFO_RESTART_UNKNOWN == pCommand->restart)
49 {
50 pCommand->restart = BAL_INFO_RESTART_NEVER;
51 }
52 }
53 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"forcerestart", -1))
54 {
55 if (BAL_INFO_RESTART_UNKNOWN == pCommand->restart)
56 {
57 pCommand->restart = BAL_INFO_RESTART_ALWAYS;
58 }
59 }
60 else
61 {
62 fUnknownArg = TRUE;
63 }
64 }
65 else
66 {
67 const wchar_t* pwc = wcschr(argv[i], L'=');
68 if (!pwc)
69 {
70 fUnknownArg = TRUE;
71 }
72 else
73 {
74 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pCommand->rgVariableNames), pCommand->cVariables, 1, sizeof(LPWSTR), 5);
75 BalExitOnFailure(hr, "Failed to ensure size for variable names.");
76
77 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pCommand->rgVariableValues), pCommand->cVariables, 1, sizeof(LPWSTR), 5);
78 BalExitOnFailure(hr, "Failed to ensure size for variable values.");
79
80 LPWSTR* psczVariableName = pCommand->rgVariableNames + pCommand->cVariables;
81 LPWSTR* psczVariableValue = pCommand->rgVariableValues + pCommand->cVariables;
82 pCommand->cVariables += 1;
83
84 hr = StrAllocString(psczVariableName, argv[i], pwc - argv[i]);
85 BalExitOnFailure(hr, "Failed to copy variable name.");
86
87 hr = StrAllocString(psczVariableValue, ++pwc, 0);
88 BalExitOnFailure(hr, "Failed to copy variable value.");
89 }
90 }
91
92 if (fUnknownArg)
93 {
94 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pCommand->rgUnknownArgs), pCommand->cUnknownArgs, 1, sizeof(LPWSTR), 5);
95 BalExitOnFailure(hr, "Failed to ensure size for unknown args.");
96
97 LPWSTR* psczArg = pCommand->rgUnknownArgs + pCommand->cUnknownArgs;
98 pCommand->cUnknownArgs += 1;
99
100 StrAllocString(psczArg, argv[i], 0);
101 BalExitOnFailure(hr, "Failed to copy unknown arg.");
102 }
103 }
104
105 LExit:
106 if (BAL_INFO_RESTART_UNKNOWN == pCommand->restart)
107 {
108 pCommand->restart = BOOTSTRAPPER_DISPLAY_FULL > pBootstrapperCommand->display ? BAL_INFO_RESTART_AUTOMATIC : BAL_INFO_RESTART_PROMPT;
109 }
110
111 if (argv)
112 {
113 AppFreeCommandLineArgs(argv);
114 }
115
116 return hr;
117 }
118
119 DAPI_(HRESULT) BalInfoParseFromXml(
120 __in BAL_INFO_BUNDLE* pBundle,
121 __in IXMLDOMDocument* pixdManifest
122 )
123 {
124 HRESULT hr = S_OK;
125 IXMLDOMNode* pNode = NULL;
126 BOOL fXmlFound = FALSE;
127
128 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixBundleProperties", &pNode);
129 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to select bundle information.");
130
131 if (fXmlFound)
132 {
133 hr = XmlGetYesNoAttribute(pNode, L"PerMachine", &pBundle->fPerMachine);
134 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to read bundle information per-machine.");
135
136 hr = XmlGetAttributeEx(pNode, L"DisplayName", &pBundle->sczName);
137 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to read bundle information display name.");
138
139 hr = XmlGetAttributeEx(pNode, L"LogPathVariable", &pBundle->sczLogVariable);
140 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to read bundle information log path variable.");
141 }
142
143 hr = ParseOverridableVariablesFromXml(&pBundle->overridableVariables, pixdManifest);
144 BalExitOnFailure(hr, "Failed to parse overridable variables from bootstrapper application data.");
145
146 hr = ParsePackagesFromXml(&pBundle->packages, pixdManifest);
147 BalExitOnFailure(hr, "Failed to parse package information from bootstrapper application data.");
148
149 hr = ParseBalPackageInfoFromXml(&pBundle->packages, pixdManifest);
150 BalExitOnFailure(hr, "Failed to parse bal package information from bootstrapper application data.");
151
152 LExit:
153 ReleaseObject(pNode);
154
155 return hr;
156 }
157
158
159 DAPI_(HRESULT) BalInfoAddRelatedBundleAsPackage(
160 __in BAL_INFO_PACKAGES* pPackages,
161 __in_z LPCWSTR wzId,
162 __in BOOTSTRAPPER_RELATION_TYPE relationType,
163 __in BOOL /*fPerMachine*/,
164 __out_opt BAL_INFO_PACKAGE** ppPackage
165 )
166 {
167 HRESULT hr = S_OK;
168 BAL_INFO_PACKAGE_TYPE type = BAL_INFO_PACKAGE_TYPE_UNKNOWN;
169 BAL_INFO_PACKAGE* pPackage = NULL;
170
171 // Ensure we have a supported relation type.
172 switch (relationType)
173 {
174 case BOOTSTRAPPER_RELATION_ADDON:
175 type = BAL_INFO_PACKAGE_TYPE_BUNDLE_ADDON;
176 break;
177
178 case BOOTSTRAPPER_RELATION_PATCH:
179 type = BAL_INFO_PACKAGE_TYPE_BUNDLE_PATCH;
180 break;
181
182 case BOOTSTRAPPER_RELATION_UPGRADE:
183 type = BAL_INFO_PACKAGE_TYPE_BUNDLE_UPGRADE;
184 break;
185
186 default:
187 ExitWithRootFailure(hr, E_INVALIDARG, "Unknown related bundle type: %u", relationType);
188 }
189
190 // Check to see if the bundle is already in the list of packages.
191 for (DWORD i = 0; i < pPackages->cPackages; ++i)
192 {
193 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzId, -1, pPackages->rgPackages[i].sczId, -1))
194 {
195 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS));
196 }
197 }
198
199 // Add the related bundle as a package.
200 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPackages->rgPackages), pPackages->cPackages + 1, sizeof(BAL_INFO_PACKAGE), 2);
201 ExitOnFailure(hr, "Failed to allocate memory for related bundle package information.");
202
203 pPackage = pPackages->rgPackages + pPackages->cPackages;
204 ++pPackages->cPackages;
205
206 hr = StrAllocString(&pPackage->sczId, wzId, 0);
207 ExitOnFailure(hr, "Failed to copy related bundle package id.");
208
209 pPackage->type = type;
210
211 // TODO: try to look up the DisplayName and Description in Add/Remove Programs with the wzId.
212
213 if (ppPackage)
214 {
215 *ppPackage = pPackage;
216 }
217
218 LExit:
219 return hr;
220 }
221
222
223 DAPI_(HRESULT) BalInfoAddUpdateBundleAsPackage(
224 __in BAL_INFO_PACKAGES* pPackages,
225 __in_z LPCWSTR wzId,
226 __out_opt BAL_INFO_PACKAGE** ppPackage
227 )
228 {
229 HRESULT hr = S_OK;
230 BAL_INFO_PACKAGE* pPackage = NULL;
231
232 // Check to see if the bundle is already in the list of packages.
233 for (DWORD i = 0; i < pPackages->cPackages; ++i)
234 {
235 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzId, -1, pPackages->rgPackages[i].sczId, -1))
236 {
237 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS));
238 }
239 }
240
241 // Add the update bundle as a package.
242 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPackages->rgPackages), pPackages->cPackages + 1, sizeof(BAL_INFO_PACKAGE), 2);
243 ExitOnFailure(hr, "Failed to allocate memory for update bundle package information.");
244
245 pPackage = pPackages->rgPackages + pPackages->cPackages;
246 ++pPackages->cPackages;
247
248 hr = StrAllocString(&pPackage->sczId, wzId, 0);
249 ExitOnFailure(hr, "Failed to copy update bundle package id.");
250
251 pPackage->type = BAL_INFO_PACKAGE_TYPE_BUNDLE_UPDATE;
252
253 if (ppPackage)
254 {
255 *ppPackage = pPackage;
256 }
257
258 LExit:
259 return hr;
260 }
261
262
263 DAPI_(HRESULT) BalInfoFindPackageById(
264 __in BAL_INFO_PACKAGES* pPackages,
265 __in LPCWSTR wzId,
266 __out BAL_INFO_PACKAGE** ppPackage
267 )
268 {
269 *ppPackage = NULL;
270
271 for (DWORD i = 0; i < pPackages->cPackages; ++i)
272 {
273 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzId, -1, pPackages->rgPackages[i].sczId, -1))
274 {
275 *ppPackage = pPackages->rgPackages + i;
276 break;
277 }
278 }
279
280 return *ppPackage ? S_OK : E_NOTFOUND;
281 }
282
283
284 DAPI_(void) BalInfoUninitialize(
285 __in BAL_INFO_BUNDLE* pBundle
286 )
287 {
288 for (DWORD i = 0; i < pBundle->packages.cPackages; ++i)
289 {
290 ReleaseStr(pBundle->packages.rgPackages[i].sczDisplayName);
291 ReleaseStr(pBundle->packages.rgPackages[i].sczDescription);
292 ReleaseStr(pBundle->packages.rgPackages[i].sczId);
293 ReleaseStr(pBundle->packages.rgPackages[i].sczDisplayInternalUICondition);
294 ReleaseStr(pBundle->packages.rgPackages[i].sczProductCode);
295 ReleaseStr(pBundle->packages.rgPackages[i].sczUpgradeCode);
296 ReleaseStr(pBundle->packages.rgPackages[i].sczVersion);
297 ReleaseStr(pBundle->packages.rgPackages[i].sczInstallCondition);
298 ReleaseStr(pBundle->packages.rgPackages[i].sczRepairCondition);
299 ReleaseStr(pBundle->packages.rgPackages[i].sczPrereqLicenseFile);
300 ReleaseStr(pBundle->packages.rgPackages[i].sczPrereqLicenseUrl);
301 }
302
303 ReleaseMem(pBundle->packages.rgPackages);
304
305 for (DWORD i = 0; i < pBundle->overridableVariables.cVariables; ++i)
306 {
307 ReleaseStr(pBundle->overridableVariables.rgVariables[i].sczName);
308 }
309
310 ReleaseMem(pBundle->overridableVariables.rgVariables);
311 ReleaseDict(pBundle->overridableVariables.sdVariables);
312
313 ReleaseStr(pBundle->sczName);
314 ReleaseStr(pBundle->sczLogVariable);
315 memset(pBundle, 0, sizeof(BAL_INFO_BUNDLE));
316 }
317
318
319 DAPI_(void) BalInfoUninitializeCommandLine(
320 __in BAL_INFO_COMMAND* pCommand
321 )
322 {
323 for (DWORD i = 0; i < pCommand->cUnknownArgs; ++i)
324 {
325 ReleaseNullStrSecure(pCommand->rgUnknownArgs[i]);
326 }
327
328 ReleaseMem(pCommand->rgUnknownArgs);
329
330 for (DWORD i = 0; i < pCommand->cVariables; ++i)
331 {
332 ReleaseNullStrSecure(pCommand->rgVariableNames[i]);
333 ReleaseNullStrSecure(pCommand->rgVariableValues[i]);
334 }
335
336 ReleaseMem(pCommand->rgVariableNames);
337 ReleaseMem(pCommand->rgVariableValues);
338
339 memset(pCommand, 0, sizeof(BAL_INFO_COMMAND));
340 }
341
342
343 DAPI_(HRESULT) BalSetOverridableVariablesFromEngine(
344 __in BAL_INFO_OVERRIDABLE_VARIABLES* pOverridableVariables,
345 __in BAL_INFO_COMMAND* pCommand,
346 __in IBootstrapperEngine* pEngine
347 )
348 {
349 HRESULT hr = S_OK;
350 BAL_INFO_OVERRIDABLE_VARIABLE* pOverridableVariable = NULL;
351
352 for (DWORD i = 0; i < pCommand->cVariables; ++i)
353 {
354 LPCWSTR wzVariableName = pCommand->rgVariableNames[i];
355 LPCWSTR wzVariableValue = pCommand->rgVariableValues[i];
356
357 hr = DictGetValue(pOverridableVariables->sdVariables, wzVariableName, reinterpret_cast<void**>(&pOverridableVariable));
358 if (E_NOTFOUND == hr || E_INVALIDARG == hr)
359 {
360 BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Ignoring attempt to set non-overridable variable: '%ls'.", wzVariableName);
361 hr = S_OK;
362 continue;
363 }
364 BalExitOnFailure(hr, "Failed to check the dictionary of overridable variables.");
365
366 hr = pEngine->SetVariableString(pOverridableVariable->sczName, wzVariableValue, FALSE);
367 BalExitOnFailure(hr, "Failed to set variable: '%ls'.", pOverridableVariable->sczName);
368 }
369
370 LExit:
371 return hr;
372 }
373
374
375 static HRESULT ParsePackagesFromXml(
376 __in BAL_INFO_PACKAGES* pPackages,
377 __in IXMLDOMDocument* pixdManifest
378 )
379 {
380 HRESULT hr = S_OK;
381 IXMLDOMNodeList* pNodeList = NULL;
382 IXMLDOMNode* pNode = NULL;
383 BAL_INFO_PACKAGE* prgPackages = NULL;
384 DWORD cPackages = 0;
385 LPWSTR scz = NULL;
386 BOOL fXmlFound = FALSE;
387
388 hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixPackageProperties", &pNodeList);
389 ExitOnFailure(hr, "Failed to select all packages.");
390
391 hr = pNodeList->get_length(reinterpret_cast<long*>(&cPackages));
392 ExitOnFailure(hr, "Failed to get the package count.");
393
394 prgPackages = static_cast<BAL_INFO_PACKAGE*>(MemAlloc(sizeof(BAL_INFO_PACKAGE) * cPackages, TRUE));
395 ExitOnNull(prgPackages, hr, E_OUTOFMEMORY, "Failed to allocate memory for packages.");
396
397 DWORD iPackage = 0;
398 while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL)))
399 {
400 hr = XmlGetAttributeEx(pNode, L"Package", &prgPackages[iPackage].sczId);
401 ExitOnRequiredXmlQueryFailure(hr, "Failed to get package identifier for package.");
402
403 hr = XmlGetAttributeEx(pNode, L"DisplayName", &prgPackages[iPackage].sczDisplayName);
404 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get display name for package.");
405
406 hr = XmlGetAttributeEx(pNode, L"Description", &prgPackages[iPackage].sczDescription);
407 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get description for package.");
408
409 hr = XmlGetAttributeEx(pNode, L"PackageType", &scz);
410 ExitOnRequiredXmlQueryFailure(hr, "Failed to get package type for package.");
411
412 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Bundle", -1, scz, -1))
413 {
414 prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_BUNDLE_CHAIN;
415 }
416 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Exe", -1, scz, -1))
417 {
418 prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_EXE;
419 }
420 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msi", -1, scz, -1))
421 {
422 prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSI;
423 }
424 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msp", -1, scz, -1))
425 {
426 prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSP;
427 }
428 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msu", -1, scz, -1))
429 {
430 prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSU;
431 }
432
433 hr = XmlGetYesNoAttribute(pNode, L"Permanent", &prgPackages[iPackage].fPermanent);
434 ExitOnRequiredXmlQueryFailure(hr, "Failed to get permanent setting for package.");
435
436 hr = XmlGetYesNoAttribute(pNode, L"Vital", &prgPackages[iPackage].fVital);
437 ExitOnRequiredXmlQueryFailure(hr, "Failed to get vital setting for package.");
438
439 hr = XmlGetAttributeEx(pNode, L"ProductCode", &prgPackages[iPackage].sczProductCode);
440 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get product code for package.");
441
442 hr = XmlGetAttributeEx(pNode, L"UpgradeCode", &prgPackages[iPackage].sczUpgradeCode);
443 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get upgrade code for package.");
444
445 hr = XmlGetAttributeEx(pNode, L"Version", &prgPackages[iPackage].sczVersion);
446 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get version for package.");
447
448 hr = XmlGetAttributeEx(pNode, L"InstallCondition", &prgPackages[iPackage].sczInstallCondition);
449 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get install condition for package.");
450
451 hr = XmlGetAttributeEx(pNode, L"RepairCondition", &prgPackages[iPackage].sczRepairCondition);
452 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get repair condition for package.");
453
454 hr = XmlGetAttributeEx(pNode, L"Cache", &scz);
455 ExitOnRequiredXmlQueryFailure(hr, "Failed to get cache type for package.");
456
457 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, scz, -1, L"remove", -1))
458 {
459 prgPackages[iPackage].cacheType = BOOTSTRAPPER_CACHE_TYPE_REMOVE;
460 }
461 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, scz, -1, L"keep", -1))
462 {
463 prgPackages[iPackage].cacheType = BOOTSTRAPPER_CACHE_TYPE_KEEP;
464 }
465 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, scz, -1, L"force", -1))
466 {
467 prgPackages[iPackage].cacheType = BOOTSTRAPPER_CACHE_TYPE_FORCE;
468 }
469
470 ++iPackage;
471 ReleaseNullObject(pNode);
472 }
473 ExitOnFailure(hr, "Failed to parse all package property elements.");
474
475 if (S_FALSE == hr)
476 {
477 hr = S_OK;
478 }
479
480 pPackages->cPackages = cPackages;
481 pPackages->rgPackages = prgPackages;
482 prgPackages = NULL;
483
484 LExit:
485 ReleaseStr(scz);
486 ReleaseMem(prgPackages);
487 ReleaseObject(pNode);
488 ReleaseObject(pNodeList);
489
490 return hr;
491 }
492
493
494 static HRESULT ParseBalPackageInfoFromXml(
495 __in BAL_INFO_PACKAGES* pPackages,
496 __in IXMLDOMDocument* pixdManifest
497 )
498 {
499 HRESULT hr = S_OK;
500 IXMLDOMNodeList* pNodeList = NULL;
501 IXMLDOMNode* pNode = NULL;
502 LPWSTR scz = NULL;
503 BAL_INFO_PACKAGE* pPackage = NULL;
504 BOOL fXmlFound = FALSE;
505
506 hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixBalPackageInfo", &pNodeList);
507 ExitOnFailure(hr, "Failed to select all packages.");
508
509 while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL)))
510 {
511 hr = XmlGetAttributeEx(pNode, L"PackageId", &scz);
512 ExitOnRequiredXmlQueryFailure(hr, "Failed to get package identifier for WixBalPackageInfo.");
513
514 hr = BalInfoFindPackageById(pPackages, scz, &pPackage);
515 ExitOnFailure(hr, "Failed to find package specified in WixBalPackageInfo: %ls", scz);
516
517 hr = XmlGetAttributeEx(pNode, L"DisplayInternalUICondition", &pPackage->sczDisplayInternalUICondition);
518 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get DisplayInternalUICondition setting for package.");
519
520 hr = XmlGetAttributeEx(pNode, L"PrimaryPackageType", &scz);
521 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get PrimaryPackageType setting for package.");
522
523 if (fXmlFound)
524 {
525 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"default", -1))
526 {
527 pPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_DEFAULT;
528 }
529 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"x86", -1))
530 {
531 pPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X86;
532 }
533 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"x64", -1))
534 {
535 pPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X64;
536 }
537 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"arm64", -1))
538 {
539 pPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_ARM64;
540 }
541 else
542 {
543 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for WixBalPackageInfo/@PrimaryPackageType: %ls", scz);
544 }
545 }
546
547 ReleaseNullObject(pNode);
548 }
549 ExitOnFailure(hr, "Failed to parse all WixBalPackageInfo elements.");
550
551 hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixPrereqInformation", &pNodeList);
552 ExitOnFailure(hr, "Failed to select all packages.");
553
554 while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL)))
555 {
556 hr = XmlGetAttributeEx(pNode, L"PackageId", &scz);
557 ExitOnRequiredXmlQueryFailure(hr, "Failed to get package identifier for WixPrereqInformation.");
558
559 hr = BalInfoFindPackageById(pPackages, scz, &pPackage);
560 ExitOnFailure(hr, "Failed to find package specified in WixPrereqInformation: %ls", scz);
561
562 pPackage->fPrereqPackage = TRUE;
563
564 hr = XmlGetAttributeEx(pNode, L"LicenseFile", &pPackage->sczPrereqLicenseFile);
565 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get LicenseFile setting for prereq package.");
566
567 hr = XmlGetAttributeEx(pNode, L"LicenseUrl", &pPackage->sczPrereqLicenseUrl);
568 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get LicenseUrl setting for prereq package.");
569
570 ReleaseNullObject(pNode);
571 }
572 ExitOnFailure(hr, "Failed to parse all WixPrereqInformation elements.");
573
574 if (S_FALSE == hr)
575 {
576 hr = S_OK;
577 }
578
579 LExit:
580 ReleaseStr(scz);
581 ReleaseObject(pNode);
582 ReleaseObject(pNodeList);
583
584 return hr;
585 }
586
587
588 static HRESULT ParseOverridableVariablesFromXml(
589 __in BAL_INFO_OVERRIDABLE_VARIABLES* pOverridableVariables,
590 __in IXMLDOMDocument* pixdManifest
591 )
592 {
593 HRESULT hr = S_OK;
594 IXMLDOMNode* pCommandLineNode = NULL;
595 BOOL fXmlFound = FALSE;
596 LPWSTR scz = NULL;
597 IXMLDOMNode* pNode = NULL;
598 IXMLDOMNodeList* pNodes = NULL;
599 BAL_INFO_OVERRIDABLE_VARIABLE* pOverridableVariable = NULL;
600
601 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixStdbaCommandLine", &pCommandLineNode);
602 ExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to select command line information.");
603
604 if (!fXmlFound)
605 {
606 pOverridableVariables->commandLineType = BAL_INFO_VARIABLE_COMMAND_LINE_TYPE_CASE_SENSITIVE;
607 }
608 else
609 {
610 // @Variables
611 hr = XmlGetAttributeEx(pCommandLineNode, L"VariableType", &scz);
612 ExitOnRequiredXmlQueryFailure(hr, "Failed to get command line variable type.");
613
614 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"caseInsensitive", -1))
615 {
616 pOverridableVariables->commandLineType = BAL_INFO_VARIABLE_COMMAND_LINE_TYPE_CASE_INSENSITIVE;
617 }
618 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"caseSensitive", -1))
619 {
620 pOverridableVariables->commandLineType = BAL_INFO_VARIABLE_COMMAND_LINE_TYPE_CASE_SENSITIVE;
621 }
622 else
623 {
624 ExitWithRootFailure(hr, E_INVALIDARG, "Invalid value for CommandLine/@Variables: %ls", scz);
625 }
626 }
627
628 // Get the list of variables users can override on the command line.
629 hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixStdbaOverridableVariable", &pNodes);
630 ExitOnFailure(hr, "Failed to select overridable variable nodes.");
631
632 hr = pNodes->get_length(reinterpret_cast<long*>(&pOverridableVariables->cVariables));
633 ExitOnFailure(hr, "Failed to get overridable variable node count.");
634
635 if (pOverridableVariables->cVariables)
636 {
637 DICT_FLAG dfFlags = BAL_INFO_VARIABLE_COMMAND_LINE_TYPE_CASE_INSENSITIVE == pOverridableVariables->commandLineType ? DICT_FLAG_CASEINSENSITIVE : DICT_FLAG_NONE;
638
639 hr = DictCreateWithEmbeddedKey(&pOverridableVariables->sdVariables, pOverridableVariables->cVariables, reinterpret_cast<void**>(&pOverridableVariables->rgVariables), offsetof(BAL_INFO_OVERRIDABLE_VARIABLE, sczName), dfFlags);
640 ExitOnFailure(hr, "Failed to create the overridable variables string dictionary.");
641
642 hr = MemAllocArray(reinterpret_cast<LPVOID*>(&pOverridableVariables->rgVariables), sizeof(pOverridableVariable), pOverridableVariables->cVariables);
643 ExitOnFailure(hr, "Failed to create the overridable variables array.");
644
645 for (DWORD i = 0; i < pOverridableVariables->cVariables; ++i)
646 {
647 pOverridableVariable = pOverridableVariables->rgVariables + i;
648
649 hr = XmlNextElement(pNodes, &pNode, NULL);
650 ExitOnFailure(hr, "Failed to get next node.");
651
652 // @Name
653 hr = XmlGetAttributeEx(pNode, L"Name", &pOverridableVariable->sczName);
654 ExitOnRequiredXmlQueryFailure(hr, "Failed to get name for overridable variable.");
655
656 hr = DictAddValue(pOverridableVariables->sdVariables, pOverridableVariable);
657 ExitOnFailure(hr, "Failed to add \"%ls\" to the string dictionary.", pOverridableVariable->sczName);
658
659 // prepare next iteration
660 ReleaseNullObject(pNode);
661 }
662 }
663
664 LExit:
665 ReleaseStr(scz);
666 ReleaseObject(pCommandLineNode);
667 ReleaseObject(pNode);
668 ReleaseObject(pNodes);
669 return hr;
670 }