diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2018-12-29 22:12:08 -0600 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2018-12-29 22:12:08 -0600 |
commit | 61847dddd4fd497057c780658e383c4627de19ec (patch) | |
tree | f85a845182922538ab9aa6ee85b0db3ab40c1f6e /src/engine/detect.cpp | |
parent | 8295f5f8fd28042e1a0a172d5afbba79178064c2 (diff) | |
download | wix-61847dddd4fd497057c780658e383c4627de19ec.tar.gz wix-61847dddd4fd497057c780658e383c4627de19ec.tar.bz2 wix-61847dddd4fd497057c780658e383c4627de19ec.zip |
Import code from old v4 repo
Diffstat (limited to 'src/engine/detect.cpp')
-rw-r--r-- | src/engine/detect.cpp | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/src/engine/detect.cpp b/src/engine/detect.cpp new file mode 100644 index 00000000..7953daf5 --- /dev/null +++ b/src/engine/detect.cpp | |||
@@ -0,0 +1,431 @@ | |||
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 | typedef struct _DETECT_AUTHENTICATION_REQUIRED_DATA | ||
6 | { | ||
7 | BURN_USER_EXPERIENCE* pUX; | ||
8 | LPCWSTR wzPackageOrContainerId; | ||
9 | } DETECT_AUTHENTICATION_REQUIRED_DATA; | ||
10 | |||
11 | // internal function definitions | ||
12 | static HRESULT AuthenticationRequired( | ||
13 | __in LPVOID pData, | ||
14 | __in HINTERNET hUrl, | ||
15 | __in long lHttpCode, | ||
16 | __out BOOL* pfRetrySend, | ||
17 | __out BOOL* pfRetry | ||
18 | ); | ||
19 | |||
20 | static HRESULT DetectAtomFeedUpdate( | ||
21 | __in_z LPCWSTR wzBundleId, | ||
22 | __in BURN_USER_EXPERIENCE* pUX, | ||
23 | __in BURN_UPDATE* pUpdate | ||
24 | ); | ||
25 | |||
26 | static HRESULT DownloadUpdateFeed( | ||
27 | __in_z LPCWSTR wzBundleId, | ||
28 | __in BURN_USER_EXPERIENCE* pUX, | ||
29 | __in BURN_UPDATE* pUpdate, | ||
30 | __deref_inout_z LPWSTR* psczTempFile | ||
31 | ); | ||
32 | |||
33 | // function definitions | ||
34 | |||
35 | extern "C" void DetectReset( | ||
36 | __in BURN_REGISTRATION* pRegistration, | ||
37 | __in BURN_PACKAGES* pPackages | ||
38 | ) | ||
39 | { | ||
40 | RelatedBundlesUninitialize(&pRegistration->relatedBundles); | ||
41 | ReleaseNullStr(pRegistration->sczDetectedProviderKeyBundleId); | ||
42 | pRegistration->fEnabledForwardCompatibleBundle = FALSE; | ||
43 | PackageUninitialize(&pRegistration->forwardCompatibleBundle); | ||
44 | |||
45 | for (DWORD iPackage = 0; iPackage < pPackages->cPackages; ++iPackage) | ||
46 | { | ||
47 | BURN_PACKAGE* pPackage = pPackages->rgPackages + iPackage; | ||
48 | |||
49 | pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN; | ||
50 | |||
51 | pPackage->cache = BURN_CACHE_STATE_NONE; | ||
52 | for (DWORD iPayload = 0; iPayload < pPackage->cPayloads; ++iPayload) | ||
53 | { | ||
54 | BURN_PACKAGE_PAYLOAD* pPayload = pPackage->rgPayloads + iPayload; | ||
55 | pPayload->fCached = FALSE; | ||
56 | } | ||
57 | |||
58 | if (BURN_PACKAGE_TYPE_MSI == pPackage->type) | ||
59 | { | ||
60 | for (DWORD iFeature = 0; iFeature < pPackage->Msi.cFeatures; ++iFeature) | ||
61 | { | ||
62 | BURN_MSIFEATURE* pFeature = pPackage->Msi.rgFeatures + iFeature; | ||
63 | |||
64 | pFeature->currentState = BOOTSTRAPPER_FEATURE_STATE_UNKNOWN; | ||
65 | } | ||
66 | |||
67 | pPackage->Msi.fCompatibleInstalled = FALSE; | ||
68 | } | ||
69 | else if (BURN_PACKAGE_TYPE_MSP == pPackage->type) | ||
70 | { | ||
71 | ReleaseNullMem(pPackage->Msp.rgTargetProducts); | ||
72 | pPackage->Msp.cTargetProductCodes = 0; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo) | ||
77 | { | ||
78 | MSIPATCHSEQUENCEINFOW* pPatchInfo = pPackages->rgPatchInfo + iPatchInfo; | ||
79 | pPatchInfo->dwOrder = 0; | ||
80 | pPatchInfo->uStatus = 0; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | extern "C" HRESULT DetectForwardCompatibleBundle( | ||
85 | __in BURN_USER_EXPERIENCE* pUX, | ||
86 | __in BOOTSTRAPPER_COMMAND* pCommand, | ||
87 | __in BURN_REGISTRATION* pRegistration | ||
88 | ) | ||
89 | { | ||
90 | HRESULT hr = S_OK; | ||
91 | BOOL fRecommendIgnore = TRUE; | ||
92 | BOOL fIgnoreBundle = FALSE; | ||
93 | |||
94 | if (pRegistration->sczDetectedProviderKeyBundleId && | ||
95 | CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleId, -1, pRegistration->sczId, -1)) | ||
96 | { | ||
97 | // Only change the recommendation if an active parent was provided. | ||
98 | if (pRegistration->sczActiveParent && *pRegistration->sczActiveParent) | ||
99 | { | ||
100 | // On install, recommend running the forward compatible bundle because there is an active parent. This | ||
101 | // will essentially register the parent with the forward compatible bundle. | ||
102 | if (BOOTSTRAPPER_ACTION_INSTALL == pCommand->action) | ||
103 | { | ||
104 | fRecommendIgnore = FALSE; | ||
105 | } | ||
106 | else if (BOOTSTRAPPER_ACTION_UNINSTALL == pCommand->action || | ||
107 | BOOTSTRAPPER_ACTION_MODIFY == pCommand->action || | ||
108 | BOOTSTRAPPER_ACTION_REPAIR == pCommand->action) | ||
109 | { | ||
110 | // When modifying the bundle, only recommend running the forward compatible bundle if the parent | ||
111 | // is already registered as a dependent of the provider key. | ||
112 | if (DependencyDependentExists(pRegistration, pRegistration->sczActiveParent)) | ||
113 | { | ||
114 | fRecommendIgnore = FALSE; | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | for (DWORD iRelatedBundle = 0; iRelatedBundle < pRegistration->relatedBundles.cRelatedBundles; ++iRelatedBundle) | ||
120 | { | ||
121 | BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + iRelatedBundle; | ||
122 | fIgnoreBundle = fRecommendIgnore; | ||
123 | |||
124 | if (BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->relationType && | ||
125 | pRegistration->qwVersion <= pRelatedBundle->qwVersion && | ||
126 | CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleId, -1, pRelatedBundle->package.sczId, -1)) | ||
127 | { | ||
128 | hr = UserExperienceOnDetectForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->qwVersion, &fIgnoreBundle); | ||
129 | ExitOnRootFailure(hr, "BA aborted detect forward compatible bundle."); | ||
130 | |||
131 | if (!fIgnoreBundle) | ||
132 | { | ||
133 | hr = PseudoBundleInitializePassthrough(&pRegistration->forwardCompatibleBundle, pCommand, NULL, pRegistration->sczActiveParent, pRegistration->sczAncestors, &pRelatedBundle->package); | ||
134 | ExitOnFailure(hr, "Failed to initialize update bundle."); | ||
135 | |||
136 | pRegistration->fEnabledForwardCompatibleBundle = TRUE; | ||
137 | } | ||
138 | |||
139 | LogId(REPORT_STANDARD, MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), LoggingVersionToString(pRelatedBundle->qwVersion), LoggingBoolToString(pRegistration->fEnabledForwardCompatibleBundle)); | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | LExit: | ||
146 | return hr; | ||
147 | } | ||
148 | |||
149 | extern "C" HRESULT DetectReportRelatedBundles( | ||
150 | __in BURN_USER_EXPERIENCE* pUX, | ||
151 | __in BURN_REGISTRATION* pRegistration, | ||
152 | __in BOOTSTRAPPER_RELATION_TYPE relationType, | ||
153 | __in BOOTSTRAPPER_ACTION action | ||
154 | ) | ||
155 | { | ||
156 | HRESULT hr = S_OK; | ||
157 | |||
158 | for (DWORD iRelatedBundle = 0; iRelatedBundle < pRegistration->relatedBundles.cRelatedBundles; ++iRelatedBundle) | ||
159 | { | ||
160 | const BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + iRelatedBundle; | ||
161 | BOOTSTRAPPER_RELATED_OPERATION operation = BOOTSTRAPPER_RELATED_OPERATION_NONE; | ||
162 | |||
163 | switch (pRelatedBundle->relationType) | ||
164 | { | ||
165 | case BOOTSTRAPPER_RELATION_UPGRADE: | ||
166 | if (BOOTSTRAPPER_RELATION_UPGRADE != relationType && BOOTSTRAPPER_ACTION_UNINSTALL < action) | ||
167 | { | ||
168 | if (pRegistration->qwVersion > pRelatedBundle->qwVersion) | ||
169 | { | ||
170 | operation = BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE; | ||
171 | } | ||
172 | else if (pRegistration->qwVersion < pRelatedBundle->qwVersion) | ||
173 | { | ||
174 | operation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE; | ||
175 | } | ||
176 | } | ||
177 | break; | ||
178 | |||
179 | case BOOTSTRAPPER_RELATION_PATCH: __fallthrough; | ||
180 | case BOOTSTRAPPER_RELATION_ADDON: | ||
181 | if (BOOTSTRAPPER_ACTION_UNINSTALL == action) | ||
182 | { | ||
183 | operation = BOOTSTRAPPER_RELATED_OPERATION_REMOVE; | ||
184 | } | ||
185 | else if (BOOTSTRAPPER_ACTION_INSTALL == action || BOOTSTRAPPER_ACTION_MODIFY == action) | ||
186 | { | ||
187 | operation = BOOTSTRAPPER_RELATED_OPERATION_INSTALL; | ||
188 | } | ||
189 | else if (BOOTSTRAPPER_ACTION_REPAIR == action) | ||
190 | { | ||
191 | operation = BOOTSTRAPPER_RELATED_OPERATION_REPAIR; | ||
192 | } | ||
193 | break; | ||
194 | |||
195 | case BOOTSTRAPPER_RELATION_DETECT: __fallthrough; | ||
196 | case BOOTSTRAPPER_RELATION_DEPENDENT: | ||
197 | break; | ||
198 | |||
199 | default: | ||
200 | hr = E_FAIL; | ||
201 | ExitOnRootFailure(hr, "Unexpected relation type encountered: %d", pRelatedBundle->relationType); | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), LoggingVersionToString(pRelatedBundle->qwVersion), LoggingRelatedOperationToString(operation)); | ||
206 | |||
207 | hr = UserExperienceOnDetectRelatedBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->qwVersion, operation); | ||
208 | ExitOnRootFailure(hr, "BA aborted detect related bundle."); | ||
209 | } | ||
210 | |||
211 | LExit: | ||
212 | return hr; | ||
213 | } | ||
214 | |||
215 | extern "C" HRESULT DetectUpdate( | ||
216 | __in_z LPCWSTR wzBundleId, | ||
217 | __in BURN_USER_EXPERIENCE* pUX, | ||
218 | __in BURN_UPDATE* pUpdate | ||
219 | ) | ||
220 | { | ||
221 | HRESULT hr = S_OK; | ||
222 | BOOL fBeginCalled = FALSE; | ||
223 | BOOL fSkip = TRUE; | ||
224 | BOOL fIgnoreError = FALSE; | ||
225 | |||
226 | // If no update source was specified, skip update detection. | ||
227 | if (!pUpdate->sczUpdateSource || !*pUpdate->sczUpdateSource) | ||
228 | { | ||
229 | ExitFunction(); | ||
230 | } | ||
231 | |||
232 | fBeginCalled = TRUE; | ||
233 | hr = UserExperienceOnDetectUpdateBegin(pUX, pUpdate->sczUpdateSource, &fSkip); | ||
234 | ExitOnRootFailure(hr, "BA aborted detect update begin."); | ||
235 | |||
236 | if (!fSkip) | ||
237 | { | ||
238 | hr = DetectAtomFeedUpdate(wzBundleId, pUX, pUpdate); | ||
239 | ExitOnFailure(hr, "Failed to detect atom feed update."); | ||
240 | } | ||
241 | |||
242 | LExit: | ||
243 | if (fBeginCalled) | ||
244 | { | ||
245 | UserExperienceOnDetectUpdateComplete(pUX, hr, &fIgnoreError); | ||
246 | if (fIgnoreError) | ||
247 | { | ||
248 | hr = S_OK; | ||
249 | } | ||
250 | } | ||
251 | |||
252 | return hr; | ||
253 | } | ||
254 | |||
255 | static HRESULT AuthenticationRequired( | ||
256 | __in LPVOID pData, | ||
257 | __in HINTERNET hUrl, | ||
258 | __in long lHttpCode, | ||
259 | __out BOOL* pfRetrySend, | ||
260 | __out BOOL* pfRetry | ||
261 | ) | ||
262 | { | ||
263 | Assert(401 == lHttpCode || 407 == lHttpCode); | ||
264 | |||
265 | HRESULT hr = S_OK; | ||
266 | DWORD er = ERROR_SUCCESS; | ||
267 | BOOTSTRAPPER_ERROR_TYPE errorType = (401 == lHttpCode) ? BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_SERVER : BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_PROXY; | ||
268 | LPWSTR sczError = NULL; | ||
269 | DETECT_AUTHENTICATION_REQUIRED_DATA* pAuthenticationData = reinterpret_cast<DETECT_AUTHENTICATION_REQUIRED_DATA*>(pData); | ||
270 | int nResult = IDNOACTION; | ||
271 | |||
272 | *pfRetrySend = FALSE; | ||
273 | *pfRetry = FALSE; | ||
274 | |||
275 | hr = StrAllocFromError(&sczError, HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), NULL); | ||
276 | ExitOnFailure(hr, "Failed to allocation error string."); | ||
277 | |||
278 | UserExperienceOnError(pAuthenticationData->pUX, errorType, pAuthenticationData->wzPackageOrContainerId, ERROR_ACCESS_DENIED, sczError, MB_RETRYTRYAGAIN, 0, NULL, &nResult); // ignore return value. | ||
279 | nResult = UserExperienceCheckExecuteResult(pAuthenticationData->pUX, FALSE, MB_RETRYTRYAGAIN, nResult); | ||
280 | if (IDTRYAGAIN == nResult && pAuthenticationData->pUX->hwndDetect) | ||
281 | { | ||
282 | er = ::InternetErrorDlg(pAuthenticationData->pUX->hwndDetect, hUrl, ERROR_INTERNET_INCORRECT_PASSWORD, FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, NULL); | ||
283 | if (ERROR_SUCCESS == er || ERROR_CANCELLED == er) | ||
284 | { | ||
285 | hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); | ||
286 | } | ||
287 | else if (ERROR_INTERNET_FORCE_RETRY == er) | ||
288 | { | ||
289 | *pfRetrySend = TRUE; | ||
290 | hr = S_OK; | ||
291 | } | ||
292 | else | ||
293 | { | ||
294 | hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); | ||
295 | } | ||
296 | } | ||
297 | else if (IDRETRY == nResult) | ||
298 | { | ||
299 | *pfRetry = TRUE; | ||
300 | hr = S_OK; | ||
301 | } | ||
302 | else | ||
303 | { | ||
304 | hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); | ||
305 | } | ||
306 | |||
307 | LExit: | ||
308 | ReleaseStr(sczError); | ||
309 | |||
310 | return hr; | ||
311 | } | ||
312 | |||
313 | static HRESULT DownloadUpdateFeed( | ||
314 | __in_z LPCWSTR wzBundleId, | ||
315 | __in BURN_USER_EXPERIENCE* pUX, | ||
316 | __in BURN_UPDATE* pUpdate, | ||
317 | __deref_inout_z LPWSTR* psczTempFile | ||
318 | ) | ||
319 | { | ||
320 | HRESULT hr = S_OK; | ||
321 | DOWNLOAD_SOURCE downloadSource = { }; | ||
322 | DOWNLOAD_CACHE_CALLBACK cacheCallback = { }; | ||
323 | DOWNLOAD_AUTHENTICATION_CALLBACK authenticationCallback = { }; | ||
324 | DETECT_AUTHENTICATION_REQUIRED_DATA authenticationData = { }; | ||
325 | LPWSTR sczUpdateId = NULL; | ||
326 | LPWSTR sczError = NULL; | ||
327 | DWORD64 qwDownloadSize = 0; | ||
328 | |||
329 | // Always do our work in the working folder, even if cached. | ||
330 | hr = PathCreateTimeBasedTempFile(NULL, L"UpdateFeed", NULL, L"xml", psczTempFile, NULL); | ||
331 | ExitOnFailure(hr, "Failed to create UpdateFeed based on current system time."); | ||
332 | |||
333 | // Do we need a means of the BA to pass in a user name and password? If so, we should copy it to downloadSource here | ||
334 | hr = StrAllocString(&downloadSource.sczUrl, pUpdate->sczUpdateSource, 0); | ||
335 | ExitOnFailure(hr, "Failed to copy update url."); | ||
336 | |||
337 | cacheCallback.pfnProgress = NULL; //UpdateProgressRoutine; | ||
338 | cacheCallback.pfnCancel = NULL; // TODO: set this | ||
339 | cacheCallback.pv = NULL; //pProgress; | ||
340 | |||
341 | authenticationData.pUX = pUX; | ||
342 | authenticationData.wzPackageOrContainerId = wzBundleId; | ||
343 | |||
344 | authenticationCallback.pv = static_cast<LPVOID>(&authenticationData); | ||
345 | authenticationCallback.pfnAuthenticate = &AuthenticationRequired; | ||
346 | |||
347 | hr = DownloadUrl(&downloadSource, qwDownloadSize, *psczTempFile, &cacheCallback, &authenticationCallback); | ||
348 | ExitOnFailure(hr, "Failed attempt to download update feed from URL: '%ls' to: '%ls'", downloadSource.sczUrl, *psczTempFile); | ||
349 | |||
350 | LExit: | ||
351 | if (FAILED(hr)) | ||
352 | { | ||
353 | if (*psczTempFile) | ||
354 | { | ||
355 | FileEnsureDelete(*psczTempFile); | ||
356 | } | ||
357 | |||
358 | ReleaseNullStr(*psczTempFile); | ||
359 | } | ||
360 | |||
361 | ReleaseStr(downloadSource.sczUrl); | ||
362 | ReleaseStr(downloadSource.sczUser); | ||
363 | ReleaseStr(downloadSource.sczPassword); | ||
364 | ReleaseStr(sczUpdateId); | ||
365 | ReleaseStr(sczError); | ||
366 | return hr; | ||
367 | } | ||
368 | |||
369 | |||
370 | static HRESULT DetectAtomFeedUpdate( | ||
371 | __in_z LPCWSTR wzBundleId, | ||
372 | __in BURN_USER_EXPERIENCE* pUX, | ||
373 | __in BURN_UPDATE* pUpdate | ||
374 | ) | ||
375 | { | ||
376 | Assert(pUpdate && pUpdate->sczUpdateSource && *pUpdate->sczUpdateSource); | ||
377 | #ifdef DEBUG | ||
378 | LogStringLine(REPORT_STANDARD, "DetectAtomFeedUpdate() - update location: %ls", pUpdate->sczUpdateSource); | ||
379 | #endif | ||
380 | |||
381 | |||
382 | HRESULT hr = S_OK; | ||
383 | LPWSTR sczUpdateFeedTempFile = NULL; | ||
384 | ATOM_FEED* pAtomFeed = NULL; | ||
385 | APPLICATION_UPDATE_CHAIN* pApupChain = NULL; | ||
386 | BOOL fStopProcessingUpdates = FALSE; | ||
387 | |||
388 | hr = AtomInitialize(); | ||
389 | ExitOnFailure(hr, "Failed to initialize Atom."); | ||
390 | |||
391 | hr = DownloadUpdateFeed(wzBundleId, pUX, pUpdate, &sczUpdateFeedTempFile); | ||
392 | ExitOnFailure(hr, "Failed to download update feed."); | ||
393 | |||
394 | hr = AtomParseFromFile(sczUpdateFeedTempFile, &pAtomFeed); | ||
395 | ExitOnFailure(hr, "Failed to parse update atom feed: %ls.", sczUpdateFeedTempFile); | ||
396 | |||
397 | hr = ApupAllocChainFromAtom(pAtomFeed, &pApupChain); | ||
398 | ExitOnFailure(hr, "Failed to allocate update chain from atom feed."); | ||
399 | |||
400 | if (0 < pApupChain->cEntries) | ||
401 | { | ||
402 | for (DWORD i = 0; i < pApupChain->cEntries; ++i) | ||
403 | { | ||
404 | APPLICATION_UPDATE_ENTRY* pAppUpdateEntry = &pApupChain->rgEntries[i]; | ||
405 | |||
406 | hr = UserExperienceOnDetectUpdate(pUX, pAppUpdateEntry->rgEnclosures ? pAppUpdateEntry->rgEnclosures->wzUrl : NULL, | ||
407 | pAppUpdateEntry->rgEnclosures ? pAppUpdateEntry->rgEnclosures->dw64Size : 0, | ||
408 | pAppUpdateEntry->dw64Version, pAppUpdateEntry->wzTitle, | ||
409 | pAppUpdateEntry->wzSummary, pAppUpdateEntry->wzContentType, pAppUpdateEntry->wzContent, &fStopProcessingUpdates); | ||
410 | ExitOnRootFailure(hr, "BA aborted detect update."); | ||
411 | |||
412 | if (fStopProcessingUpdates) | ||
413 | { | ||
414 | break; | ||
415 | } | ||
416 | } | ||
417 | } | ||
418 | |||
419 | LExit: | ||
420 | if (sczUpdateFeedTempFile && *sczUpdateFeedTempFile) | ||
421 | { | ||
422 | FileEnsureDelete(sczUpdateFeedTempFile); | ||
423 | } | ||
424 | |||
425 | ApupFreeChain(pApupChain); | ||
426 | AtomFreeFeed(pAtomFeed); | ||
427 | ReleaseStr(sczUpdateFeedTempFile); | ||
428 | AtomUninitialize(); | ||
429 | |||
430 | return hr; | ||
431 | } | ||