diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2022-01-03 15:35:14 -0600 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2022-01-04 19:19:43 -0600 |
commit | 1f5314302b3c8bc1977aed79df1d05c52608f382 (patch) | |
tree | f0fef3a4462352c914a4cc9413515d07f2244703 /src/burn/engine/bundlepackageengine.cpp | |
parent | db44f6cf3b1eb476e47384f2eccba5712808def5 (diff) | |
download | wix-1f5314302b3c8bc1977aed79df1d05c52608f382.tar.gz wix-1f5314302b3c8bc1977aed79df1d05c52608f382.tar.bz2 wix-1f5314302b3c8bc1977aed79df1d05c52608f382.zip |
Don't assume Exe packages with Burn protocol are bundles.
Related to #3693
Diffstat (limited to 'src/burn/engine/bundlepackageengine.cpp')
-rw-r--r-- | src/burn/engine/bundlepackageengine.cpp | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp new file mode 100644 index 00000000..10022b6a --- /dev/null +++ b/src/burn/engine/bundlepackageengine.cpp | |||
@@ -0,0 +1,460 @@ | |||
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 | |||
6 | |||
7 | // function definitions | ||
8 | |||
9 | extern "C" void BundlePackageEnginePackageUninitialize( | ||
10 | __in BURN_PACKAGE* pPackage | ||
11 | ) | ||
12 | { | ||
13 | ReleaseStr(pPackage->Bundle.sczInstallArguments); | ||
14 | ReleaseStr(pPackage->Bundle.sczRepairArguments); | ||
15 | ReleaseStr(pPackage->Bundle.sczUninstallArguments); | ||
16 | ReleaseStr(pPackage->Bundle.sczIgnoreDependencies); | ||
17 | ReleaseMem(pPackage->Bundle.rgExitCodes); | ||
18 | |||
19 | // free command-line arguments | ||
20 | if (pPackage->Bundle.rgCommandLineArguments) | ||
21 | { | ||
22 | for (DWORD i = 0; i < pPackage->Bundle.cCommandLineArguments; ++i) | ||
23 | { | ||
24 | ExeEngineCommandLineArgumentUninitialize(pPackage->Bundle.rgCommandLineArguments + i); | ||
25 | } | ||
26 | MemFree(pPackage->Bundle.rgCommandLineArguments); | ||
27 | } | ||
28 | |||
29 | // clear struct | ||
30 | memset(&pPackage->Bundle, 0, sizeof(pPackage->Bundle)); | ||
31 | } | ||
32 | |||
33 | // | ||
34 | // PlanCalculate - calculates the execute and rollback state for the requested package state. | ||
35 | // | ||
36 | extern "C" HRESULT BundlePackageEnginePlanCalculatePackage( | ||
37 | __in BURN_PACKAGE* pPackage | ||
38 | ) | ||
39 | { | ||
40 | HRESULT hr = S_OK; | ||
41 | BOOTSTRAPPER_ACTION_STATE execute = BOOTSTRAPPER_ACTION_STATE_NONE; | ||
42 | BOOTSTRAPPER_ACTION_STATE rollback = BOOTSTRAPPER_ACTION_STATE_NONE; | ||
43 | |||
44 | // execute action | ||
45 | switch (pPackage->currentState) | ||
46 | { | ||
47 | case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: | ||
48 | switch (pPackage->requested) | ||
49 | { | ||
50 | case BOOTSTRAPPER_REQUEST_STATE_PRESENT: | ||
51 | execute = pPackage->Bundle.fPseudoBundle ? BOOTSTRAPPER_ACTION_STATE_INSTALL : BOOTSTRAPPER_ACTION_STATE_NONE; | ||
52 | break; | ||
53 | case BOOTSTRAPPER_REQUEST_STATE_REPAIR: | ||
54 | execute = pPackage->Bundle.fRepairable ? BOOTSTRAPPER_ACTION_STATE_REPAIR : BOOTSTRAPPER_ACTION_STATE_NONE; | ||
55 | break; | ||
56 | case BOOTSTRAPPER_REQUEST_STATE_ABSENT: __fallthrough; | ||
57 | case BOOTSTRAPPER_REQUEST_STATE_CACHE: | ||
58 | execute = pPackage->fUninstallable ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE; | ||
59 | break; | ||
60 | case BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT: | ||
61 | execute = BOOTSTRAPPER_ACTION_STATE_UNINSTALL; | ||
62 | break; | ||
63 | default: | ||
64 | execute = BOOTSTRAPPER_ACTION_STATE_NONE; | ||
65 | break; | ||
66 | } | ||
67 | break; | ||
68 | |||
69 | case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: | ||
70 | switch (pPackage->requested) | ||
71 | { | ||
72 | case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough; | ||
73 | case BOOTSTRAPPER_REQUEST_STATE_REPAIR: | ||
74 | execute = BOOTSTRAPPER_ACTION_STATE_INSTALL; | ||
75 | break; | ||
76 | default: | ||
77 | execute = BOOTSTRAPPER_ACTION_STATE_NONE; | ||
78 | break; | ||
79 | } | ||
80 | break; | ||
81 | |||
82 | default: | ||
83 | hr = E_INVALIDARG; | ||
84 | ExitOnRootFailure(hr, "Invalid package current state: %d.", pPackage->currentState); | ||
85 | } | ||
86 | |||
87 | // Calculate the rollback action if there is an execute action. | ||
88 | if (BOOTSTRAPPER_ACTION_STATE_NONE != execute) | ||
89 | { | ||
90 | switch (pPackage->currentState) | ||
91 | { | ||
92 | case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: | ||
93 | switch (pPackage->requested) | ||
94 | { | ||
95 | case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough; | ||
96 | case BOOTSTRAPPER_REQUEST_STATE_REPAIR: | ||
97 | rollback = BOOTSTRAPPER_ACTION_STATE_NONE; | ||
98 | break; | ||
99 | case BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT: __fallthrough; | ||
100 | case BOOTSTRAPPER_REQUEST_STATE_ABSENT: | ||
101 | rollback = BOOTSTRAPPER_ACTION_STATE_INSTALL; | ||
102 | break; | ||
103 | default: | ||
104 | rollback = BOOTSTRAPPER_ACTION_STATE_NONE; | ||
105 | break; | ||
106 | } | ||
107 | break; | ||
108 | |||
109 | case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: | ||
110 | switch (pPackage->requested) | ||
111 | { | ||
112 | case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough; | ||
113 | case BOOTSTRAPPER_REQUEST_STATE_REPAIR: | ||
114 | rollback = pPackage->fUninstallable ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE; | ||
115 | break; | ||
116 | case BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT: __fallthrough; | ||
117 | case BOOTSTRAPPER_REQUEST_STATE_ABSENT: | ||
118 | rollback = BOOTSTRAPPER_ACTION_STATE_NONE; | ||
119 | break; | ||
120 | default: | ||
121 | rollback = BOOTSTRAPPER_ACTION_STATE_NONE; | ||
122 | break; | ||
123 | } | ||
124 | break; | ||
125 | |||
126 | default: | ||
127 | hr = E_INVALIDARG; | ||
128 | ExitOnRootFailure(hr, "Invalid package expected state."); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | // return values | ||
133 | pPackage->execute = execute; | ||
134 | pPackage->rollback = rollback; | ||
135 | |||
136 | LExit: | ||
137 | return hr; | ||
138 | } | ||
139 | |||
140 | // | ||
141 | // PlanAdd - adds the calculated execute and rollback actions for the package. | ||
142 | // | ||
143 | extern "C" HRESULT BundlePackageEnginePlanAddRelatedBundle( | ||
144 | __in_opt DWORD *pdwInsertSequence, | ||
145 | __in BURN_RELATED_BUNDLE* pRelatedBundle, | ||
146 | __in BURN_PLAN* pPlan, | ||
147 | __in BURN_LOGGING* pLog, | ||
148 | __in BURN_VARIABLES* pVariables | ||
149 | ) | ||
150 | { | ||
151 | HRESULT hr = S_OK; | ||
152 | BURN_EXECUTE_ACTION* pAction = NULL; | ||
153 | BURN_PACKAGE* pPackage = &pRelatedBundle->package; | ||
154 | |||
155 | hr = DependencyPlanPackage(pdwInsertSequence, pPackage, pPlan); | ||
156 | ExitOnFailure(hr, "Failed to plan package dependency actions."); | ||
157 | |||
158 | // add execute action | ||
159 | if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute) | ||
160 | { | ||
161 | if (pdwInsertSequence) | ||
162 | { | ||
163 | hr = PlanInsertExecuteAction(*pdwInsertSequence, pPlan, &pAction); | ||
164 | ExitOnFailure(hr, "Failed to insert execute action."); | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | hr = PlanAppendExecuteAction(pPlan, &pAction); | ||
169 | ExitOnFailure(hr, "Failed to append execute action."); | ||
170 | } | ||
171 | |||
172 | pAction->type = BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE; | ||
173 | pAction->relatedBundle.pRelatedBundle = pRelatedBundle; | ||
174 | pAction->relatedBundle.action = pPackage->execute; | ||
175 | |||
176 | if (pPackage->Bundle.sczIgnoreDependencies) | ||
177 | { | ||
178 | hr = StrAllocString(&pAction->relatedBundle.sczIgnoreDependencies, pPackage->Bundle.sczIgnoreDependencies, 0); | ||
179 | ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); | ||
180 | } | ||
181 | |||
182 | if (pPackage->Bundle.wzAncestors) | ||
183 | { | ||
184 | hr = StrAllocString(&pAction->relatedBundle.sczAncestors, pPackage->Bundle.wzAncestors, 0); | ||
185 | ExitOnFailure(hr, "Failed to allocate the list of ancestors."); | ||
186 | } | ||
187 | |||
188 | if (pPackage->Bundle.wzEngineWorkingDirectory) | ||
189 | { | ||
190 | hr = StrAllocString(&pAction->relatedBundle.sczEngineWorkingDirectory, pPackage->Bundle.wzEngineWorkingDirectory, 0); | ||
191 | ExitOnFailure(hr, "Failed to allocate the custom working directory."); | ||
192 | } | ||
193 | |||
194 | LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, NULL); // ignore errors. | ||
195 | } | ||
196 | |||
197 | // add rollback action | ||
198 | if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback) | ||
199 | { | ||
200 | hr = PlanAppendRollbackAction(pPlan, &pAction); | ||
201 | ExitOnFailure(hr, "Failed to append rollback action."); | ||
202 | |||
203 | pAction->type = BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE; | ||
204 | pAction->relatedBundle.pRelatedBundle = pRelatedBundle; | ||
205 | pAction->relatedBundle.action = pPackage->rollback; | ||
206 | |||
207 | if (pPackage->Bundle.sczIgnoreDependencies) | ||
208 | { | ||
209 | hr = StrAllocString(&pAction->relatedBundle.sczIgnoreDependencies, pPackage->Bundle.sczIgnoreDependencies, 0); | ||
210 | ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); | ||
211 | } | ||
212 | |||
213 | if (pPackage->Bundle.wzAncestors) | ||
214 | { | ||
215 | hr = StrAllocString(&pAction->relatedBundle.sczAncestors, pPackage->Bundle.wzAncestors, 0); | ||
216 | ExitOnFailure(hr, "Failed to allocate the list of ancestors."); | ||
217 | } | ||
218 | |||
219 | if (pPackage->Bundle.wzEngineWorkingDirectory) | ||
220 | { | ||
221 | hr = StrAllocString(&pAction->relatedBundle.sczEngineWorkingDirectory, pPackage->Bundle.wzEngineWorkingDirectory, 0); | ||
222 | ExitOnFailure(hr, "Failed to allocate the custom working directory."); | ||
223 | } | ||
224 | |||
225 | LoggingSetPackageVariable(pPackage, NULL, TRUE, pLog, pVariables, NULL); // ignore errors. | ||
226 | } | ||
227 | |||
228 | LExit: | ||
229 | return hr; | ||
230 | } | ||
231 | |||
232 | extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | ||
233 | __in BURN_EXECUTE_ACTION* pExecuteAction, | ||
234 | __in BURN_CACHE* pCache, | ||
235 | __in BURN_VARIABLES* pVariables, | ||
236 | __in BOOL fRollback, | ||
237 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | ||
238 | __in LPVOID pvContext, | ||
239 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart | ||
240 | ) | ||
241 | { | ||
242 | HRESULT hr = S_OK; | ||
243 | int nResult = IDNOACTION; | ||
244 | LPCWSTR wzArguments = NULL; | ||
245 | LPWSTR sczArguments = NULL; | ||
246 | LPWSTR sczArgumentsFormatted = NULL; | ||
247 | LPWSTR sczArgumentsObfuscated = NULL; | ||
248 | LPWSTR sczCachedDirectory = NULL; | ||
249 | LPWSTR sczExecutablePath = NULL; | ||
250 | LPWSTR sczCommand = NULL; | ||
251 | LPWSTR sczCommandObfuscated = NULL; | ||
252 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; | ||
253 | STARTUPINFOW si = { }; | ||
254 | PROCESS_INFORMATION pi = { }; | ||
255 | DWORD dwExitCode = 0; | ||
256 | GENERIC_EXECUTE_MESSAGE message = { }; | ||
257 | BOOTSTRAPPER_ACTION_STATE action = pExecuteAction->relatedBundle.action; | ||
258 | BURN_RELATED_BUNDLE* pRelatedBundle = pExecuteAction->relatedBundle.pRelatedBundle; | ||
259 | BOOTSTRAPPER_RELATION_TYPE relationType = pRelatedBundle->relationType; | ||
260 | BURN_PACKAGE* pPackage = &pRelatedBundle->package; | ||
261 | BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; | ||
262 | LPCWSTR wzRelationTypeCommandLine = CoreRelationTypeToCommandLineString(relationType); | ||
263 | LPCWSTR wzOperationCommandLine = NULL; | ||
264 | BOOL fRunEmbedded = pPackage->Bundle.fSupportsBurnProtocol; | ||
265 | |||
266 | // get cached executable path | ||
267 | hr = CacheGetCompletedPath(pCache, pPackage->fPerMachine, pPackage->sczCacheId, &sczCachedDirectory); | ||
268 | ExitOnFailure(hr, "Failed to get cached path for package: %ls", pPackage->sczId); | ||
269 | |||
270 | // Best effort to set the execute package cache folder and action variables. | ||
271 | VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, sczCachedDirectory, TRUE, FALSE); | ||
272 | VariableSetNumeric(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_ACTION, action, TRUE); | ||
273 | |||
274 | hr = PathConcat(sczCachedDirectory, pPackagePayload->sczFilePath, &sczExecutablePath); | ||
275 | ExitOnFailure(hr, "Failed to build executable path."); | ||
276 | |||
277 | // pick arguments | ||
278 | switch (action) | ||
279 | { | ||
280 | case BOOTSTRAPPER_ACTION_STATE_INSTALL: | ||
281 | wzArguments = pPackage->Bundle.sczInstallArguments; | ||
282 | break; | ||
283 | |||
284 | case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: | ||
285 | wzOperationCommandLine = L"-uninstall"; | ||
286 | wzArguments = pPackage->Bundle.sczUninstallArguments; | ||
287 | break; | ||
288 | |||
289 | case BOOTSTRAPPER_ACTION_STATE_REPAIR: | ||
290 | wzOperationCommandLine = L"-repair"; | ||
291 | wzArguments = pPackage->Bundle.sczRepairArguments; | ||
292 | break; | ||
293 | |||
294 | default: | ||
295 | hr = E_INVALIDARG; | ||
296 | ExitOnFailure(hr, "Invalid Bundle package action: %d.", action); | ||
297 | } | ||
298 | |||
299 | // now add optional arguments | ||
300 | if (wzArguments && *wzArguments) | ||
301 | { | ||
302 | hr = StrAllocString(&sczArguments, wzArguments, 0); | ||
303 | ExitOnFailure(hr, "Failed to copy package arguments."); | ||
304 | } | ||
305 | |||
306 | for (DWORD i = 0; i < pPackage->Bundle.cCommandLineArguments; ++i) | ||
307 | { | ||
308 | BURN_EXE_COMMAND_LINE_ARGUMENT* commandLineArgument = &pPackage->Bundle.rgCommandLineArguments[i]; | ||
309 | BOOL fCondition = FALSE; | ||
310 | |||
311 | hr = ConditionEvaluate(pVariables, commandLineArgument->sczCondition, &fCondition); | ||
312 | ExitOnFailure(hr, "Failed to evaluate bundle package command-line condition."); | ||
313 | |||
314 | if (fCondition) | ||
315 | { | ||
316 | if (sczArguments) | ||
317 | { | ||
318 | hr = StrAllocConcat(&sczArguments, L" ", 0); | ||
319 | ExitOnFailure(hr, "Failed to separate command-line arguments."); | ||
320 | } | ||
321 | |||
322 | switch (action) | ||
323 | { | ||
324 | case BOOTSTRAPPER_ACTION_STATE_INSTALL: | ||
325 | hr = StrAllocConcat(&sczArguments, commandLineArgument->sczInstallArgument, 0); | ||
326 | ExitOnFailure(hr, "Failed to get command-line argument for install."); | ||
327 | break; | ||
328 | |||
329 | case BOOTSTRAPPER_ACTION_STATE_UNINSTALL: | ||
330 | hr = StrAllocConcat(&sczArguments, commandLineArgument->sczUninstallArgument, 0); | ||
331 | ExitOnFailure(hr, "Failed to get command-line argument for uninstall."); | ||
332 | break; | ||
333 | |||
334 | case BOOTSTRAPPER_ACTION_STATE_REPAIR: | ||
335 | hr = StrAllocConcat(&sczArguments, commandLineArgument->sczRepairArgument, 0); | ||
336 | ExitOnFailure(hr, "Failed to get command-line argument for repair."); | ||
337 | break; | ||
338 | |||
339 | default: | ||
340 | hr = E_INVALIDARG; | ||
341 | ExitOnFailure(hr, "Invalid Bundle package action: %d.", action); | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | |||
346 | // build command | ||
347 | AppAppendCommandLineArgument(&sczCommand, sczExecutablePath); | ||
348 | ExitOnFailure(hr, "Failed to create executable command."); | ||
349 | |||
350 | if (!fRunEmbedded) | ||
351 | { | ||
352 | hr = StrAllocConcat(&sczCommand, L" -quiet", 0); | ||
353 | ExitOnFailure(hr, "Failed to append quiet argument."); | ||
354 | } | ||
355 | |||
356 | if (wzOperationCommandLine) | ||
357 | { | ||
358 | hr = StrAllocConcatFormatted(&sczCommand, L" %ls", wzOperationCommandLine); | ||
359 | ExitOnFailure(hr, "Failed to append operation argument."); | ||
360 | } | ||
361 | |||
362 | if (wzRelationTypeCommandLine) | ||
363 | { | ||
364 | hr = StrAllocConcatFormatted(&sczCommand, L" -%ls", wzRelationTypeCommandLine); | ||
365 | ExitOnFailure(hr, "Failed to append relation type argument."); | ||
366 | } | ||
367 | |||
368 | // Add the list of dependencies to ignore, if any, to the burn command line. | ||
369 | if (pExecuteAction->relatedBundle.sczIgnoreDependencies) | ||
370 | { | ||
371 | hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->relatedBundle.sczIgnoreDependencies); | ||
372 | ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); | ||
373 | } | ||
374 | |||
375 | // Add the list of ancestors, if any, to the burn command line. | ||
376 | if (pExecuteAction->relatedBundle.sczAncestors) | ||
377 | { | ||
378 | hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->relatedBundle.sczAncestors); | ||
379 | ExitOnFailure(hr, "Failed to append the list of ancestors to the command line."); | ||
380 | } | ||
381 | |||
382 | hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->relatedBundle.sczEngineWorkingDirectory, &sczCommand, NULL); | ||
383 | ExitOnFailure(hr, "Failed to append the custom working directory to the bundlepackage command line."); | ||
384 | |||
385 | hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczCommand, NULL); | ||
386 | ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF); | ||
387 | |||
388 | // Always add user supplied arguments last. | ||
389 | if (sczArguments && *sczArguments) | ||
390 | { | ||
391 | hr = VariableFormatString(pVariables, sczArguments, &sczArgumentsFormatted, NULL); | ||
392 | ExitOnFailure(hr, "Failed to format argument string."); | ||
393 | |||
394 | hr = VariableFormatStringObfuscated(pVariables, sczArguments, &sczArgumentsObfuscated, NULL); | ||
395 | ExitOnFailure(hr, "Failed to format obfuscated argument string."); | ||
396 | |||
397 | hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls %ls", sczCommand, sczArgumentsObfuscated); | ||
398 | ExitOnFailure(hr, "Failed to copy obfuscated formatted arguments."); | ||
399 | |||
400 | hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", sczArgumentsFormatted); | ||
401 | ExitOnFailure(hr, "Failed to copy formatted arguments."); | ||
402 | } | ||
403 | |||
404 | // Log before we add the secret pipe name and client token for embedded processes. | ||
405 | LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(action), sczExecutablePath, sczCommandObfuscated); | ||
406 | |||
407 | if (fRunEmbedded) | ||
408 | { | ||
409 | hr = EmbeddedRunBundle(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); | ||
410 | ExitOnFailure(hr, "Failed to run bundle as embedded from path: %ls", sczExecutablePath); | ||
411 | } | ||
412 | else // create and wait for the executable process while sending fake progress to allow cancel. | ||
413 | { | ||
414 | // Make the cache location of the executable the current directory to help those executables | ||
415 | // that expect stuff to be relative to them. | ||
416 | si.cb = sizeof(si); | ||
417 | if (!::CreateProcessW(sczExecutablePath, sczCommand, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, sczCachedDirectory, &si, &pi)) | ||
418 | { | ||
419 | ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", sczExecutablePath); | ||
420 | } | ||
421 | |||
422 | do | ||
423 | { | ||
424 | message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; | ||
425 | message.dwUIHint = MB_OKCANCEL; | ||
426 | message.progress.dwPercentage = 50; | ||
427 | nResult = pfnGenericMessageHandler(&message, pvContext); | ||
428 | hr = (IDOK == nResult || IDNOACTION == nResult) ? S_OK : IDCANCEL == nResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE); | ||
429 | ExitOnRootFailure(hr, "Bootstrapper application aborted during BUNDLE progress."); | ||
430 | |||
431 | hr = ProcWaitForCompletion(pi.hProcess, 500, &dwExitCode); | ||
432 | if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) != hr) | ||
433 | { | ||
434 | ExitOnFailure(hr, "Failed to wait for executable to complete: %ls", sczExecutablePath); | ||
435 | } | ||
436 | } while (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr); | ||
437 | } | ||
438 | |||
439 | hr = ExeEngineHandleExitCode(pPackage->Bundle.rgExitCodes, pPackage->Bundle.cExitCodes, dwExitCode, pRestart); | ||
440 | ExitOnRootFailure(hr, "Process returned error: 0x%x", dwExitCode); | ||
441 | |||
442 | LExit: | ||
443 | StrSecureZeroFreeString(sczArguments); | ||
444 | StrSecureZeroFreeString(sczArgumentsFormatted); | ||
445 | ReleaseStr(sczArgumentsObfuscated); | ||
446 | ReleaseStr(sczCachedDirectory); | ||
447 | ReleaseStr(sczExecutablePath); | ||
448 | StrSecureZeroFreeString(sczCommand); | ||
449 | ReleaseStr(sczCommandObfuscated); | ||
450 | |||
451 | ReleaseHandle(pi.hThread); | ||
452 | ReleaseHandle(pi.hProcess); | ||
453 | ReleaseFileHandle(hExecutableFile); | ||
454 | |||
455 | // Best effort to clear the execute package cache folder and action variables. | ||
456 | VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_CACHE_FOLDER, NULL, TRUE, FALSE); | ||
457 | VariableSetString(pVariables, BURN_BUNDLE_EXECUTE_PACKAGE_ACTION, NULL, TRUE, FALSE); | ||
458 | |||
459 | return hr; | ||
460 | } | ||