aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine/externalengine.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 17:06:54 -0700
committerRob Mensching <rob@firegiant.com>2021-04-29 16:36:06 -0700
commitaf10c45d7b3a44af0b461a557847fe03263dcc10 (patch)
tree6a5c1532304782c36ffe4200b38f3afb76789a43 /src/burn/engine/externalengine.cpp
parent9c2aed97299fb96aeee3f1471ce40225437aaecf (diff)
downloadwix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.gz
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.bz2
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.zip
Move burn into burn
Diffstat (limited to 'src/burn/engine/externalengine.cpp')
-rw-r--r--src/burn/engine/externalengine.cpp805
1 files changed, 805 insertions, 0 deletions
diff --git a/src/burn/engine/externalengine.cpp b/src/burn/engine/externalengine.cpp
new file mode 100644
index 00000000..409353e4
--- /dev/null
+++ b/src/burn/engine/externalengine.cpp
@@ -0,0 +1,805 @@
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
6static HRESULT CopyStringToExternal(
7 __in_z LPWSTR wzValue,
8 __in_z_opt LPWSTR wzBuffer,
9 __inout SIZE_T* pcchBuffer
10 );
11
12// function definitions
13
14void ExternalEngineGetPackageCount(
15 __in BURN_ENGINE_STATE* pEngineState,
16 __out DWORD* pcPackages
17 )
18{
19 *pcPackages = pEngineState->packages.cPackages;
20}
21
22HRESULT ExternalEngineGetVariableNumeric(
23 __in BURN_ENGINE_STATE* pEngineState,
24 __in_z LPCWSTR wzVariable,
25 __out LONGLONG* pllValue
26 )
27{
28 HRESULT hr = S_OK;
29
30 if (wzVariable && *wzVariable)
31 {
32 hr = VariableGetNumeric(&pEngineState->variables, wzVariable, pllValue);
33 }
34 else
35 {
36 *pllValue = 0;
37 hr = E_INVALIDARG;
38 }
39
40 return hr;
41}
42
43HRESULT ExternalEngineGetVariableString(
44 __in BURN_ENGINE_STATE* pEngineState,
45 __in_z LPCWSTR wzVariable,
46 __out_ecount_opt(*pcchValue) LPWSTR wzValue,
47 __inout SIZE_T* pcchValue
48 )
49{
50 HRESULT hr = S_OK;
51 LPWSTR sczValue = NULL;
52
53 if (wzVariable && *wzVariable)
54 {
55 hr = VariableGetString(&pEngineState->variables, wzVariable, &sczValue);
56 if (SUCCEEDED(hr))
57 {
58 hr = CopyStringToExternal(sczValue, wzValue, pcchValue);
59 }
60 }
61 else
62 {
63 hr = E_INVALIDARG;
64 }
65
66 StrSecureZeroFreeString(sczValue);
67
68 return hr;
69}
70
71HRESULT ExternalEngineGetVariableVersion(
72 __in BURN_ENGINE_STATE* pEngineState,
73 __in_z LPCWSTR wzVariable,
74 __out_ecount_opt(*pcchValue) LPWSTR wzValue,
75 __inout SIZE_T* pcchValue
76 )
77{
78 HRESULT hr = S_OK;
79 VERUTIL_VERSION* pVersion = NULL;
80
81 if (wzVariable && *wzVariable)
82 {
83 hr = VariableGetVersion(&pEngineState->variables, wzVariable, &pVersion);
84 if (SUCCEEDED(hr))
85 {
86 hr = CopyStringToExternal(pVersion->sczVersion, wzValue, pcchValue);
87 }
88 }
89 else
90 {
91 hr = E_INVALIDARG;
92 }
93
94 ReleaseVerutilVersion(pVersion);
95
96 return hr;
97}
98
99HRESULT ExternalEngineFormatString(
100 __in BURN_ENGINE_STATE* pEngineState,
101 __in_z LPCWSTR wzIn,
102 __out_ecount_opt(*pcchOut) LPWSTR wzOut,
103 __inout SIZE_T* pcchOut
104 )
105{
106 HRESULT hr = S_OK;
107 LPWSTR sczValue = NULL;
108
109 if (wzIn && *wzIn)
110 {
111 hr = VariableFormatString(&pEngineState->variables, wzIn, &sczValue, NULL);
112 if (SUCCEEDED(hr))
113 {
114 hr = CopyStringToExternal(sczValue, wzOut, pcchOut);
115 }
116 }
117 else
118 {
119 hr = E_INVALIDARG;
120 }
121
122 StrSecureZeroFreeString(sczValue);
123
124 return hr;
125}
126
127HRESULT ExternalEngineEscapeString(
128 __in_z LPCWSTR wzIn,
129 __out_ecount_opt(*pcchOut) LPWSTR wzOut,
130 __inout SIZE_T* pcchOut
131 )
132{
133 HRESULT hr = S_OK;
134 LPWSTR sczValue = NULL;
135
136 if (wzIn && *wzIn)
137 {
138 hr = VariableEscapeString(wzIn, &sczValue);
139 if (SUCCEEDED(hr))
140 {
141 hr = CopyStringToExternal(sczValue, wzOut, pcchOut);
142 }
143 }
144 else
145 {
146 hr = E_INVALIDARG;
147 }
148
149 StrSecureZeroFreeString(sczValue);
150
151 return hr;
152}
153
154HRESULT ExternalEngineEvaluateCondition(
155 __in BURN_ENGINE_STATE* pEngineState,
156 __in_z LPCWSTR wzCondition,
157 __out BOOL* pf
158 )
159{
160 HRESULT hr = S_OK;
161
162 if (wzCondition && *wzCondition)
163 {
164 hr = ConditionEvaluate(&pEngineState->variables, wzCondition, pf);
165 }
166 else
167 {
168 *pf = FALSE;
169 hr = E_INVALIDARG;
170 }
171
172 return hr;
173}
174
175HRESULT ExternalEngineLog(
176 __in REPORT_LEVEL rl,
177 __in_z LPCWSTR wzMessage
178 )
179{
180 HRESULT hr = S_OK;
181
182 hr = LogStringLine(rl, "%ls", wzMessage);
183
184 return hr;
185}
186
187HRESULT ExternalEngineSendEmbeddedError(
188 __in BURN_ENGINE_STATE* pEngineState,
189 __in const DWORD dwErrorCode,
190 __in_z LPCWSTR wzMessage,
191 __in const DWORD dwUIHint,
192 __out int* pnResult
193 )
194{
195 HRESULT hr = S_OK;
196 BYTE* pbData = NULL;
197 SIZE_T cbData = 0;
198 DWORD dwResult = *pnResult = 0;
199
200 if (BURN_MODE_EMBEDDED != pEngineState->mode)
201 {
202 hr = HRESULT_FROM_WIN32(ERROR_INVALID_STATE);
203 ExitOnRootFailure(hr, "BA requested to send embedded message when not in embedded mode.");
204 }
205
206 hr = BuffWriteNumber(&pbData, &cbData, dwErrorCode);
207 ExitOnFailure(hr, "Failed to write error code to message buffer.");
208
209 hr = BuffWriteString(&pbData, &cbData, wzMessage ? wzMessage : L"");
210 ExitOnFailure(hr, "Failed to write message string to message buffer.");
211
212 hr = BuffWriteNumber(&pbData, &cbData, dwUIHint);
213 ExitOnFailure(hr, "Failed to write UI hint to message buffer.");
214
215 hr = PipeSendMessage(pEngineState->embeddedConnection.hPipe, BURN_EMBEDDED_MESSAGE_TYPE_ERROR, pbData, cbData, NULL, NULL, &dwResult);
216 ExitOnFailure(hr, "Failed to send embedded message over pipe.");
217
218 *pnResult = static_cast<int>(dwResult);
219
220LExit:
221 ReleaseBuffer(pbData);
222
223 return hr;
224}
225
226HRESULT ExternalEngineSendEmbeddedProgress(
227 __in BURN_ENGINE_STATE* pEngineState,
228 __in const DWORD dwProgressPercentage,
229 __in const DWORD dwOverallProgressPercentage,
230 __out int* pnResult
231 )
232{
233 HRESULT hr = S_OK;
234 BYTE* pbData = NULL;
235 SIZE_T cbData = 0;
236 DWORD dwResult = *pnResult = 0;
237
238 if (BURN_MODE_EMBEDDED != pEngineState->mode)
239 {
240 hr = HRESULT_FROM_WIN32(ERROR_INVALID_STATE);
241 ExitOnRootFailure(hr, "BA requested to send embedded progress message when not in embedded mode.");
242 }
243
244 hr = BuffWriteNumber(&pbData, &cbData, dwProgressPercentage);
245 ExitOnFailure(hr, "Failed to write progress percentage to message buffer.");
246
247 hr = BuffWriteNumber(&pbData, &cbData, dwOverallProgressPercentage);
248 ExitOnFailure(hr, "Failed to write overall progress percentage to message buffer.");
249
250 hr = PipeSendMessage(pEngineState->embeddedConnection.hPipe, BURN_EMBEDDED_MESSAGE_TYPE_PROGRESS, pbData, cbData, NULL, NULL, &dwResult);
251 ExitOnFailure(hr, "Failed to send embedded progress message over pipe.");
252
253 *pnResult = static_cast<int>(dwResult);
254
255LExit:
256 ReleaseBuffer(pbData);
257
258 return hr;
259}
260
261HRESULT ExternalEngineSetUpdate(
262 __in BURN_ENGINE_STATE* pEngineState,
263 __in_z_opt LPCWSTR wzLocalSource,
264 __in_z_opt LPCWSTR wzDownloadSource,
265 __in const DWORD64 qwSize,
266 __in const BOOTSTRAPPER_UPDATE_HASH_TYPE hashType,
267 __in_opt const BYTE* rgbHash,
268 __in const DWORD cbHash
269 )
270{
271 HRESULT hr = S_OK;
272 LPWSTR sczFilePath = NULL;
273 LPWSTR sczCommandline = NULL;
274 UUID guid = { };
275 WCHAR wzGuid[39];
276 RPC_STATUS rs = RPC_S_OK;
277
278 ::EnterCriticalSection(&pEngineState->userExperience.csEngineActive);
279 hr = UserExperienceEnsureEngineInactive(&pEngineState->userExperience);
280 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
281
282 if ((!wzLocalSource || !*wzLocalSource) && (!wzDownloadSource || !*wzDownloadSource))
283 {
284 UpdateUninitialize(&pEngineState->update);
285 }
286 else if (BOOTSTRAPPER_UPDATE_HASH_TYPE_NONE == hashType && (0 != cbHash || rgbHash))
287 {
288 hr = E_INVALIDARG;
289 }
290 else if (BOOTSTRAPPER_UPDATE_HASH_TYPE_SHA512 == hashType && (SHA512_HASH_LEN != cbHash || !rgbHash))
291 {
292 hr = E_INVALIDARG;
293 }
294 else
295 {
296 UpdateUninitialize(&pEngineState->update);
297
298 hr = CoreRecreateCommandLine(&sczCommandline, BOOTSTRAPPER_ACTION_INSTALL, pEngineState->command.display, pEngineState->command.restart, BOOTSTRAPPER_RELATION_NONE, FALSE, pEngineState->registration.sczActiveParent, pEngineState->registration.sczAncestors, NULL, pEngineState->command.wzCommandLine);
299 ExitOnFailure(hr, "Failed to recreate command-line for update bundle.");
300
301 // Bundles would fail to use the downloaded update bundle, as the running bundle would be one of the search paths.
302 // Here I am generating a random guid, but in the future it would be nice if the feed would provide the ID of the update.
303 rs = ::UuidCreate(&guid);
304 hr = HRESULT_FROM_RPC(rs);
305 ExitOnFailure(hr, "Failed to create bundle update guid.");
306
307 if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid)))
308 {
309 hr = E_OUTOFMEMORY;
310 ExitOnRootFailure(hr, "Failed to convert bundle update guid into string.");
311 }
312
313 hr = StrAllocFormatted(&sczFilePath, L"%ls\\%ls", wzGuid, pEngineState->registration.sczExecutableName);
314 ExitOnFailure(hr, "Failed to build bundle update file path.");
315
316 if (!wzLocalSource || !*wzLocalSource)
317 {
318 wzLocalSource = sczFilePath;
319 }
320
321 hr = PseudoBundleInitialize(FILEMAKEVERSION(rmj, rmm, rup, rpr), &pEngineState->update.package, FALSE, pEngineState->registration.sczId, BOOTSTRAPPER_RELATION_UPDATE, BOOTSTRAPPER_PACKAGE_STATE_ABSENT, FALSE, sczFilePath, wzLocalSource, wzDownloadSource, qwSize, TRUE, sczCommandline, NULL, NULL, NULL, rgbHash, cbHash);
322 ExitOnFailure(hr, "Failed to set update bundle.");
323
324 pEngineState->update.fUpdateAvailable = TRUE;
325 }
326
327LExit:
328 ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive);
329
330 ReleaseStr(sczCommandline);
331 ReleaseStr(sczFilePath);
332
333 return hr;
334}
335
336HRESULT ExternalEngineSetLocalSource(
337 __in BURN_ENGINE_STATE* pEngineState,
338 __in_z_opt LPCWSTR wzPackageOrContainerId,
339 __in_z_opt LPCWSTR wzPayloadId,
340 __in_z LPCWSTR wzPath
341 )
342{
343 HRESULT hr = S_OK;
344 BURN_CONTAINER* pContainer = NULL;
345 BURN_PAYLOAD* pPayload = NULL;
346
347 ::EnterCriticalSection(&pEngineState->userExperience.csEngineActive);
348 hr = UserExperienceEnsureEngineInactive(&pEngineState->userExperience);
349 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
350
351 if (!wzPath || !*wzPath)
352 {
353 hr = E_INVALIDARG;
354 }
355 else if (wzPayloadId && *wzPayloadId)
356 {
357 hr = PayloadFindById(&pEngineState->payloads, wzPayloadId, &pPayload);
358 ExitOnFailure(hr, "BA requested unknown payload with id: %ls", wzPayloadId);
359
360 hr = StrAllocString(&pPayload->sczSourcePath, wzPath, 0);
361 ExitOnFailure(hr, "Failed to set source path for payload.");
362 }
363 else if (wzPackageOrContainerId && *wzPackageOrContainerId)
364 {
365 hr = ContainerFindById(&pEngineState->containers, wzPackageOrContainerId, &pContainer);
366 ExitOnFailure(hr, "BA requested unknown container with id: %ls", wzPackageOrContainerId);
367
368 hr = StrAllocString(&pContainer->sczSourcePath, wzPath, 0);
369 ExitOnFailure(hr, "Failed to set source path for container.");
370 }
371 else
372 {
373 hr = E_INVALIDARG;
374 }
375
376LExit:
377 ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive);
378
379 return hr;
380}
381
382HRESULT ExternalEngineSetDownloadSource(
383 __in BURN_ENGINE_STATE* pEngineState,
384 __in_z_opt LPCWSTR wzPackageOrContainerId,
385 __in_z_opt LPCWSTR wzPayloadId,
386 __in_z_opt LPCWSTR wzUrl,
387 __in_z_opt LPCWSTR wzUser,
388 __in_z_opt LPCWSTR wzPassword
389 )
390{
391 HRESULT hr = S_OK;
392 BURN_CONTAINER* pContainer = NULL;
393 BURN_PAYLOAD* pPayload = NULL;
394 DOWNLOAD_SOURCE* pDownloadSource = NULL;
395
396 ::EnterCriticalSection(&pEngineState->userExperience.csEngineActive);
397 hr = UserExperienceEnsureEngineInactive(&pEngineState->userExperience);
398 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
399
400 if (wzPayloadId && *wzPayloadId)
401 {
402 hr = PayloadFindById(&pEngineState->payloads, wzPayloadId, &pPayload);
403 ExitOnFailure(hr, "BA requested unknown payload with id: %ls", wzPayloadId);
404
405 pDownloadSource = &pPayload->downloadSource;
406 }
407 else if (wzPackageOrContainerId && *wzPackageOrContainerId)
408 {
409 hr = ContainerFindById(&pEngineState->containers, wzPackageOrContainerId, &pContainer);
410 ExitOnFailure(hr, "BA requested unknown container with id: %ls", wzPackageOrContainerId);
411
412 pDownloadSource = &pContainer->downloadSource;
413 }
414 else
415 {
416 hr = E_INVALIDARG;
417 ExitOnFailure(hr, "BA did not provide container or payload id.");
418 }
419
420 if (wzUrl && *wzUrl)
421 {
422 hr = StrAllocString(&pDownloadSource->sczUrl, wzUrl, 0);
423 ExitOnFailure(hr, "Failed to set download URL.");
424
425 if (wzUser && *wzUser)
426 {
427 hr = StrAllocString(&pDownloadSource->sczUser, wzUser, 0);
428 ExitOnFailure(hr, "Failed to set download user.");
429
430 if (wzPassword && *wzPassword)
431 {
432 hr = StrAllocString(&pDownloadSource->sczPassword, wzPassword, 0);
433 ExitOnFailure(hr, "Failed to set download password.");
434 }
435 else // no password.
436 {
437 ReleaseNullStr(pDownloadSource->sczPassword);
438 }
439 }
440 else // no user means no password either.
441 {
442 ReleaseNullStr(pDownloadSource->sczUser);
443 ReleaseNullStr(pDownloadSource->sczPassword);
444 }
445 }
446 else // no URL provided means clear out the whole download source.
447 {
448 ReleaseNullStr(pDownloadSource->sczUrl);
449 ReleaseNullStr(pDownloadSource->sczUser);
450 ReleaseNullStr(pDownloadSource->sczPassword);
451 }
452
453LExit:
454 ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive);
455
456 return hr;
457}
458
459HRESULT ExternalEngineSetVariableNumeric(
460 __in BURN_ENGINE_STATE* pEngineState,
461 __in_z LPCWSTR wzVariable,
462 __in const LONGLONG llValue
463 )
464{
465 HRESULT hr = S_OK;
466
467 if (wzVariable && *wzVariable)
468 {
469 hr = VariableSetNumeric(&pEngineState->variables, wzVariable, llValue, FALSE);
470 ExitOnFailure(hr, "Failed to set numeric variable.");
471 }
472 else
473 {
474 hr = E_INVALIDARG;
475 ExitOnFailure(hr, "SetVariableNumeric did not provide variable name.");
476 }
477
478LExit:
479 return hr;
480}
481
482HRESULT ExternalEngineSetVariableString(
483 __in BURN_ENGINE_STATE* pEngineState,
484 __in_z LPCWSTR wzVariable,
485 __in_z_opt LPCWSTR wzValue,
486 __in const BOOL fFormatted
487 )
488{
489 HRESULT hr = S_OK;
490
491 if (wzVariable && *wzVariable)
492 {
493 hr = VariableSetString(&pEngineState->variables, wzVariable, wzValue, FALSE, fFormatted);
494 ExitOnFailure(hr, "Failed to set string variable.");
495 }
496 else
497 {
498 hr = E_INVALIDARG;
499 ExitOnFailure(hr, "SetVariableString did not provide variable name.");
500 }
501
502LExit:
503 return hr;
504}
505
506HRESULT ExternalEngineSetVariableVersion(
507 __in BURN_ENGINE_STATE* pEngineState,
508 __in_z LPCWSTR wzVariable,
509 __in_z_opt LPCWSTR wzValue
510 )
511{
512 HRESULT hr = S_OK;
513 VERUTIL_VERSION* pVersion = NULL;
514
515 if (wzVariable && *wzVariable)
516 {
517 if (wzValue)
518 {
519 hr = VerParseVersion(wzValue, 0, FALSE, &pVersion);
520 ExitOnFailure(hr, "Failed to parse new version value.");
521 }
522
523 hr = VariableSetVersion(&pEngineState->variables, wzVariable, pVersion, FALSE);
524 ExitOnFailure(hr, "Failed to set version variable.");
525 }
526 else
527 {
528 hr = E_INVALIDARG;
529 ExitOnFailure(hr, "SetVariableVersion did not provide variable name.");
530 }
531
532LExit:
533 ReleaseVerutilVersion(pVersion);
534
535 return hr;
536}
537
538void ExternalEngineCloseSplashScreen(
539 __in BURN_ENGINE_STATE* pEngineState
540 )
541{
542 // If the splash screen is still around, close it.
543 if (::IsWindow(pEngineState->command.hwndSplashScreen))
544 {
545 ::PostMessageW(pEngineState->command.hwndSplashScreen, WM_CLOSE, 0, 0);
546 }
547}
548
549HRESULT ExternalEngineCompareVersions(
550 __in_z LPCWSTR wzVersion1,
551 __in_z LPCWSTR wzVersion2,
552 __out int* pnResult
553 )
554{
555 HRESULT hr = S_OK;
556
557 hr = VerCompareStringVersions(wzVersion1, wzVersion2, FALSE, pnResult);
558
559 return hr;
560}
561
562HRESULT ExternalEngineDetect(
563 __in const DWORD dwThreadId,
564 __in_opt const HWND hwndParent
565 )
566{
567 HRESULT hr = S_OK;
568
569 if (!::PostThreadMessageW(dwThreadId, WM_BURN_DETECT, 0, reinterpret_cast<LPARAM>(hwndParent)))
570 {
571 ExitWithLastError(hr, "Failed to post detect message.");
572 }
573
574LExit:
575 return hr;
576}
577
578HRESULT ExternalEnginePlan(
579 __in const DWORD dwThreadId,
580 __in const BOOTSTRAPPER_ACTION action
581 )
582{
583 HRESULT hr = S_OK;
584
585 if (BOOTSTRAPPER_ACTION_LAYOUT > action || BOOTSTRAPPER_ACTION_UPDATE_REPLACE_EMBEDDED < action)
586 {
587 ExitOnRootFailure(hr = E_INVALIDARG, "BA passed invalid action to Plan: %u.", action);
588 }
589
590 if (!::PostThreadMessageW(dwThreadId, WM_BURN_PLAN, 0, action))
591 {
592 ExitWithLastError(hr, "Failed to post plan message.");
593 }
594
595LExit:
596 return hr;
597}
598
599HRESULT ExternalEngineElevate(
600 __in BURN_ENGINE_STATE* pEngineState,
601 __in const DWORD dwThreadId,
602 __in_opt const HWND hwndParent
603 )
604{
605 HRESULT hr = S_OK;
606
607 if (INVALID_HANDLE_VALUE != pEngineState->companionConnection.hPipe)
608 {
609 hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
610 }
611 else if (!::PostThreadMessageW(dwThreadId, WM_BURN_ELEVATE, 0, reinterpret_cast<LPARAM>(hwndParent)))
612 {
613 ExitWithLastError(hr, "Failed to post elevate message.");
614 }
615
616LExit:
617 return hr;
618}
619
620HRESULT ExternalEngineApply(
621 __in const DWORD dwThreadId,
622 __in_opt const HWND hwndParent
623 )
624{
625 HRESULT hr = S_OK;
626
627 ExitOnNull(hwndParent, hr, E_INVALIDARG, "BA passed NULL hwndParent to Apply.");
628 if (!::IsWindow(hwndParent))
629 {
630 ExitOnRootFailure(hr = E_INVALIDARG, "BA passed invalid hwndParent to Apply.");
631 }
632
633 if (!::PostThreadMessageW(dwThreadId, WM_BURN_APPLY, 0, reinterpret_cast<LPARAM>(hwndParent)))
634 {
635 ExitWithLastError(hr, "Failed to post apply message.");
636 }
637
638LExit:
639 return hr;
640}
641
642HRESULT ExternalEngineQuit(
643 __in const DWORD dwThreadId,
644 __in const DWORD dwExitCode
645 )
646{
647 HRESULT hr = S_OK;
648
649 if (!::PostThreadMessageW(dwThreadId, WM_BURN_QUIT, static_cast<WPARAM>(dwExitCode), 0))
650 {
651 ExitWithLastError(hr, "Failed to post shutdown message.");
652 }
653
654LExit:
655 return hr;
656}
657
658HRESULT ExternalEngineLaunchApprovedExe(
659 __in BURN_ENGINE_STATE* pEngineState,
660 __in const DWORD dwThreadId,
661 __in_opt const HWND hwndParent,
662 __in_z LPCWSTR wzApprovedExeForElevationId,
663 __in_z_opt LPCWSTR wzArguments,
664 __in const DWORD dwWaitForInputIdleTimeout
665 )
666{
667 HRESULT hr = S_OK;
668 BURN_APPROVED_EXE* pApprovedExe = NULL;
669 BOOL fLeaveCriticalSection = FALSE;
670 BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe = NULL;
671
672 pLaunchApprovedExe = (BURN_LAUNCH_APPROVED_EXE*)MemAlloc(sizeof(BURN_LAUNCH_APPROVED_EXE), TRUE);
673 ExitOnNull(pLaunchApprovedExe, hr, E_OUTOFMEMORY, "Failed to alloc BURN_LAUNCH_APPROVED_EXE");
674
675 ::EnterCriticalSection(&pEngineState->userExperience.csEngineActive);
676 fLeaveCriticalSection = TRUE;
677 hr = UserExperienceEnsureEngineInactive(&pEngineState->userExperience);
678 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
679
680 if (!wzApprovedExeForElevationId || !*wzApprovedExeForElevationId)
681 {
682 ExitFunction1(hr = E_INVALIDARG);
683 }
684
685 hr = ApprovedExesFindById(&pEngineState->approvedExes, wzApprovedExeForElevationId, &pApprovedExe);
686 ExitOnFailure(hr, "BA requested unknown approved exe with id: %ls", wzApprovedExeForElevationId);
687
688 hr = StrAllocString(&pLaunchApprovedExe->sczId, wzApprovedExeForElevationId, NULL);
689 ExitOnFailure(hr, "Failed to copy the id.");
690
691 if (wzArguments)
692 {
693 hr = StrAllocString(&pLaunchApprovedExe->sczArguments, wzArguments, NULL);
694 ExitOnFailure(hr, "Failed to copy the arguments.");
695 }
696
697 pLaunchApprovedExe->dwWaitForInputIdleTimeout = dwWaitForInputIdleTimeout;
698
699 pLaunchApprovedExe->hwndParent = hwndParent;
700
701 if (!::PostThreadMessageW(dwThreadId, WM_BURN_LAUNCH_APPROVED_EXE, 0, reinterpret_cast<LPARAM>(pLaunchApprovedExe)))
702 {
703 ExitWithLastError(hr, "Failed to post launch approved exe message.");
704 }
705
706LExit:
707 if (fLeaveCriticalSection)
708 {
709 ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive);
710 }
711
712 if (FAILED(hr))
713 {
714 ApprovedExesUninitializeLaunch(pLaunchApprovedExe);
715 }
716
717 return hr;
718}
719
720HRESULT ExternalEngineSetUpdateSource(
721 __in BURN_ENGINE_STATE* pEngineState,
722 __in_z LPCWSTR wzUrl
723 )
724{
725 HRESULT hr = S_OK;
726 BOOL fLeaveCriticalSection = FALSE;
727
728 ::EnterCriticalSection(&pEngineState->userExperience.csEngineActive);
729 fLeaveCriticalSection = TRUE;
730 hr = UserExperienceEnsureEngineInactive(&pEngineState->userExperience);
731 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
732
733 if (wzUrl && *wzUrl)
734 {
735 hr = StrAllocString(&pEngineState->update.sczUpdateSource, wzUrl, 0);
736 ExitOnFailure(hr, "Failed to set feed download URL.");
737 }
738 else // no URL provided means clear out the whole download source.
739 {
740 ReleaseNullStr(pEngineState->update.sczUpdateSource);
741 }
742
743LExit:
744 if (fLeaveCriticalSection)
745 {
746 ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive);
747 }
748
749 return hr;
750}
751
752// TODO: callers need to provide the original size (at the time of first public release) of the struct instead of the current size.
753HRESULT WINAPI ExternalEngineValidateMessageParameter(
754 __in_opt const LPVOID pv,
755 __in SIZE_T cbSizeOffset,
756 __in DWORD dwMinimumSize
757 )
758{
759 HRESULT hr = S_OK;
760
761 if (!pv)
762 {
763 ExitFunction1(hr = E_INVALIDARG);
764 }
765
766 DWORD cbSize = *(DWORD*)((BYTE*)pv + cbSizeOffset);
767 if (dwMinimumSize < cbSize)
768 {
769 ExitFunction1(hr = E_INVALIDARG);
770 }
771
772LExit:
773 return hr;
774}
775
776static HRESULT CopyStringToExternal(
777 __in_z LPWSTR wzValue,
778 __in_z_opt LPWSTR wzBuffer,
779 __inout SIZE_T* pcchBuffer
780 )
781{
782 HRESULT hr = S_OK;
783 BOOL fTooSmall = !wzBuffer;
784
785 if (!fTooSmall)
786 {
787 hr = ::StringCchCopyExW(wzBuffer, *pcchBuffer, wzValue, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
788 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
789 {
790 fTooSmall = TRUE;
791 }
792 }
793
794 if (fTooSmall)
795 {
796 hr = ::StringCchLengthW(wzValue, STRSAFE_MAX_LENGTH, reinterpret_cast<size_t*>(pcchBuffer));
797 if (SUCCEEDED(hr))
798 {
799 hr = E_MOREDATA;
800 *pcchBuffer += 1; // null terminator.
801 }
802 }
803
804 return hr;
805}