diff options
Diffstat (limited to '')
-rw-r--r-- | src/balutil/balinfo.cpp | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/src/balutil/balinfo.cpp b/src/balutil/balinfo.cpp new file mode 100644 index 00000000..b36e3741 --- /dev/null +++ b/src/balutil/balinfo.cpp | |||
@@ -0,0 +1,288 @@ | |||
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 | |||
11 | |||
12 | DAPI_(HRESULT) BalInfoParseFromXml( | ||
13 | __in BAL_INFO_BUNDLE* pBundle, | ||
14 | __in IXMLDOMDocument* pixdManifest | ||
15 | ) | ||
16 | { | ||
17 | HRESULT hr = S_OK; | ||
18 | IXMLDOMNode* pNode = NULL; | ||
19 | |||
20 | hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixBundleProperties", &pNode); | ||
21 | ExitOnFailure(hr, "Failed to select bundle information."); | ||
22 | |||
23 | if (S_OK == hr) | ||
24 | { | ||
25 | hr = XmlGetYesNoAttribute(pNode, L"PerMachine", &pBundle->fPerMachine); | ||
26 | if (E_NOTFOUND != hr) | ||
27 | { | ||
28 | ExitOnFailure(hr, "Failed to read bundle information per-machine."); | ||
29 | } | ||
30 | |||
31 | hr = XmlGetAttributeEx(pNode, L"DisplayName", &pBundle->sczName); | ||
32 | if (E_NOTFOUND != hr) | ||
33 | { | ||
34 | ExitOnFailure(hr, "Failed to read bundle information display name."); | ||
35 | } | ||
36 | |||
37 | hr = XmlGetAttributeEx(pNode, L"LogPathVariable", &pBundle->sczLogVariable); | ||
38 | if (E_NOTFOUND != hr) | ||
39 | { | ||
40 | ExitOnFailure(hr, "Failed to read bundle information log path variable."); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | hr = ParsePackagesFromXml(&pBundle->packages, pixdManifest); | ||
45 | BalExitOnFailure(hr, "Failed to parse package information from bootstrapper application data."); | ||
46 | |||
47 | LExit: | ||
48 | ReleaseObject(pNode); | ||
49 | |||
50 | return hr; | ||
51 | } | ||
52 | |||
53 | |||
54 | DAPI_(HRESULT) BalInfoAddRelatedBundleAsPackage( | ||
55 | __in BAL_INFO_PACKAGES* pPackages, | ||
56 | __in LPCWSTR wzId, | ||
57 | __in BOOTSTRAPPER_RELATION_TYPE relationType, | ||
58 | __in BOOL /*fPerMachine*/ | ||
59 | ) | ||
60 | { | ||
61 | HRESULT hr = S_OK; | ||
62 | BAL_INFO_PACKAGE_TYPE type = BAL_INFO_PACKAGE_TYPE_UNKNOWN; | ||
63 | BAL_INFO_PACKAGE* pPackage = NULL; | ||
64 | |||
65 | // Ensure we have a supported relation type. | ||
66 | switch (relationType) | ||
67 | { | ||
68 | case BOOTSTRAPPER_RELATION_ADDON: | ||
69 | type = BAL_INFO_PACKAGE_TYPE_BUNDLE_ADDON; | ||
70 | break; | ||
71 | |||
72 | case BOOTSTRAPPER_RELATION_PATCH: | ||
73 | type = BAL_INFO_PACKAGE_TYPE_BUNDLE_PATCH; | ||
74 | break; | ||
75 | |||
76 | case BOOTSTRAPPER_RELATION_UPGRADE: | ||
77 | type = BAL_INFO_PACKAGE_TYPE_BUNDLE_UPGRADE; | ||
78 | break; | ||
79 | |||
80 | default: | ||
81 | ExitOnFailure(hr = E_INVALIDARG, "Unknown related bundle type: %u", relationType); | ||
82 | } | ||
83 | |||
84 | // Check to see if the bundle is already in the list of packages. | ||
85 | for (DWORD i = 0; i < pPackages->cPackages; ++i) | ||
86 | { | ||
87 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzId, -1, pPackages->rgPackages[i].sczId, -1)) | ||
88 | { | ||
89 | ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | // Add the related bundle as a package. | ||
94 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPackages->rgPackages), pPackages->cPackages + 1, sizeof(BAL_INFO_PACKAGE), 2); | ||
95 | ExitOnFailure(hr, "Failed to allocate memory for related bundle package information."); | ||
96 | |||
97 | pPackage = pPackages->rgPackages + pPackages->cPackages; | ||
98 | ++pPackages->cPackages; | ||
99 | |||
100 | hr = StrAllocString(&pPackage->sczId, wzId, 0); | ||
101 | ExitOnFailure(hr, "Failed to copy related bundle package id."); | ||
102 | |||
103 | pPackage->type = type; | ||
104 | |||
105 | // TODO: try to look up the DisplayName and Description in Add/Remove Programs with the wzId. | ||
106 | |||
107 | LExit: | ||
108 | return hr; | ||
109 | } | ||
110 | |||
111 | |||
112 | DAPI_(HRESULT) BalInfoFindPackageById( | ||
113 | __in BAL_INFO_PACKAGES* pPackages, | ||
114 | __in LPCWSTR wzId, | ||
115 | __out BAL_INFO_PACKAGE** ppPackage | ||
116 | ) | ||
117 | { | ||
118 | *ppPackage = NULL; | ||
119 | |||
120 | for (DWORD i = 0; i < pPackages->cPackages; ++i) | ||
121 | { | ||
122 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzId, -1, pPackages->rgPackages[i].sczId, -1)) | ||
123 | { | ||
124 | *ppPackage = pPackages->rgPackages + i; | ||
125 | break; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | return *ppPackage ? S_OK : E_NOTFOUND; | ||
130 | } | ||
131 | |||
132 | |||
133 | DAPI_(void) BalInfoUninitialize( | ||
134 | __in BAL_INFO_BUNDLE* pBundle | ||
135 | ) | ||
136 | { | ||
137 | for (DWORD i = 0; i < pBundle->packages.cPackages; ++i) | ||
138 | { | ||
139 | ReleaseStr(pBundle->packages.rgPackages[i].sczDisplayName); | ||
140 | ReleaseStr(pBundle->packages.rgPackages[i].sczDescription); | ||
141 | ReleaseStr(pBundle->packages.rgPackages[i].sczId); | ||
142 | ReleaseStr(pBundle->packages.rgPackages[i].sczProductCode); | ||
143 | ReleaseStr(pBundle->packages.rgPackages[i].sczUpgradeCode); | ||
144 | ReleaseStr(pBundle->packages.rgPackages[i].sczVersion); | ||
145 | ReleaseStr(pBundle->packages.rgPackages[i].sczInstallCondition); | ||
146 | } | ||
147 | |||
148 | ReleaseMem(pBundle->packages.rgPackages); | ||
149 | |||
150 | ReleaseStr(pBundle->sczName); | ||
151 | ReleaseStr(pBundle->sczLogVariable); | ||
152 | memset(pBundle, 0, sizeof(BAL_INFO_BUNDLE)); | ||
153 | } | ||
154 | |||
155 | |||
156 | static HRESULT ParsePackagesFromXml( | ||
157 | __in BAL_INFO_PACKAGES* pPackages, | ||
158 | __in IXMLDOMDocument* pixdManifest | ||
159 | ) | ||
160 | { | ||
161 | HRESULT hr = S_OK; | ||
162 | IXMLDOMNodeList* pNodeList = NULL; | ||
163 | IXMLDOMNode* pNode = NULL; | ||
164 | BAL_INFO_PACKAGE* prgPackages = NULL; | ||
165 | DWORD cPackages = 0; | ||
166 | LPWSTR scz = NULL; | ||
167 | |||
168 | hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixPackageProperties", &pNodeList); | ||
169 | ExitOnFailure(hr, "Failed to select all packages."); | ||
170 | |||
171 | hr = pNodeList->get_length(reinterpret_cast<long*>(&cPackages)); | ||
172 | ExitOnFailure(hr, "Failed to get the package count."); | ||
173 | |||
174 | prgPackages = static_cast<BAL_INFO_PACKAGE*>(MemAlloc(sizeof(BAL_INFO_PACKAGE) * cPackages, TRUE)); | ||
175 | ExitOnNull(prgPackages, hr, E_OUTOFMEMORY, "Failed to allocate memory for packages."); | ||
176 | |||
177 | DWORD iPackage = 0; | ||
178 | while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL))) | ||
179 | { | ||
180 | hr = XmlGetAttributeEx(pNode, L"Package", &prgPackages[iPackage].sczId); | ||
181 | ExitOnFailure(hr, "Failed to get package identifier for package."); | ||
182 | |||
183 | hr = XmlGetAttributeEx(pNode, L"DisplayName", &prgPackages[iPackage].sczDisplayName); | ||
184 | if (E_NOTFOUND != hr) | ||
185 | { | ||
186 | ExitOnFailure(hr, "Failed to get display name for package."); | ||
187 | } | ||
188 | |||
189 | hr = XmlGetAttributeEx(pNode, L"Description", &prgPackages[iPackage].sczDescription); | ||
190 | if (E_NOTFOUND != hr) | ||
191 | { | ||
192 | ExitOnFailure(hr, "Failed to get description for package."); | ||
193 | } | ||
194 | |||
195 | hr = XmlGetAttributeEx(pNode, L"PackageType", &scz); | ||
196 | ExitOnFailure(hr, "Failed to get package type for package."); | ||
197 | |||
198 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Exe", -1, scz, -1)) | ||
199 | { | ||
200 | prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_EXE; | ||
201 | } | ||
202 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msi", -1, scz, -1)) | ||
203 | { | ||
204 | prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSI; | ||
205 | } | ||
206 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msp", -1, scz, -1)) | ||
207 | { | ||
208 | prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSP; | ||
209 | } | ||
210 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msu", -1, scz, -1)) | ||
211 | { | ||
212 | prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSU; | ||
213 | } | ||
214 | |||
215 | hr = XmlGetYesNoAttribute(pNode, L"Permanent", &prgPackages[iPackage].fPermanent); | ||
216 | ExitOnFailure(hr, "Failed to get permanent setting for package."); | ||
217 | |||
218 | hr = XmlGetYesNoAttribute(pNode, L"Vital", &prgPackages[iPackage].fVital); | ||
219 | ExitOnFailure(hr, "Failed to get vital setting for package."); | ||
220 | |||
221 | hr = XmlGetYesNoAttribute(pNode, L"DisplayInternalUI", &prgPackages[iPackage].fDisplayInternalUI); | ||
222 | if (E_NOTFOUND != hr) | ||
223 | { | ||
224 | ExitOnFailure(hr, "Failed to get DisplayInternalUI setting for package."); | ||
225 | } | ||
226 | |||
227 | hr = XmlGetAttributeEx(pNode, L"ProductCode", &prgPackages[iPackage].sczProductCode); | ||
228 | if (E_NOTFOUND != hr) | ||
229 | { | ||
230 | ExitOnFailure(hr, "Failed to get product code for package."); | ||
231 | } | ||
232 | |||
233 | hr = XmlGetAttributeEx(pNode, L"UpgradeCode", &prgPackages[iPackage].sczUpgradeCode); | ||
234 | if (E_NOTFOUND != hr) | ||
235 | { | ||
236 | ExitOnFailure(hr, "Failed to get upgrade code for package."); | ||
237 | } | ||
238 | |||
239 | hr = XmlGetAttributeEx(pNode, L"Version", &prgPackages[iPackage].sczVersion); | ||
240 | if (E_NOTFOUND != hr) | ||
241 | { | ||
242 | ExitOnFailure(hr, "Failed to get version for package."); | ||
243 | } | ||
244 | |||
245 | hr = XmlGetAttributeEx(pNode, L"InstallCondition", &prgPackages[iPackage].sczInstallCondition); | ||
246 | if (E_NOTFOUND != hr) | ||
247 | { | ||
248 | ExitOnFailure(hr, "Failed to get install condition for package."); | ||
249 | } | ||
250 | |||
251 | hr = XmlGetAttributeEx(pNode, L"Cache", &scz); | ||
252 | ExitOnFailure(hr, "Failed to get cache type for package."); | ||
253 | |||
254 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, scz, -1, L"no", -1)) | ||
255 | { | ||
256 | prgPackages[iPackage].cacheType = BAL_INFO_CACHE_TYPE_NO; | ||
257 | } | ||
258 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, scz, -1, L"yes", -1)) | ||
259 | { | ||
260 | prgPackages[iPackage].cacheType = BAL_INFO_CACHE_TYPE_YES; | ||
261 | } | ||
262 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, scz, -1, L"always", -1)) | ||
263 | { | ||
264 | prgPackages[iPackage].cacheType = BAL_INFO_CACHE_TYPE_ALWAYS; | ||
265 | } | ||
266 | |||
267 | ++iPackage; | ||
268 | ReleaseNullObject(pNode); | ||
269 | } | ||
270 | ExitOnFailure(hr, "Failed to parse all package property elements."); | ||
271 | |||
272 | if (S_FALSE == hr) | ||
273 | { | ||
274 | hr = S_OK; | ||
275 | } | ||
276 | |||
277 | pPackages->cPackages = cPackages; | ||
278 | pPackages->rgPackages = prgPackages; | ||
279 | prgPackages = NULL; | ||
280 | |||
281 | LExit: | ||
282 | ReleaseStr(scz); | ||
283 | ReleaseMem(prgPackages); | ||
284 | ReleaseObject(pNode); | ||
285 | ReleaseObject(pNodeList); | ||
286 | |||
287 | return hr; | ||
288 | } | ||