aboutsummaryrefslogtreecommitdiff
path: root/src/engine/EngineForApplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/EngineForApplication.cpp')
-rw-r--r--src/engine/EngineForApplication.cpp894
1 files changed, 894 insertions, 0 deletions
diff --git a/src/engine/EngineForApplication.cpp b/src/engine/EngineForApplication.cpp
new file mode 100644
index 00000000..eda5fc64
--- /dev/null
+++ b/src/engine/EngineForApplication.cpp
@@ -0,0 +1,894 @@
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
5static HRESULT BAEngineGetPackageCount(
6 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
7 __in BAENGINE_GETPACKAGECOUNT_ARGS* /*pArgs*/,
8 __in BAENGINE_GETPACKAGECOUNT_RESULTS* pResults
9 )
10{
11 HRESULT hr = S_OK;
12 DWORD* pcPackages = &pResults->cPackages;
13
14 *pcPackages = pContext->pEngineState->packages.cPackages;
15
16 return hr;
17}
18
19static HRESULT BAEngineGetVariableNumeric(
20 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
21 __in BAENGINE_GETVARIABLENUMERIC_ARGS* pArgs,
22 __in BAENGINE_GETVARIABLENUMERIC_RESULTS* pResults
23 )
24{
25 HRESULT hr = S_OK;
26 LPCWSTR wzVariable = pArgs->wzVariable;
27 LONGLONG* pllValue = &pResults->llValue;
28
29 if (wzVariable && *wzVariable)
30 {
31 hr = VariableGetNumeric(&pContext->pEngineState->variables, wzVariable, pllValue);
32 }
33 else
34 {
35 hr = E_INVALIDARG;
36 }
37
38 return hr;
39}
40
41static HRESULT BAEngineGetVariableString(
42 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
43 __in BAENGINE_GETVARIABLESTRING_ARGS* pArgs,
44 __in BAENGINE_GETVARIABLESTRING_RESULTS* pResults
45 )
46{
47 HRESULT hr = S_OK;
48 LPWSTR sczValue = NULL;
49 size_t cchRemaining = 0;
50 LPCWSTR wzVariable = pArgs->wzVariable;
51 LPWSTR wzValue = pResults->wzValue;
52 DWORD* pcchValue = &pResults->cchValue;
53
54 if (wzVariable && *wzVariable)
55 {
56 hr = VariableGetString(&pContext->pEngineState->variables, wzVariable, &sczValue);
57 if (SUCCEEDED(hr))
58 {
59 if (wzValue)
60 {
61 hr = ::StringCchCopyExW(wzValue, *pcchValue, sczValue, NULL, &cchRemaining, STRSAFE_FILL_BEHIND_NULL);
62 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
63 {
64 hr = E_MOREDATA;
65
66 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
67 *pcchValue = cchRemaining + 1;
68 }
69 }
70 else
71 {
72 hr = E_MOREDATA;
73
74 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
75 *pcchValue = cchRemaining + 1;
76 }
77 }
78 }
79 else
80 {
81 hr = E_INVALIDARG;
82 }
83
84 StrSecureZeroFreeString(sczValue);
85 return hr;
86}
87
88static HRESULT BAEngineGetVariableVersion(
89 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
90 __in BAENGINE_GETVARIABLEVERSION_ARGS* pArgs,
91 __in BAENGINE_GETVARIABLEVERSION_RESULTS* pResults
92 )
93{
94 HRESULT hr = S_OK;
95 LPCWSTR wzVariable = pArgs->wzVariable;
96 DWORD64* pqwValue = &pResults->qwValue;
97
98 if (wzVariable && *wzVariable)
99 {
100 hr = VariableGetVersion(&pContext->pEngineState->variables, wzVariable, pqwValue);
101 }
102 else
103 {
104 hr = E_INVALIDARG;
105 }
106
107 return hr;
108}
109
110static HRESULT BAEngineFormatString(
111 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
112 __in BAENGINE_FORMATSTRING_ARGS* pArgs,
113 __in BAENGINE_FORMATSTRING_RESULTS* pResults
114 )
115{
116 HRESULT hr = S_OK;
117 LPWSTR sczValue = NULL;
118 DWORD cchValue = 0;
119 LPCWSTR wzIn = pArgs->wzIn;
120 LPWSTR wzOut = pResults->wzOut;
121 DWORD* pcchOut = &pResults->cchOut;
122
123 if (wzIn && *wzIn)
124 {
125 hr = VariableFormatString(&pContext->pEngineState->variables, wzIn, &sczValue, &cchValue);
126 if (SUCCEEDED(hr))
127 {
128 if (wzOut)
129 {
130 hr = ::StringCchCopyExW(wzOut, *pcchOut, sczValue, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
131 if (FAILED(hr))
132 {
133 *pcchOut = cchValue;
134 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
135 {
136 hr = E_MOREDATA;
137 }
138 }
139 }
140 else
141 {
142 hr = E_MOREDATA;
143 *pcchOut = cchValue;
144 }
145 }
146 }
147 else
148 {
149 hr = E_INVALIDARG;
150 }
151
152 StrSecureZeroFreeString(sczValue);
153 return hr;
154}
155
156static HRESULT BAEngineEscapeString(
157 __in BOOTSTRAPPER_ENGINE_CONTEXT* /*pContext*/,
158 __in BAENGINE_ESCAPESTRING_ARGS* pArgs,
159 __in BAENGINE_ESCAPESTRING_RESULTS* pResults
160 )
161{
162 HRESULT hr = S_OK;
163 LPWSTR sczValue = NULL;
164 size_t cchRemaining = 0;
165 LPCWSTR wzIn = pArgs->wzIn;
166 LPWSTR wzOut = pResults->wzOut;
167 DWORD* pcchOut = &pResults->cchOut;
168
169 if (wzIn && *wzIn)
170 {
171 hr = VariableEscapeString(wzIn, &sczValue);
172 if (SUCCEEDED(hr))
173 {
174 if (wzOut)
175 {
176 hr = ::StringCchCopyExW(wzOut, *pcchOut, sczValue, NULL, &cchRemaining, STRSAFE_FILL_BEHIND_NULL);
177 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
178 {
179 hr = E_MOREDATA;
180 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
181 *pcchOut = cchRemaining;
182 }
183 }
184 else
185 {
186 ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining);
187 *pcchOut = cchRemaining;
188 }
189 }
190 }
191 else
192 {
193 hr = E_INVALIDARG;
194 }
195
196 StrSecureZeroFreeString(sczValue);
197 return hr;
198}
199
200static HRESULT BAEngineEvaluateCondition(
201 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
202 __in BAENGINE_EVALUATECONDITION_ARGS* pArgs,
203 __in BAENGINE_EVALUATECONDITION_RESULTS* pResults
204 )
205{
206 HRESULT hr = S_OK;
207 LPCWSTR wzCondition = pArgs->wzCondition;
208 BOOL* pf = &pResults->f;
209
210 if (wzCondition && *wzCondition)
211 {
212 hr = ConditionEvaluate(&pContext->pEngineState->variables, wzCondition, pf);
213 }
214 else
215 {
216 hr = E_INVALIDARG;
217 }
218
219 return hr;
220}
221
222static HRESULT BAEngineLog(
223 __in BOOTSTRAPPER_ENGINE_CONTEXT* /*pContext*/,
224 __in BAENGINE_LOG_ARGS* pArgs,
225 __in BAENGINE_LOG_RESULTS* /*pResults*/
226 )
227{
228 HRESULT hr = S_OK;
229 REPORT_LEVEL rl = REPORT_NONE;
230 BOOTSTRAPPER_LOG_LEVEL level = pArgs->level;
231 LPCWSTR wzMessage = pArgs->wzMessage;
232
233 switch (level)
234 {
235 case BOOTSTRAPPER_LOG_LEVEL_STANDARD:
236 rl = REPORT_STANDARD;
237 break;
238
239 case BOOTSTRAPPER_LOG_LEVEL_VERBOSE:
240 rl = REPORT_VERBOSE;
241 break;
242
243 case BOOTSTRAPPER_LOG_LEVEL_DEBUG:
244 rl = REPORT_DEBUG;
245 break;
246
247 case BOOTSTRAPPER_LOG_LEVEL_ERROR:
248 rl = REPORT_ERROR;
249 break;
250
251 default:
252 ExitFunction1(hr = E_INVALIDARG);
253 }
254
255 hr = LogStringLine(rl, "%ls", wzMessage);
256 ExitOnFailure(hr, "Failed to log BA message.");
257
258LExit:
259 return hr;
260}
261
262static HRESULT BAEngineSendEmbeddedError(
263 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
264 __in BAENGINE_SENDEMBEDDEDERROR_ARGS* pArgs,
265 __in BAENGINE_SENDEMBEDDEDERROR_RESULTS* pResults
266 )
267{
268 HRESULT hr = S_OK;
269 BYTE* pbData = NULL;
270 DWORD cbData = 0;
271 DWORD dwResult = 0;
272 DWORD dwErrorCode = pArgs->dwErrorCode;
273 LPCWSTR wzMessage = pArgs->wzMessage;
274 DWORD dwUIHint = pArgs->dwUIHint;
275 int* pnResult = &pResults->nResult;
276
277 if (BURN_MODE_EMBEDDED != pContext->pEngineState->mode)
278 {
279 hr = HRESULT_FROM_WIN32(ERROR_INVALID_STATE);
280 ExitOnRootFailure(hr, "BA requested to send embedded message when not in embedded mode.");
281 }
282
283 hr = BuffWriteNumber(&pbData, &cbData, dwErrorCode);
284 ExitOnFailure(hr, "Failed to write error code to message buffer.");
285
286 hr = BuffWriteString(&pbData, &cbData, wzMessage ? wzMessage : L"");
287 ExitOnFailure(hr, "Failed to write message string to message buffer.");
288
289 hr = BuffWriteNumber(&pbData, &cbData, dwUIHint);
290 ExitOnFailure(hr, "Failed to write UI hint to message buffer.");
291
292 hr = PipeSendMessage(pContext->pEngineState->embeddedConnection.hPipe, BURN_EMBEDDED_MESSAGE_TYPE_ERROR, pbData, cbData, NULL, NULL, &dwResult);
293 ExitOnFailure(hr, "Failed to send embedded message over pipe.");
294
295 *pnResult = static_cast<int>(dwResult);
296
297LExit:
298 ReleaseBuffer(pbData);
299 return hr;
300}
301
302static HRESULT BAEngineSendEmbeddedProgress(
303 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
304 __in BAENGINE_SENDEMBEDDEDPROGRESS_ARGS* pArgs,
305 __in BAENGINE_SENDEMBEDDEDPROGRESS_RESULTS* pResults
306 )
307{
308 HRESULT hr = S_OK;
309 BYTE* pbData = NULL;
310 DWORD cbData = 0;
311 DWORD dwResult = 0;
312 DWORD dwProgressPercentage = pArgs->dwProgressPercentage;
313 DWORD dwOverallProgressPercentage = pArgs->dwOverallProgressPercentage;
314 int* pnResult = &pResults->nResult;
315
316 if (BURN_MODE_EMBEDDED != pContext->pEngineState->mode)
317 {
318 hr = HRESULT_FROM_WIN32(ERROR_INVALID_STATE);
319 ExitOnRootFailure(hr, "BA requested to send embedded progress message when not in embedded mode.");
320 }
321
322 hr = BuffWriteNumber(&pbData, &cbData, dwProgressPercentage);
323 ExitOnFailure(hr, "Failed to write progress percentage to message buffer.");
324
325 hr = BuffWriteNumber(&pbData, &cbData, dwOverallProgressPercentage);
326 ExitOnFailure(hr, "Failed to write overall progress percentage to message buffer.");
327
328 hr = PipeSendMessage(pContext->pEngineState->embeddedConnection.hPipe, BURN_EMBEDDED_MESSAGE_TYPE_PROGRESS, pbData, cbData, NULL, NULL, &dwResult);
329 ExitOnFailure(hr, "Failed to send embedded progress message over pipe.");
330
331 *pnResult = static_cast<int>(dwResult);
332
333LExit:
334 ReleaseBuffer(pbData);
335 return hr;
336}
337
338static HRESULT BAEngineSetUpdate(
339 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
340 __in const BAENGINE_SETUPDATE_ARGS* pArgs,
341 __in BAENGINE_SETUPDATE_RESULTS* /*pResults*/
342 )
343{
344 HRESULT hr = S_OK;
345 LPCWSTR sczId = NULL;
346 LPWSTR sczLocalSource = NULL;
347 LPWSTR sczCommandline = NULL;
348 UUID guid = { };
349 WCHAR wzGuid[39];
350 RPC_STATUS rs = RPC_S_OK;
351 LPCWSTR wzLocalSource = pArgs->wzLocalSource;
352 LPCWSTR wzDownloadSource = pArgs->wzDownloadSource;
353 DWORD64 qwSize = pArgs->qwSize;
354 BOOTSTRAPPER_UPDATE_HASH_TYPE hashType = pArgs->hashType;
355 BYTE* rgbHash = pArgs->rgbHash;
356 DWORD cbHash = pArgs->cbHash;
357
358 ::EnterCriticalSection(&pContext->pEngineState->csActive);
359
360 if ((!wzLocalSource || !*wzLocalSource) && (!wzDownloadSource || !*wzDownloadSource))
361 {
362 UpdateUninitialize(&pContext->pEngineState->update);
363 }
364 else if (BOOTSTRAPPER_UPDATE_HASH_TYPE_NONE == hashType && (0 != cbHash || rgbHash))
365 {
366 hr = E_INVALIDARG;
367 }
368 else if (BOOTSTRAPPER_UPDATE_HASH_TYPE_SHA1 == hashType && (SHA1_HASH_LEN != cbHash || !rgbHash))
369 {
370 hr = E_INVALIDARG;
371 }
372 else
373 {
374 UpdateUninitialize(&pContext->pEngineState->update);
375
376 if (!wzLocalSource || !*wzLocalSource)
377 {
378 hr = StrAllocFormatted(&sczLocalSource, L"update\\%ls", pContext->pEngineState->registration.sczExecutableName);
379 ExitOnFailure(hr, "Failed to default local update source");
380 }
381
382 hr = CoreRecreateCommandLine(&sczCommandline, BOOTSTRAPPER_ACTION_INSTALL, pContext->pEngineState->command.display, pContext->pEngineState->command.restart, BOOTSTRAPPER_RELATION_NONE, FALSE, pContext->pEngineState->registration.sczActiveParent, pContext->pEngineState->registration.sczAncestors, NULL, pContext->pEngineState->command.wzCommandLine);
383 ExitOnFailure(hr, "Failed to recreate command-line for update bundle.");
384
385 // Per-user bundles would fail to use the downloaded update bundle, as the existing install would already be cached
386 // at the registration id's location. Here I am generating a random guid, but in the future it would be nice if the
387 // feed would provide the ID of the update.
388 if (!pContext->pEngineState->registration.fPerMachine)
389 {
390 rs = ::UuidCreate(&guid);
391 hr = HRESULT_FROM_RPC(rs);
392 ExitOnFailure(hr, "Failed to create bundle update guid.");
393
394 if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid)))
395 {
396 hr = E_OUTOFMEMORY;
397 ExitOnRootFailure(hr, "Failed to convert bundle update guid into string.");
398 }
399
400 sczId = wzGuid;
401 }
402 else
403 {
404 sczId = pContext->pEngineState->registration.sczId;
405 }
406
407 hr = PseudoBundleInitialize(FILEMAKEVERSION(rmj, rmm, rup, 0), &pContext->pEngineState->update.package, FALSE, sczId, BOOTSTRAPPER_RELATION_UPDATE, BOOTSTRAPPER_PACKAGE_STATE_ABSENT, pContext->pEngineState->registration.sczExecutableName, sczLocalSource ? sczLocalSource : wzLocalSource, wzDownloadSource, qwSize, TRUE, sczCommandline, NULL, NULL, NULL, rgbHash, cbHash);
408 ExitOnFailure(hr, "Failed to set update bundle.");
409
410 pContext->pEngineState->update.fUpdateAvailable = TRUE;
411 }
412
413LExit:
414 ::LeaveCriticalSection(&pContext->pEngineState->csActive);
415
416 ReleaseStr(sczCommandline);
417 ReleaseStr(sczLocalSource);
418 return hr;
419}
420
421static HRESULT BAEngineSetLocalSource(
422 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
423 __in BAENGINE_SETLOCALSOURCE_ARGS* pArgs,
424 __in BAENGINE_SETLOCALSOURCE_RESULTS* /*pResults*/
425 )
426{
427 HRESULT hr = S_OK;
428 BURN_CONTAINER* pContainer = NULL;
429 BURN_PAYLOAD* pPayload = NULL;
430 LPCWSTR wzPackageOrContainerId = pArgs->wzPackageOrContainerId;
431 LPCWSTR wzPayloadId = pArgs->wzPayloadId;
432 LPCWSTR wzPath = pArgs->wzPath;
433
434 ::EnterCriticalSection(&pContext->pEngineState->csActive);
435 hr = UserExperienceEnsureEngineInactive(&pContext->pEngineState->userExperience);
436 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
437
438 if (!wzPath || !*wzPath)
439 {
440 hr = E_INVALIDARG;
441 }
442 else if (wzPayloadId && * wzPayloadId)
443 {
444 hr = PayloadFindById(&pContext->pEngineState->payloads, wzPayloadId, &pPayload);
445 ExitOnFailure(hr, "BA requested unknown payload with id: %ls", wzPayloadId);
446
447 if (BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging)
448 {
449 hr = HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION);
450 ExitOnFailure(hr, "BA denied while trying to set source on embedded payload: %ls", wzPayloadId);
451 }
452
453 hr = StrAllocString(&pPayload->sczSourcePath, wzPath, 0);
454 ExitOnFailure(hr, "Failed to set source path for payload.");
455 }
456 else if (wzPackageOrContainerId && *wzPackageOrContainerId)
457 {
458 hr = ContainerFindById(&pContext->pEngineState->containers, wzPackageOrContainerId, &pContainer);
459 ExitOnFailure(hr, "BA requested unknown container with id: %ls", wzPackageOrContainerId);
460
461 hr = StrAllocString(&pContainer->sczSourcePath, wzPath, 0);
462 ExitOnFailure(hr, "Failed to set source path for container.");
463 }
464 else
465 {
466 hr = E_INVALIDARG;
467 }
468
469LExit:
470 ::LeaveCriticalSection(&pContext->pEngineState->csActive);
471 return hr;
472}
473
474static HRESULT BAEngineSetDownloadSource(
475 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
476 __in BAENGINE_SETDOWNLOADSOURCE_ARGS* pArgs,
477 __in BAENGINE_SETDOWNLOADSOURCE_RESULTS* /*pResults*/
478 )
479{
480 HRESULT hr = S_OK;
481 BURN_CONTAINER* pContainer = NULL;
482 BURN_PAYLOAD* pPayload = NULL;
483 DOWNLOAD_SOURCE* pDownloadSource = NULL;
484 LPCWSTR wzPackageOrContainerId = pArgs->wzPackageOrContainerId;
485 LPCWSTR wzPayloadId = pArgs->wzPayloadId;
486 LPCWSTR wzUrl = pArgs->wzUrl;
487 LPCWSTR wzUser = pArgs->wzUser;
488 LPCWSTR wzPassword = pArgs->wzPassword;
489
490 ::EnterCriticalSection(&pContext->pEngineState->csActive);
491 hr = UserExperienceEnsureEngineInactive(&pContext->pEngineState->userExperience);
492 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
493
494 if (wzPayloadId && *wzPayloadId)
495 {
496 hr = PayloadFindById(&pContext->pEngineState->payloads, wzPayloadId, &pPayload);
497 ExitOnFailure(hr, "BA requested unknown payload with id: %ls", wzPayloadId);
498
499 if (BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging)
500 {
501 hr = HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION);
502 ExitOnFailure(hr, "BA denied while trying to set download URL on embedded payload: %ls", wzPayloadId);
503 }
504
505 pDownloadSource = &pPayload->downloadSource;
506 }
507 else if (wzPackageOrContainerId && *wzPackageOrContainerId)
508 {
509 hr = ContainerFindById(&pContext->pEngineState->containers, wzPackageOrContainerId, &pContainer);
510 ExitOnFailure(hr, "BA requested unknown container with id: %ls", wzPackageOrContainerId);
511
512 pDownloadSource = &pContainer->downloadSource;
513 }
514 else
515 {
516 hr = E_INVALIDARG;
517 ExitOnFailure(hr, "BA did not provide container or payload id.");
518 }
519
520 if (wzUrl && *wzUrl)
521 {
522 hr = StrAllocString(&pDownloadSource->sczUrl, wzUrl, 0);
523 ExitOnFailure(hr, "Failed to set download URL.");
524
525 if (wzUser && *wzUser)
526 {
527 hr = StrAllocString(&pDownloadSource->sczUser, wzUser, 0);
528 ExitOnFailure(hr, "Failed to set download user.");
529
530 if (wzPassword && *wzPassword)
531 {
532 hr = StrAllocString(&pDownloadSource->sczPassword, wzPassword, 0);
533 ExitOnFailure(hr, "Failed to set download password.");
534 }
535 else // no password.
536 {
537 ReleaseNullStr(pDownloadSource->sczPassword);
538 }
539 }
540 else // no user means no password either.
541 {
542 ReleaseNullStr(pDownloadSource->sczUser);
543 ReleaseNullStr(pDownloadSource->sczPassword);
544 }
545 }
546 else // no URL provided means clear out the whole download source.
547 {
548 ReleaseNullStr(pDownloadSource->sczUrl);
549 ReleaseNullStr(pDownloadSource->sczUser);
550 ReleaseNullStr(pDownloadSource->sczPassword);
551 }
552
553LExit:
554 ::LeaveCriticalSection(&pContext->pEngineState->csActive);
555 return hr;
556}
557
558static HRESULT BAEngineSetVariableNumeric(
559 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
560 __in const BAENGINE_SETVARIABLENUMERIC_ARGS* pArgs,
561 __in BAENGINE_SETVARIABLENUMERIC_RESULTS* /*pResults*/
562 )
563{
564 HRESULT hr = S_OK;
565 LPCWSTR wzVariable = pArgs->wzVariable;
566 LONGLONG llValue = pArgs->llValue;
567
568 if (wzVariable && *wzVariable)
569 {
570 hr = VariableSetNumeric(&pContext->pEngineState->variables, wzVariable, llValue, FALSE);
571 ExitOnFailure(hr, "Failed to set numeric variable.");
572 }
573 else
574 {
575 hr = E_INVALIDARG;
576 ExitOnFailure(hr, "BA did not provide variable name.");
577 }
578
579LExit:
580 return hr;
581}
582
583static HRESULT BAEngineSetVariableString(
584 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
585 __in const BAENGINE_SETVARIABLESTRING_ARGS* pArgs,
586 __in BAENGINE_SETVARIABLESTRING_RESULTS* /*pResults*/
587 )
588{
589 HRESULT hr = S_OK;
590 LPCWSTR wzVariable = pArgs->wzVariable;
591 LPCWSTR wzValue = pArgs->wzValue;
592
593 if (wzVariable && *wzVariable)
594 {
595 hr = VariableSetString(&pContext->pEngineState->variables, wzVariable, wzValue, FALSE);
596 ExitOnFailure(hr, "Failed to set numeric variable.");
597 }
598 else
599 {
600 hr = E_INVALIDARG;
601 ExitOnFailure(hr, "BA did not provide variable name.");
602 }
603
604LExit:
605 return hr;
606}
607
608static HRESULT BAEngineSetVariableVersion(
609 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
610 __in const BAENGINE_SETVARIABLEVERSION_ARGS* pArgs,
611 __in BAENGINE_SETVARIABLEVERSION_RESULTS* /*pResults*/
612 )
613{
614 HRESULT hr = S_OK;
615 LPCWSTR wzVariable = pArgs->wzVariable;
616 DWORD64 qwValue = pArgs->qwValue;
617
618 if (wzVariable && *wzVariable)
619 {
620 hr = VariableSetVersion(&pContext->pEngineState->variables, wzVariable, qwValue, FALSE);
621 ExitOnFailure(hr, "Failed to set version variable.");
622 }
623 else
624 {
625 hr = E_INVALIDARG;
626 ExitOnFailure(hr, "BA did not provide variable name.");
627 }
628
629LExit:
630 return hr;
631}
632
633static HRESULT BAEngineCloseSplashScreen(
634 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
635 __in const BAENGINE_CLOSESPLASHSCREEN_ARGS* /*pArgs*/,
636 __in BAENGINE_CLOSESPLASHSCREEN_RESULTS* /*pResults*/
637 )
638{
639 // If the splash screen is still around, close it.
640 if (::IsWindow(pContext->pEngineState->command.hwndSplashScreen))
641 {
642 ::PostMessageW(pContext->pEngineState->command.hwndSplashScreen, WM_CLOSE, 0, 0);
643 }
644
645 return S_OK;
646}
647
648static HRESULT BAEngineDetect(
649 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
650 __in BAENGINE_DETECT_ARGS* pArgs,
651 __in BAENGINE_DETECT_RESULTS* /*pResults*/
652 )
653{
654 HRESULT hr = S_OK;
655
656 if (!::PostThreadMessageW(pContext->dwThreadId, WM_BURN_DETECT, 0, reinterpret_cast<LPARAM>(pArgs->hwndParent)))
657 {
658 ExitWithLastError(hr, "Failed to post detect message.");
659 }
660
661LExit:
662 return hr;
663}
664
665static HRESULT BAEnginePlan(
666 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
667 __in const BAENGINE_PLAN_ARGS* pArgs,
668 __in BAENGINE_PLAN_RESULTS* /*pResults*/
669 )
670{
671 HRESULT hr = S_OK;
672 BOOTSTRAPPER_ACTION action = pArgs->action;
673
674 if (!::PostThreadMessageW(pContext->dwThreadId, WM_BURN_PLAN, 0, action))
675 {
676 ExitWithLastError(hr, "Failed to post plan message.");
677 }
678
679LExit:
680 return hr;
681}
682
683static HRESULT BAEngineElevate(
684 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
685 __in const BAENGINE_ELEVATE_ARGS* pArgs,
686 __in BAENGINE_ELEVATE_RESULTS* /*pResults*/
687 )
688{
689 HRESULT hr = S_OK;
690
691 if (INVALID_HANDLE_VALUE != pContext->pEngineState->companionConnection.hPipe)
692 {
693 hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
694 }
695 else if (!::PostThreadMessageW(pContext->dwThreadId, WM_BURN_ELEVATE, 0, reinterpret_cast<LPARAM>(pArgs->hwndParent)))
696 {
697 ExitWithLastError(hr, "Failed to post elevate message.");
698 }
699
700LExit:
701 return hr;
702}
703
704static HRESULT BAEngineApply(
705 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
706 __in const BAENGINE_APPLY_ARGS* pArgs,
707 __in BAENGINE_APPLY_RESULTS* /*pResults*/
708 )
709{
710 HRESULT hr = S_OK;
711
712 if (!::PostThreadMessageW(pContext->dwThreadId, WM_BURN_APPLY, 0, reinterpret_cast<LPARAM>(pArgs->hwndParent)))
713 {
714 ExitWithLastError(hr, "Failed to post apply message.");
715 }
716
717LExit:
718 return hr;
719}
720
721static HRESULT BAEngineQuit(
722 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
723 __in const BAENGINE_QUIT_ARGS* pArgs,
724 __in BAENGINE_QUIT_RESULTS* /*pResults*/
725 )
726{
727 HRESULT hr = S_OK;
728
729 if (!::PostThreadMessageW(pContext->dwThreadId, WM_BURN_QUIT, static_cast<WPARAM>(pArgs->dwExitCode), 0))
730 {
731 ExitWithLastError(hr, "Failed to post shutdown message.");
732 }
733
734LExit:
735 return hr;
736}
737
738static HRESULT BAEngineLaunchApprovedExe(
739 __in BOOTSTRAPPER_ENGINE_CONTEXT* pContext,
740 __in const BAENGINE_LAUNCHAPPROVEDEXE_ARGS* pArgs,
741 __in BAENGINE_LAUNCHAPPROVEDEXE_RESULTS* /*pResults*/
742 )
743{
744 HRESULT hr = S_OK;
745 BURN_APPROVED_EXE* pApprovedExe = NULL;
746 BOOL fLeaveCriticalSection = FALSE;
747 BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe = (BURN_LAUNCH_APPROVED_EXE*)MemAlloc(sizeof(BURN_LAUNCH_APPROVED_EXE), TRUE);
748 HWND hwndParent = pArgs->hwndParent;
749 LPCWSTR wzApprovedExeForElevationId = pArgs->wzApprovedExeForElevationId;
750 LPCWSTR wzArguments = pArgs->wzArguments;
751 DWORD dwWaitForInputIdleTimeout = pArgs->dwWaitForInputIdleTimeout;
752
753 ::EnterCriticalSection(&pContext->pEngineState->csActive);
754 fLeaveCriticalSection = TRUE;
755 hr = UserExperienceEnsureEngineInactive(&pContext->pEngineState->userExperience);
756 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
757
758 if (!wzApprovedExeForElevationId || !*wzApprovedExeForElevationId)
759 {
760 ExitFunction1(hr = E_INVALIDARG);
761 }
762
763 hr = ApprovedExesFindById(&pContext->pEngineState->approvedExes, wzApprovedExeForElevationId, &pApprovedExe);
764 ExitOnFailure(hr, "BA requested unknown approved exe with id: %ls", wzApprovedExeForElevationId);
765
766 ::LeaveCriticalSection(&pContext->pEngineState->csActive);
767 fLeaveCriticalSection = FALSE;
768
769 hr = StrAllocString(&pLaunchApprovedExe->sczId, wzApprovedExeForElevationId, NULL);
770 ExitOnFailure(hr, "Failed to copy the id.");
771
772 if (wzArguments)
773 {
774 hr = StrAllocString(&pLaunchApprovedExe->sczArguments, wzArguments, NULL);
775 ExitOnFailure(hr, "Failed to copy the arguments.");
776 }
777
778 pLaunchApprovedExe->dwWaitForInputIdleTimeout = dwWaitForInputIdleTimeout;
779
780 pLaunchApprovedExe->hwndParent = hwndParent;
781
782 if (!::PostThreadMessageW(pContext->dwThreadId, WM_BURN_LAUNCH_APPROVED_EXE, 0, reinterpret_cast<LPARAM>(pLaunchApprovedExe)))
783 {
784 ExitWithLastError(hr, "Failed to post launch approved exe message.");
785 }
786
787LExit:
788 if (fLeaveCriticalSection)
789 {
790 ::LeaveCriticalSection(&pContext->pEngineState->csActive);
791 }
792
793 if (FAILED(hr))
794 {
795 ApprovedExesUninitializeLaunch(pLaunchApprovedExe);
796 }
797
798 return hr;
799}
800
801HRESULT WINAPI EngineForApplicationProc(
802 __in BOOTSTRAPPER_ENGINE_MESSAGE message,
803 __in const LPVOID pvArgs,
804 __inout LPVOID pvResults,
805 __in_opt LPVOID pvContext
806 )
807{
808 HRESULT hr = S_OK;
809 BOOTSTRAPPER_ENGINE_CONTEXT* pContext = reinterpret_cast<BOOTSTRAPPER_ENGINE_CONTEXT*>(pvContext);
810
811 if (!pContext || !pvArgs || !pvResults)
812 {
813 ExitFunction1(hr = E_INVALIDARG);
814 }
815
816 switch (message)
817 {
818 case BOOTSTRAPPER_ENGINE_MESSAGE_GETPACKAGECOUNT:
819 hr = BAEngineGetPackageCount(pContext, reinterpret_cast<BAENGINE_GETPACKAGECOUNT_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_GETPACKAGECOUNT_RESULTS*>(pvResults));
820 break;
821 case BOOTSTRAPPER_ENGINE_MESSAGE_GETVARIABLENUMERIC:
822 hr = BAEngineGetVariableNumeric(pContext, reinterpret_cast<BAENGINE_GETVARIABLENUMERIC_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_GETVARIABLENUMERIC_RESULTS*>(pvResults));
823 break;
824 case BOOTSTRAPPER_ENGINE_MESSAGE_GETVARIABLESTRING:
825 hr = BAEngineGetVariableString(pContext, reinterpret_cast<BAENGINE_GETVARIABLESTRING_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_GETVARIABLESTRING_RESULTS*>(pvResults));
826 break;
827 case BOOTSTRAPPER_ENGINE_MESSAGE_GETVARIABLEVERSION:
828 hr = BAEngineGetVariableVersion(pContext, reinterpret_cast<BAENGINE_GETVARIABLEVERSION_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_GETVARIABLEVERSION_RESULTS*>(pvResults));
829 break;
830 case BOOTSTRAPPER_ENGINE_MESSAGE_FORMATSTRING:
831 hr = BAEngineFormatString(pContext, reinterpret_cast<BAENGINE_FORMATSTRING_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_FORMATSTRING_RESULTS*>(pvResults));
832 break;
833 case BOOTSTRAPPER_ENGINE_MESSAGE_ESCAPESTRING:
834 hr = BAEngineEscapeString(pContext, reinterpret_cast<BAENGINE_ESCAPESTRING_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_ESCAPESTRING_RESULTS*>(pvResults));
835 break;
836 case BOOTSTRAPPER_ENGINE_MESSAGE_EVALUATECONDITION:
837 hr = BAEngineEvaluateCondition(pContext, reinterpret_cast<BAENGINE_EVALUATECONDITION_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_EVALUATECONDITION_RESULTS*>(pvResults));
838 break;
839 case BOOTSTRAPPER_ENGINE_MESSAGE_LOG:
840 hr = BAEngineLog(pContext, reinterpret_cast<BAENGINE_LOG_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_LOG_RESULTS*>(pvResults));
841 break;
842 case BOOTSTRAPPER_ENGINE_MESSAGE_SENDEMBEDDEDERROR:
843 hr = BAEngineSendEmbeddedError(pContext, reinterpret_cast<BAENGINE_SENDEMBEDDEDERROR_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_SENDEMBEDDEDERROR_RESULTS*>(pvResults));
844 break;
845 case BOOTSTRAPPER_ENGINE_MESSAGE_SENDEMBEDDEDPROGRESS:
846 hr = BAEngineSendEmbeddedProgress(pContext, reinterpret_cast<BAENGINE_SENDEMBEDDEDPROGRESS_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_SENDEMBEDDEDPROGRESS_RESULTS*>(pvResults));
847 break;
848 case BOOTSTRAPPER_ENGINE_MESSAGE_SETUPDATE:
849 hr = BAEngineSetUpdate(pContext, reinterpret_cast<BAENGINE_SETUPDATE_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_SETUPDATE_RESULTS*>(pvResults));
850 break;
851 case BOOTSTRAPPER_ENGINE_MESSAGE_SETLOCALSOURCE:
852 hr = BAEngineSetLocalSource(pContext, reinterpret_cast<BAENGINE_SETLOCALSOURCE_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_SETLOCALSOURCE_RESULTS*>(pvResults));
853 break;
854 case BOOTSTRAPPER_ENGINE_MESSAGE_SETDOWNLOADSOURCE:
855 hr = BAEngineSetDownloadSource(pContext, reinterpret_cast<BAENGINE_SETDOWNLOADSOURCE_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_SETDOWNLOADSOURCE_RESULTS*>(pvResults));
856 break;
857 case BOOTSTRAPPER_ENGINE_MESSAGE_SETVARIABLENUMERIC:
858 hr = BAEngineSetVariableNumeric(pContext, reinterpret_cast<BAENGINE_SETVARIABLENUMERIC_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_SETVARIABLENUMERIC_RESULTS*>(pvResults));
859 break;
860 case BOOTSTRAPPER_ENGINE_MESSAGE_SETVARIABLESTRING:
861 hr = BAEngineSetVariableString(pContext, reinterpret_cast<BAENGINE_SETVARIABLESTRING_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_SETVARIABLESTRING_RESULTS*>(pvResults));
862 break;
863 case BOOTSTRAPPER_ENGINE_MESSAGE_SETVARIABLEVERSION:
864 hr = BAEngineSetVariableVersion(pContext, reinterpret_cast<BAENGINE_SETVARIABLEVERSION_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_SETVARIABLEVERSION_RESULTS*>(pvResults));
865 break;
866 case BOOTSTRAPPER_ENGINE_MESSAGE_CLOSESPLASHSCREEN:
867 hr = BAEngineCloseSplashScreen(pContext, reinterpret_cast<BAENGINE_CLOSESPLASHSCREEN_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_CLOSESPLASHSCREEN_RESULTS*>(pvResults));
868 break;
869 case BOOTSTRAPPER_ENGINE_MESSAGE_DETECT:
870 hr = BAEngineDetect(pContext, reinterpret_cast<BAENGINE_DETECT_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_DETECT_RESULTS*>(pvResults));
871 break;
872 case BOOTSTRAPPER_ENGINE_MESSAGE_PLAN:
873 hr = BAEnginePlan(pContext, reinterpret_cast<BAENGINE_PLAN_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_PLAN_RESULTS*>(pvResults));
874 break;
875 case BOOTSTRAPPER_ENGINE_MESSAGE_ELEVATE:
876 hr = BAEngineElevate(pContext, reinterpret_cast<BAENGINE_ELEVATE_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_ELEVATE_RESULTS*>(pvResults));
877 break;
878 case BOOTSTRAPPER_ENGINE_MESSAGE_APPLY:
879 hr = BAEngineApply(pContext, reinterpret_cast<BAENGINE_APPLY_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_APPLY_RESULTS*>(pvResults));
880 break;
881 case BOOTSTRAPPER_ENGINE_MESSAGE_QUIT:
882 hr = BAEngineQuit(pContext, reinterpret_cast<BAENGINE_QUIT_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_QUIT_RESULTS*>(pvResults));
883 break;
884 case BOOTSTRAPPER_ENGINE_MESSAGE_LAUNCHAPPROVEDEXE:
885 hr = BAEngineLaunchApprovedExe(pContext, reinterpret_cast<BAENGINE_LAUNCHAPPROVEDEXE_ARGS*>(pvArgs), reinterpret_cast<BAENGINE_LAUNCHAPPROVEDEXE_RESULTS*>(pvResults));
886 break;
887 default:
888 hr = E_NOTIMPL;
889 break;
890 }
891
892LExit:
893 return hr;
894}