main
cpp 965 lines 26.3 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
6 static HRESULT CopyStringToExternal(
7 __in_z LPWSTR wzValue,
8 __in_z_opt LPWSTR wzBuffer,
9 __inout SIZE_T* pcchBuffer
10 );
11 static HRESULT ProcessUnknownEmbeddedMessages(
12 __in PIPE_MESSAGE* /*pMsg*/,
13 __in_opt LPVOID /*pvContext*/,
14 __out DWORD* pdwResult
15 );
16 static HRESULT EnqueueAction(
17 __in BAENGINE_CONTEXT* pEngineContext,
18 __inout BAENGINE_ACTION** ppAction
19 );
20
21 // function definitions
22
23 void ExternalEngineGetPackageCount(
24 __in BURN_ENGINE_STATE* pEngineState,
25 __out DWORD* pcPackages
26 )
27 {
28 *pcPackages = pEngineState->packages.cPackages;
29 }
30
31 HRESULT ExternalEngineGetVariableNumeric(
32 __in BURN_ENGINE_STATE* pEngineState,
33 __in_z LPCWSTR wzVariable,
34 __out LONGLONG* pllValue
35 )
36 {
37 HRESULT hr = S_OK;
38
39 if (wzVariable && *wzVariable)
40 {
41 hr = VariableGetNumeric(&pEngineState->variables, wzVariable, pllValue);
42 }
43 else
44 {
45 *pllValue = 0;
46 hr = E_INVALIDARG;
47 }
48
49 return hr;
50 }
51
52 HRESULT ExternalEngineGetVariableString(
53 __in BURN_ENGINE_STATE* pEngineState,
54 __in_z LPCWSTR wzVariable,
55 __out_ecount_opt(*pcchValue) LPWSTR wzValue,
56 __inout SIZE_T* pcchValue
57 )
58 {
59 HRESULT hr = S_OK;
60 LPWSTR sczValue = NULL;
61
62 if (wzVariable && *wzVariable)
63 {
64 hr = VariableGetString(&pEngineState->variables, wzVariable, &sczValue);
65 if (SUCCEEDED(hr))
66 {
67 hr = CopyStringToExternal(sczValue, wzValue, pcchValue);
68 }
69 }
70 else
71 {
72 hr = E_INVALIDARG;
73 }
74
75 StrSecureZeroFreeString(sczValue);
76
77 return hr;
78 }
79
80 HRESULT ExternalEngineGetVariableVersion(
81 __in BURN_ENGINE_STATE* pEngineState,
82 __in_z LPCWSTR wzVariable,
83 __out_ecount_opt(*pcchValue) LPWSTR wzValue,
84 __inout SIZE_T* pcchValue
85 )
86 {
87 HRESULT hr = S_OK;
88 VERUTIL_VERSION* pVersion = NULL;
89
90 if (wzVariable && *wzVariable)
91 {
92 hr = VariableGetVersion(&pEngineState->variables, wzVariable, &pVersion);
93 if (SUCCEEDED(hr))
94 {
95 hr = CopyStringToExternal(pVersion->sczVersion, wzValue, pcchValue);
96 }
97 }
98 else
99 {
100 hr = E_INVALIDARG;
101 }
102
103 ReleaseVerutilVersion(pVersion);
104
105 return hr;
106 }
107
108 HRESULT ExternalEngineFormatString(
109 __in BURN_ENGINE_STATE* pEngineState,
110 __in_z LPCWSTR wzIn,
111 __out_ecount_opt(*pcchOut) LPWSTR wzOut,
112 __inout SIZE_T* pcchOut
113 )
114 {
115 HRESULT hr = S_OK;
116 LPWSTR sczValue = NULL;
117
118 if (wzIn && *wzIn)
119 {
120 hr = VariableFormatString(&pEngineState->variables, wzIn, &sczValue, NULL);
121 if (SUCCEEDED(hr))
122 {
123 hr = CopyStringToExternal(sczValue, wzOut, pcchOut);
124 }
125 }
126 else
127 {
128 hr = E_INVALIDARG;
129 }
130
131 StrSecureZeroFreeString(sczValue);
132
133 return hr;
134 }
135
136 HRESULT ExternalEngineEscapeString(
137 __in_z LPCWSTR wzIn,
138 __out_ecount_opt(*pcchOut) LPWSTR wzOut,
139 __inout SIZE_T* pcchOut
140 )
141 {
142 HRESULT hr = S_OK;
143 LPWSTR sczValue = NULL;
144
145 if (wzIn && *wzIn)
146 {
147 hr = VariableEscapeString(wzIn, &sczValue);
148 if (SUCCEEDED(hr))
149 {
150 hr = CopyStringToExternal(sczValue, wzOut, pcchOut);
151 }
152 }
153 else
154 {
155 hr = E_INVALIDARG;
156 }
157
158 StrSecureZeroFreeString(sczValue);
159
160 return hr;
161 }
162
163 HRESULT ExternalEngineEvaluateCondition(
164 __in BURN_ENGINE_STATE* pEngineState,
165 __in_z LPCWSTR wzCondition,
166 __out BOOL* pf
167 )
168 {
169 HRESULT hr = S_OK;
170
171 if (wzCondition && *wzCondition)
172 {
173 hr = ConditionEvaluate(&pEngineState->variables, wzCondition, pf);
174 }
175 else
176 {
177 *pf = FALSE;
178 hr = E_INVALIDARG;
179 }
180
181 return hr;
182 }
183
184 HRESULT ExternalEngineLog(
185 __in REPORT_LEVEL rl,
186 __in_z LPCWSTR wzMessage
187 )
188 {
189 HRESULT hr = S_OK;
190
191 hr = LogStringLine(rl, "%ls", wzMessage);
192
193 return hr;
194 }
195
196 HRESULT ExternalEngineSendEmbeddedError(
197 __in BURN_ENGINE_STATE* pEngineState,
198 __in const DWORD dwErrorCode,
199 __in_z LPCWSTR wzMessage,
200 __in const DWORD dwUIHint,
201 __out int* pnResult
202 )
203 {
204 HRESULT hr = S_OK;
205 BYTE* pbData = NULL;
206 SIZE_T cbData = 0;
207 DWORD dwResult = *pnResult = 0;
208
209 if (BURN_MODE_EMBEDDED != pEngineState->internalCommand.mode)
210 {
211 hr = HRESULT_FROM_WIN32(ERROR_INVALID_STATE);
212 ExitOnRootFailure(hr, "BA requested to send embedded message when not in embedded mode.");
213 }
214
215 hr = BuffWriteNumber(&pbData, &cbData, dwErrorCode);
216 ExitOnFailure(hr, "Failed to write error code to message buffer.");
217
218 hr = BuffWriteString(&pbData, &cbData, wzMessage ? wzMessage : L"");
219 ExitOnFailure(hr, "Failed to write message string to message buffer.");
220
221 hr = BuffWriteNumber(&pbData, &cbData, dwUIHint);
222 ExitOnFailure(hr, "Failed to write UI hint to message buffer.");
223
224 hr = BurnPipeSendMessage(pEngineState->embeddedConnection.hPipe, BURN_EMBEDDED_MESSAGE_TYPE_ERROR, pbData, cbData, ProcessUnknownEmbeddedMessages, NULL, &dwResult);
225 ExitOnFailure(hr, "Failed to send embedded message over pipe.");
226
227 *pnResult = static_cast<int>(dwResult);
228
229 LExit:
230 ReleaseMem(pbData);
231
232 return hr;
233 }
234
235 HRESULT ExternalEngineSendEmbeddedProgress(
236 __in BURN_ENGINE_STATE* pEngineState,
237 __in const DWORD dwProgressPercentage,
238 __in const DWORD dwOverallProgressPercentage,
239 __out int* pnResult
240 )
241 {
242 HRESULT hr = S_OK;
243 BYTE* pbData = NULL;
244 SIZE_T cbData = 0;
245 DWORD dwResult = *pnResult = 0;
246
247 if (BURN_MODE_EMBEDDED != pEngineState->internalCommand.mode)
248 {
249 hr = HRESULT_FROM_WIN32(ERROR_INVALID_STATE);
250 ExitOnRootFailure(hr, "BA requested to send embedded progress message when not in embedded mode.");
251 }
252
253 hr = BuffWriteNumber(&pbData, &cbData, dwProgressPercentage);
254 ExitOnFailure(hr, "Failed to write progress percentage to message buffer.");
255
256 hr = BuffWriteNumber(&pbData, &cbData, dwOverallProgressPercentage);
257 ExitOnFailure(hr, "Failed to write overall progress percentage to message buffer.");
258
259 hr = BurnPipeSendMessage(pEngineState->embeddedConnection.hPipe, BURN_EMBEDDED_MESSAGE_TYPE_PROGRESS, pbData, cbData, ProcessUnknownEmbeddedMessages, NULL, &dwResult);
260 ExitOnFailure(hr, "Failed to send embedded progress message over pipe.");
261
262 *pnResult = static_cast<int>(dwResult);
263
264 LExit:
265 ReleaseMem(pbData);
266
267 return hr;
268 }
269
270 HRESULT ExternalEngineSetUpdate(
271 __in BURN_ENGINE_STATE* pEngineState,
272 __in_z_opt LPCWSTR wzLocalSource,
273 __in_z_opt LPCWSTR wzDownloadSource,
274 __in const DWORD64 qwSize,
275 __in const BOOTSTRAPPER_UPDATE_HASH_TYPE hashType,
276 __in_opt LPCWSTR wzHash,
277 __in_z_opt LPCWSTR wzUpdatePackageId
278 )
279 {
280 HRESULT hr = S_OK;
281 BOOL fLeaveCriticalSection = FALSE;
282 LPWSTR sczFileRelativePath = NULL;
283 LPWSTR sczCommandline = NULL;
284 UUID guid = { };
285 WCHAR wzCacheId[39];
286 RPC_STATUS rs = RPC_S_OK;
287 BOOL fRemove = (!wzLocalSource || !*wzLocalSource) && (!wzDownloadSource || !*wzDownloadSource);
288
289 // Consider allowing the BA to pass this name in, like the UpdatePackageId can be passed in.
290 LPCWSTR wzFileName = NULL;
291
292 ::EnterCriticalSection(&pEngineState->userExperience.csEngineActive);
293 fLeaveCriticalSection = TRUE;
294 hr = BootstrapperApplicationEnsureEngineInactive(&pEngineState->userExperience);
295 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
296
297 if (!fRemove)
298 {
299 if (BOOTSTRAPPER_UPDATE_HASH_TYPE_NONE == hashType && wzHash && *wzHash)
300 {
301 ExitFunction1(hr = E_INVALIDARG);
302 }
303 else if (BOOTSTRAPPER_UPDATE_HASH_TYPE_SHA512 == hashType && (!wzHash || !*wzHash || SHA512_HASH_LEN * 2 != lstrlenW(wzHash)))
304 {
305 ExitFunction1(hr = E_INVALIDARG);
306 }
307 }
308
309 UpdateUninitialize(&pEngineState->update);
310
311 if (fRemove)
312 {
313 ExitFunction();
314 }
315
316 hr = CoreCreateUpdateBundleCommandLine(&sczCommandline, &pEngineState->internalCommand, &pEngineState->command);
317 ExitOnFailure(hr, "Failed to create command-line for update bundle.");
318
319 // Always generate a new CacheId for a location to where we can download then cache the update bundle. This running
320 // bundle will clean that cached location when it is done while the update bundle caches itself in its official cache
321 // location during its execution.
322 rs = ::UuidCreate(&guid);
323 hr = HRESULT_FROM_RPC(rs);
324 ExitOnFailure(hr, "Failed to create bundle update guid.");
325
326 if (!::StringFromGUID2(guid, wzCacheId, countof(wzCacheId)))
327 {
328 hr = E_INSUFFICIENT_BUFFER;
329 ExitOnRootFailure(hr, "Failed to convert bundle update guid into string.");
330 }
331
332 // If the update package id is not provided, use the cache id.
333 if (!wzUpdatePackageId || !*wzUpdatePackageId)
334 {
335 wzUpdatePackageId = wzCacheId;
336 }
337
338 // If the file name is not provided, use the current bundle's name. Not a great option but it is the best we have.
339 if (!wzFileName || !*wzFileName)
340 {
341 wzFileName = pEngineState->registration.sczExecutableName;
342 }
343
344 // Download the update bundle into a relative folder using the update package id. Ths is important because this running bundle is
345 // in the root of one of search paths used in source resolution. Thus, if when wzFileName is the same as the running bundle, the
346 // running bundle will be found first and the updated bundle will not actually be downloaded.
347 hr = StrAllocFormatted(&sczFileRelativePath, L"%ls\\%ls", wzUpdatePackageId, wzFileName);
348 ExitOnFailure(hr, "Failed to build bundle update file path.");
349
350 if (!wzLocalSource || !*wzLocalSource)
351 {
352 wzLocalSource = sczFileRelativePath;
353 }
354
355 hr = PseudoBundleInitializeUpdateBundle(&pEngineState->update.package, wzUpdatePackageId, wzCacheId, sczFileRelativePath, wzLocalSource, wzDownloadSource, qwSize, sczCommandline, wzHash);
356 ExitOnFailure(hr, "Failed to set update bundle.");
357
358 pEngineState->update.fUpdateAvailable = TRUE;
359
360 LExit:
361 if (fLeaveCriticalSection)
362 {
363 ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive);
364 }
365
366 ReleaseStr(sczCommandline);
367 ReleaseStr(sczFileRelativePath);
368
369 return hr;
370 }
371
372 HRESULT ExternalEngineSetLocalSource(
373 __in BURN_ENGINE_STATE* pEngineState,
374 __in_z_opt LPCWSTR wzPackageOrContainerId,
375 __in_z_opt LPCWSTR wzPayloadId,
376 __in_z LPCWSTR wzPath
377 )
378 {
379 HRESULT hr = S_OK;
380 BURN_CONTAINER* pContainer = NULL;
381 BURN_PAYLOAD* pPayload = NULL;
382
383 ::EnterCriticalSection(&pEngineState->userExperience.csEngineActive);
384 hr = BootstrapperApplicationEnsureEngineInactive(&pEngineState->userExperience);
385 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
386
387 if (!wzPath || !*wzPath)
388 {
389 hr = E_INVALIDARG;
390 }
391 else if (wzPayloadId && *wzPayloadId)
392 {
393 hr = PayloadFindById(&pEngineState->payloads, wzPayloadId, &pPayload);
394 ExitOnFailure(hr, "BA requested unknown payload with id: %ls", wzPayloadId);
395
396 hr = StrAllocString(&pPayload->sczSourcePath, wzPath, 0);
397 ExitOnFailure(hr, "Failed to set source path for payload.");
398 }
399 else if (wzPackageOrContainerId && *wzPackageOrContainerId)
400 {
401 hr = ContainerFindById(&pEngineState->containers, wzPackageOrContainerId, &pContainer);
402 ExitOnFailure(hr, "BA requested unknown container with id: %ls", wzPackageOrContainerId);
403
404 hr = StrAllocString(&pContainer->sczSourcePath, wzPath, 0);
405 ExitOnFailure(hr, "Failed to set source path for container.");
406 }
407 else
408 {
409 hr = E_INVALIDARG;
410 }
411
412 LExit:
413 ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive);
414
415 return hr;
416 }
417
418 HRESULT ExternalEngineSetDownloadSource(
419 __in BURN_ENGINE_STATE* pEngineState,
420 __in_z_opt LPCWSTR wzPackageOrContainerId,
421 __in_z_opt LPCWSTR wzPayloadId,
422 __in_z_opt LPCWSTR wzUrl,
423 __in_z_opt LPCWSTR wzUser,
424 __in_z_opt LPCWSTR wzPassword,
425 __in_z_opt LPCWSTR wzAuthorizationHeader
426 )
427 {
428 HRESULT hr = S_OK;
429 BURN_CONTAINER* pContainer = NULL;
430 BURN_PAYLOAD* pPayload = NULL;
431 DOWNLOAD_SOURCE* pDownloadSource = NULL;
432
433 ::EnterCriticalSection(&pEngineState->userExperience.csEngineActive);
434 hr = BootstrapperApplicationEnsureEngineInactive(&pEngineState->userExperience);
435 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
436
437 if (wzPayloadId && *wzPayloadId)
438 {
439 hr = PayloadFindById(&pEngineState->payloads, wzPayloadId, &pPayload);
440 ExitOnFailure(hr, "BA requested unknown payload with id: %ls", wzPayloadId);
441
442 pDownloadSource = &pPayload->downloadSource;
443 }
444 else if (wzPackageOrContainerId && *wzPackageOrContainerId)
445 {
446 hr = ContainerFindById(&pEngineState->containers, wzPackageOrContainerId, &pContainer);
447 ExitOnFailure(hr, "BA requested unknown container with id: %ls", wzPackageOrContainerId);
448
449 pDownloadSource = &pContainer->downloadSource;
450 }
451 else
452 {
453 hr = E_INVALIDARG;
454 ExitOnFailure(hr, "BA did not provide container or payload id.");
455 }
456
457 if (wzAuthorizationHeader && *wzAuthorizationHeader)
458 {
459 hr = StrAllocString(&pDownloadSource->sczAuthorizationHeader, wzAuthorizationHeader, 0);
460 ExitOnFailure(hr, "Failed to set download authorization header.");
461
462 // Authorization header means no user.
463 ReleaseNullStr(pDownloadSource->sczUser);
464 ReleaseNullStr(pDownloadSource->sczPassword);
465 }
466 else if (wzUrl && *wzUrl)
467 {
468 hr = StrAllocString(&pDownloadSource->sczUrl, wzUrl, 0);
469 ExitOnFailure(hr, "Failed to set download URL.");
470
471 if (wzUser && *wzUser)
472 {
473 hr = StrAllocString(&pDownloadSource->sczUser, wzUser, 0);
474 ExitOnFailure(hr, "Failed to set download user.");
475
476 if (wzPassword && *wzPassword)
477 {
478 hr = StrAllocString(&pDownloadSource->sczPassword, wzPassword, 0);
479 ExitOnFailure(hr, "Failed to set download password.");
480 }
481 else // no password.
482 {
483 ReleaseNullStr(pDownloadSource->sczPassword);
484 }
485
486 // User means no authorization header.
487 ReleaseNullStr(pDownloadSource->sczAuthorizationHeader);
488 }
489 else // no user means no password either.
490 {
491 ReleaseNullStr(pDownloadSource->sczUser);
492 ReleaseNullStr(pDownloadSource->sczPassword);
493 }
494 }
495 else // no URL provided means clear out the whole download source.
496 {
497 ReleaseNullStr(pDownloadSource->sczUrl);
498 ReleaseNullStr(pDownloadSource->sczUser);
499 ReleaseNullStr(pDownloadSource->sczPassword);
500 }
501
502 LExit:
503 ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive);
504
505 return hr;
506 }
507
508 HRESULT ExternalEngineSetVariableNumeric(
509 __in BURN_ENGINE_STATE* pEngineState,
510 __in_z LPCWSTR wzVariable,
511 __in const LONGLONG llValue
512 )
513 {
514 HRESULT hr = S_OK;
515
516 if (wzVariable && *wzVariable)
517 {
518 hr = VariableSetNumeric(&pEngineState->variables, wzVariable, llValue, FALSE);
519 ExitOnFailure(hr, "Failed to set numeric variable.");
520 }
521 else
522 {
523 hr = E_INVALIDARG;
524 ExitOnFailure(hr, "SetVariableNumeric did not provide variable name.");
525 }
526
527 LExit:
528 return hr;
529 }
530
531 HRESULT ExternalEngineSetVariableString(
532 __in BURN_ENGINE_STATE* pEngineState,
533 __in_z LPCWSTR wzVariable,
534 __in_z_opt LPCWSTR wzValue,
535 __in const BOOL fFormatted
536 )
537 {
538 HRESULT hr = S_OK;
539
540 if (wzVariable && *wzVariable)
541 {
542 hr = VariableSetString(&pEngineState->variables, wzVariable, wzValue, FALSE, fFormatted);
543 ExitOnFailure(hr, "Failed to set string variable.");
544 }
545 else
546 {
547 hr = E_INVALIDARG;
548 ExitOnFailure(hr, "SetVariableString did not provide variable name.");
549 }
550
551 LExit:
552 return hr;
553 }
554
555 HRESULT ExternalEngineSetVariableVersion(
556 __in BURN_ENGINE_STATE* pEngineState,
557 __in_z LPCWSTR wzVariable,
558 __in_z_opt LPCWSTR wzValue
559 )
560 {
561 HRESULT hr = S_OK;
562 VERUTIL_VERSION* pVersion = NULL;
563
564 if (wzVariable && *wzVariable)
565 {
566 if (wzValue)
567 {
568 hr = VerParseVersion(wzValue, 0, FALSE, &pVersion);
569 ExitOnFailure(hr, "Failed to parse new version value.");
570 }
571
572 hr = VariableSetVersion(&pEngineState->variables, wzVariable, pVersion, FALSE);
573 ExitOnFailure(hr, "Failed to set version variable.");
574 }
575 else
576 {
577 hr = E_INVALIDARG;
578 ExitOnFailure(hr, "SetVariableVersion did not provide variable name.");
579 }
580
581 LExit:
582 ReleaseVerutilVersion(pVersion);
583
584 return hr;
585 }
586
587 void ExternalEngineCloseSplashScreen(
588 __in BURN_ENGINE_STATE* pEngineState
589 )
590 {
591 // If the splash screen is still around, close it.
592 if (::IsWindow(pEngineState->command.hwndSplashScreen))
593 {
594 ::PostMessageW(pEngineState->command.hwndSplashScreen, WM_CLOSE, 0, 0);
595 }
596 }
597
598 HRESULT ExternalEngineCompareVersions(
599 __in_z LPCWSTR wzVersion1,
600 __in_z LPCWSTR wzVersion2,
601 __out int* pnResult
602 )
603 {
604 HRESULT hr = S_OK;
605
606 hr = VerCompareStringVersions(wzVersion1, wzVersion2, FALSE, pnResult);
607
608 return hr;
609 }
610
611 HRESULT ExternalEngineDetect(
612 __in BAENGINE_CONTEXT* pEngineContext,
613 __in_opt const HWND hwndParent
614 )
615 {
616 HRESULT hr = S_OK;
617 BAENGINE_ACTION* pAction = NULL;
618
619 pAction = (BAENGINE_ACTION*)MemAlloc(sizeof(BAENGINE_ACTION), TRUE);
620 ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BAENGINE_ACTION");
621
622 pAction->dwMessage = WM_BURN_DETECT;
623 pAction->detect.hwndParent = hwndParent;
624
625 hr = EnqueueAction(pEngineContext, &pAction);
626 ExitOnFailure(hr, "Failed to enqueue detect action.");
627
628 LExit:
629 ReleaseMem(pAction);
630
631 return hr;
632 }
633
634 HRESULT ExternalEnginePlan(
635 __in BAENGINE_CONTEXT* pEngineContext,
636 __in const BOOTSTRAPPER_ACTION action
637 )
638 {
639 HRESULT hr = S_OK;
640 BAENGINE_ACTION* pAction = NULL;
641
642 if (BOOTSTRAPPER_ACTION_LAYOUT > action || BOOTSTRAPPER_ACTION_UPDATE_REPLACE_EMBEDDED < action)
643 {
644 ExitOnRootFailure(hr = E_INVALIDARG, "BA passed invalid action to Plan: %u.", action);
645 }
646
647 pAction = (BAENGINE_ACTION*)MemAlloc(sizeof(BAENGINE_ACTION), TRUE);
648 ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BAENGINE_ACTION");
649
650 pAction->dwMessage = WM_BURN_PLAN;
651 pAction->plan.action = action;
652
653 hr = EnqueueAction(pEngineContext, &pAction);
654 ExitOnFailure(hr, "Failed to enqueue plan action.");
655
656 LExit:
657 ReleaseMem(pAction);
658
659 return hr;
660 }
661
662 HRESULT ExternalEngineElevate(
663 __in BAENGINE_CONTEXT* pEngineContext,
664 __in_opt const HWND hwndParent
665 )
666 {
667 HRESULT hr = S_OK;
668 BAENGINE_ACTION* pAction = NULL;
669
670 if (INVALID_HANDLE_VALUE != pEngineContext->pEngineState->companionConnection.hPipe)
671 {
672 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED));
673 }
674
675 pAction = (BAENGINE_ACTION*)MemAlloc(sizeof(BAENGINE_ACTION), TRUE);
676 ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BAENGINE_ACTION");
677
678 pAction->dwMessage = WM_BURN_ELEVATE;
679 pAction->elevate.hwndParent = hwndParent;
680
681 hr = EnqueueAction(pEngineContext, &pAction);
682 ExitOnFailure(hr, "Failed to enqueue elevate action.");
683
684 LExit:
685 ReleaseMem(pAction);
686
687 return hr;
688 }
689
690 HRESULT ExternalEngineApply(
691 __in BAENGINE_CONTEXT* pEngineContext,
692 __in_opt const HWND hwndParent
693 )
694 {
695 HRESULT hr = S_OK;
696 BAENGINE_ACTION* pAction = NULL;
697
698 ExitOnNull(hwndParent, hr, E_INVALIDARG, "BA passed NULL hwndParent to Apply.");
699 if (!::IsWindow(hwndParent))
700 {
701 ExitOnRootFailure(hr = E_INVALIDARG, "BA passed invalid hwndParent to Apply.");
702 }
703
704 pAction = (BAENGINE_ACTION*)MemAlloc(sizeof(BAENGINE_ACTION), TRUE);
705 ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BAENGINE_ACTION");
706
707 pAction->dwMessage = WM_BURN_APPLY;
708 pAction->apply.hwndParent = hwndParent;
709
710 hr = EnqueueAction(pEngineContext, &pAction);
711 ExitOnFailure(hr, "Failed to enqueue apply action.");
712
713 LExit:
714 ReleaseMem(pAction);
715
716 return hr;
717 }
718
719 HRESULT ExternalEngineQuit(
720 __in BAENGINE_CONTEXT* pEngineContext,
721 __in const DWORD dwExitCode
722 )
723 {
724 HRESULT hr = S_OK;
725 BAENGINE_ACTION* pAction = NULL;
726
727 pAction = (BAENGINE_ACTION*)MemAlloc(sizeof(BAENGINE_ACTION), TRUE);
728 ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BAENGINE_ACTION");
729
730 pAction->dwMessage = WM_BURN_QUIT;
731 pAction->quit.dwExitCode = dwExitCode;
732
733 hr = EnqueueAction(pEngineContext, &pAction);
734 ExitOnFailure(hr, "Failed to enqueue shutdown action.");
735
736 LExit:
737 ReleaseMem(pAction);
738
739 return hr;
740 }
741
742 HRESULT ExternalEngineLaunchApprovedExe(
743 __in BAENGINE_CONTEXT* pEngineContext,
744 __in_opt const HWND hwndParent,
745 __in_z LPCWSTR wzApprovedExeForElevationId,
746 __in_z_opt LPCWSTR wzArguments,
747 __in const DWORD dwWaitForInputIdleTimeout
748 )
749 {
750 HRESULT hr = S_OK;
751 BURN_APPROVED_EXE* pApprovedExe = NULL;
752 BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe = NULL;
753 BAENGINE_ACTION* pAction = NULL;
754
755 if (!wzApprovedExeForElevationId || !*wzApprovedExeForElevationId)
756 {
757 ExitFunction1(hr = E_INVALIDARG);
758 }
759
760 hr = ApprovedExesFindById(&pEngineContext->pEngineState->approvedExes, wzApprovedExeForElevationId, &pApprovedExe);
761 ExitOnFailure(hr, "BA requested unknown approved exe with id: %ls", wzApprovedExeForElevationId);
762
763 pAction = (BAENGINE_ACTION*)MemAlloc(sizeof(BAENGINE_ACTION), TRUE);
764 ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BAENGINE_ACTION");
765
766 pAction->dwMessage = WM_BURN_LAUNCH_APPROVED_EXE;
767 pLaunchApprovedExe = &pAction->launchApprovedExe;
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 hr = EnqueueAction(pEngineContext, &pAction);
783 ExitOnFailure(hr, "Failed to enqueue launch approved exe action.");
784
785 LExit:
786 if (pAction)
787 {
788 BAEngineFreeAction(pAction);
789 }
790
791 return hr;
792 }
793
794 HRESULT ExternalEngineSetUpdateSource(
795 __in BURN_ENGINE_STATE* pEngineState,
796 __in_z LPCWSTR wzUrl,
797 __in_z_opt LPCWSTR wzAuthorizationHeader
798 )
799 {
800 HRESULT hr = S_OK;
801 BOOL fLeaveCriticalSection = FALSE;
802
803 ::EnterCriticalSection(&pEngineState->userExperience.csEngineActive);
804 fLeaveCriticalSection = TRUE;
805 hr = BootstrapperApplicationEnsureEngineInactive(&pEngineState->userExperience);
806 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
807
808 if (wzUrl && *wzUrl)
809 {
810 hr = StrAllocString(&pEngineState->update.sczUpdateSource, wzUrl, 0);
811 ExitOnFailure(hr, "Failed to set feed download URL.");
812
813 if (wzAuthorizationHeader && *wzAuthorizationHeader)
814 {
815 hr = StrAllocString(&pEngineState->update.sczAuthorizationHeader, wzAuthorizationHeader, 0);
816 ExitOnFailure(hr, "Failed to set feed authorization header.");
817 }
818 else
819 {
820 ReleaseNullStr(pEngineState->update.sczAuthorizationHeader);
821 }
822 }
823 else // no URL provided means clear out the whole download source.
824 {
825 ReleaseNullStr(pEngineState->update.sczAuthorizationHeader);
826 ReleaseNullStr(pEngineState->update.sczUpdateSource);
827 }
828
829 LExit:
830 if (fLeaveCriticalSection)
831 {
832 ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive);
833 }
834
835 return hr;
836 }
837
838 HRESULT ExternalEngineGetRelatedBundleVariable(
839 __in BURN_ENGINE_STATE* /*pEngineState*/,
840 __in_z LPCWSTR wzBundleId,
841 __in_z LPCWSTR wzVariable,
842 __out_ecount_opt(*pcchValue) LPWSTR wzValue,
843 __inout SIZE_T* pcchValue
844 )
845 {
846 HRESULT hr = S_OK;
847 LPWSTR sczValue = NULL;
848
849 if (wzVariable && *wzVariable && pcchValue)
850 {
851 hr = BundleGetBundleVariable(wzBundleId, wzVariable, &sczValue);
852 if (SUCCEEDED(hr))
853 {
854 hr = CopyStringToExternal(sczValue, wzValue, pcchValue);
855 }
856 }
857 else
858 {
859 hr = E_INVALIDARG;
860 }
861
862 StrSecureZeroFreeString(sczValue);
863
864 return hr;
865 }
866
867 // TODO: callers need to provide the original size (at the time of first public release) of the struct instead of the current size.
868 HRESULT WINAPI ExternalEngineValidateMessageParameter(
869 __in_opt const LPVOID pv,
870 __in SIZE_T cbSizeOffset,
871 __in DWORD dwMinimumSize
872 )
873 {
874 HRESULT hr = S_OK;
875
876 if (!pv)
877 {
878 ExitFunction1(hr = E_INVALIDARG);
879 }
880
881 DWORD cbSize = *(DWORD*)((BYTE*)pv + cbSizeOffset);
882 if (dwMinimumSize < cbSize)
883 {
884 ExitFunction1(hr = E_INVALIDARG);
885 }
886
887 LExit:
888 return hr;
889 }
890
891 static HRESULT CopyStringToExternal(
892 __in_z LPWSTR wzValue,
893 __in_z_opt LPWSTR wzBuffer,
894 __inout SIZE_T* pcchBuffer
895 )
896 {
897 HRESULT hr = S_OK;
898 BOOL fTooSmall = !wzBuffer;
899
900 if (!fTooSmall)
901 {
902 hr = ::StringCchCopyExW(wzBuffer, *pcchBuffer, wzValue, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
903 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
904 {
905 fTooSmall = TRUE;
906 }
907 }
908
909 if (fTooSmall)
910 {
911 hr = ::StringCchLengthW(wzValue, STRSAFE_MAX_LENGTH, reinterpret_cast<size_t*>(pcchBuffer));
912 if (SUCCEEDED(hr))
913 {
914 hr = E_MOREDATA;
915 *pcchBuffer += 1; // null terminator.
916 }
917 }
918
919 return hr;
920 }
921
922 static HRESULT ProcessUnknownEmbeddedMessages(
923 __in PIPE_MESSAGE* /*pMsg*/,
924 __in_opt LPVOID /*pvContext*/,
925 __out DWORD* pdwResult
926 )
927 {
928 *pdwResult = (DWORD)E_NOTIMPL;
929
930 return S_OK;
931 }
932
933 static HRESULT EnqueueAction(
934 __in BAENGINE_CONTEXT* pEngineContext,
935 __inout BAENGINE_ACTION** ppAction
936 )
937 {
938 HRESULT hr = S_OK;
939
940 ::EnterCriticalSection(&pEngineContext->csQueue);
941
942 if (pEngineContext->pEngineState->fQuit)
943 {
944 LogId(REPORT_WARNING, MSG_IGNORE_OPERATION_AFTER_QUIT, LoggingBurnMessageToString((*ppAction)->dwMessage));
945 hr = E_INVALIDSTATE;
946 }
947 else
948 {
949 hr = QueEnqueue(pEngineContext->hQueue, *ppAction);
950 }
951
952 ::LeaveCriticalSection(&pEngineContext->csQueue);
953
954 ExitOnFailure(hr, "Failed to enqueue action.");
955
956 *ppAction = NULL;
957
958 if (!::ReleaseSemaphore(pEngineContext->hQueueSemaphore, 1, NULL))
959 {
960 ExitWithLastError(hr, "Failed to signal queue semaphore.");
961 }
962
963 LExit:
964 return hr;
965 }