aboutsummaryrefslogtreecommitdiff
path: root/src/engine/externalengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/externalengine.cpp')
-rw-r--r--src/engine/externalengine.cpp760
1 files changed, 760 insertions, 0 deletions
diff --git a/src/engine/externalengine.cpp b/src/engine/externalengine.cpp
index ef4f931d..3d5b3696 100644
--- a/src/engine/externalengine.cpp
+++ b/src/engine/externalengine.cpp
@@ -3,8 +3,737 @@
3#include "precomp.h" 3#include "precomp.h"
4 4
5 5
6static HRESULT CopyStringToExternal(
7 __in_z LPWSTR wzValue,
8 __in_z_opt LPWSTR wzBuffer,
9 __inout DWORD* pcchBuffer
10 );
11
6// function definitions 12// function definitions
7 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 DWORD* 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 DWORD* 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 DWORD* 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 DWORD* 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 DWORD 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 DWORD 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 LPCWSTR sczId = NULL;
273 LPWSTR sczLocalSource = NULL;
274 LPWSTR sczCommandline = NULL;
275 UUID guid = { };
276 WCHAR wzGuid[39];
277 RPC_STATUS rs = RPC_S_OK;
278
279 ::EnterCriticalSection(&pEngineState->csActive);
280
281 if ((!wzLocalSource || !*wzLocalSource) && (!wzDownloadSource || !*wzDownloadSource))
282 {
283 UpdateUninitialize(&pEngineState->update);
284 }
285 else if (BOOTSTRAPPER_UPDATE_HASH_TYPE_NONE == hashType && (0 != cbHash || rgbHash))
286 {
287 hr = E_INVALIDARG;
288 }
289 else if (BOOTSTRAPPER_UPDATE_HASH_TYPE_SHA1 == hashType && (SHA1_HASH_LEN != cbHash || !rgbHash))
290 {
291 hr = E_INVALIDARG;
292 }
293 else
294 {
295 UpdateUninitialize(&pEngineState->update);
296
297 if (!wzLocalSource || !*wzLocalSource)
298 {
299 hr = StrAllocFormatted(&sczLocalSource, L"update\\%ls", pEngineState->registration.sczExecutableName);
300 ExitOnFailure(hr, "Failed to default local update source");
301 }
302
303 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);
304 ExitOnFailure(hr, "Failed to recreate command-line for update bundle.");
305
306 // Per-user bundles would fail to use the downloaded update bundle, as the existing install would already be cached
307 // at the registration id's location. Here I am generating a random guid, but in the future it would be nice if the
308 // feed would provide the ID of the update.
309 if (!pEngineState->registration.fPerMachine)
310 {
311 rs = ::UuidCreate(&guid);
312 hr = HRESULT_FROM_RPC(rs);
313 ExitOnFailure(hr, "Failed to create bundle update guid.");
314
315 if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid)))
316 {
317 hr = E_OUTOFMEMORY;
318 ExitOnRootFailure(hr, "Failed to convert bundle update guid into string.");
319 }
320
321 sczId = wzGuid;
322 }
323 else
324 {
325 sczId = pEngineState->registration.sczId;
326 }
327
328 hr = PseudoBundleInitialize(FILEMAKEVERSION(rmj, rmm, rup, rpr), &pEngineState->update.package, FALSE, sczId, BOOTSTRAPPER_RELATION_UPDATE, BOOTSTRAPPER_PACKAGE_STATE_ABSENT, pEngineState->registration.sczExecutableName, sczLocalSource ? sczLocalSource : wzLocalSource, wzDownloadSource, qwSize, TRUE, sczCommandline, NULL, NULL, NULL, rgbHash, cbHash);
329 ExitOnFailure(hr, "Failed to set update bundle.");
330
331 pEngineState->update.fUpdateAvailable = TRUE;
332 }
333
334LExit:
335 ::LeaveCriticalSection(&pEngineState->csActive);
336
337 ReleaseStr(sczCommandline);
338 ReleaseStr(sczLocalSource);
339
340 return hr;
341}
342
343HRESULT ExternalEngineSetLocalSource(
344 __in BURN_ENGINE_STATE* pEngineState,
345 __in_z_opt LPCWSTR wzPackageOrContainerId,
346 __in_z_opt LPCWSTR wzPayloadId,
347 __in_z LPCWSTR wzPath
348 )
349{
350 HRESULT hr = S_OK;
351 BURN_CONTAINER* pContainer = NULL;
352 BURN_PAYLOAD* pPayload = NULL;
353
354 ::EnterCriticalSection(&pEngineState->csActive);
355 hr = UserExperienceEnsureEngineInactive(&pEngineState->userExperience);
356 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
357
358 if (!wzPath || !*wzPath)
359 {
360 hr = E_INVALIDARG;
361 }
362 else if (wzPayloadId && *wzPayloadId)
363 {
364 hr = PayloadFindById(&pEngineState->payloads, wzPayloadId, &pPayload);
365 ExitOnFailure(hr, "BA requested unknown payload with id: %ls", wzPayloadId);
366
367 if (BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging)
368 {
369 hr = HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION);
370 ExitOnFailure(hr, "BA denied while trying to set source on embedded payload: %ls", wzPayloadId);
371 }
372
373 hr = StrAllocString(&pPayload->sczSourcePath, wzPath, 0);
374 ExitOnFailure(hr, "Failed to set source path for payload.");
375 }
376 else if (wzPackageOrContainerId && *wzPackageOrContainerId)
377 {
378 hr = ContainerFindById(&pEngineState->containers, wzPackageOrContainerId, &pContainer);
379 ExitOnFailure(hr, "BA requested unknown container with id: %ls", wzPackageOrContainerId);
380
381 hr = StrAllocString(&pContainer->sczSourcePath, wzPath, 0);
382 ExitOnFailure(hr, "Failed to set source path for container.");
383 }
384 else
385 {
386 hr = E_INVALIDARG;
387 }
388
389LExit:
390 ::LeaveCriticalSection(&pEngineState->csActive);
391
392 return hr;
393}
394
395HRESULT ExternalEngineSetDownloadSource(
396 __in BURN_ENGINE_STATE* pEngineState,
397 __in_z_opt LPCWSTR wzPackageOrContainerId,
398 __in_z_opt LPCWSTR wzPayloadId,
399 __in_z_opt LPCWSTR wzUrl,
400 __in_z_opt LPCWSTR wzUser,
401 __in_z_opt LPCWSTR wzPassword
402 )
403{
404 HRESULT hr = S_OK;
405 BURN_CONTAINER* pContainer = NULL;
406 BURN_PAYLOAD* pPayload = NULL;
407 DOWNLOAD_SOURCE* pDownloadSource = NULL;
408
409 ::EnterCriticalSection(&pEngineState->csActive);
410 hr = UserExperienceEnsureEngineInactive(&pEngineState->userExperience);
411 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
412
413 if (wzPayloadId && *wzPayloadId)
414 {
415 hr = PayloadFindById(&pEngineState->payloads, wzPayloadId, &pPayload);
416 ExitOnFailure(hr, "BA requested unknown payload with id: %ls", wzPayloadId);
417
418 if (BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging)
419 {
420 hr = HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION);
421 ExitOnFailure(hr, "BA denied while trying to set download URL on embedded payload: %ls", wzPayloadId);
422 }
423
424 pDownloadSource = &pPayload->downloadSource;
425 }
426 else if (wzPackageOrContainerId && *wzPackageOrContainerId)
427 {
428 hr = ContainerFindById(&pEngineState->containers, wzPackageOrContainerId, &pContainer);
429 ExitOnFailure(hr, "BA requested unknown container with id: %ls", wzPackageOrContainerId);
430
431 pDownloadSource = &pContainer->downloadSource;
432 }
433 else
434 {
435 hr = E_INVALIDARG;
436 ExitOnFailure(hr, "BA did not provide container or payload id.");
437 }
438
439 if (wzUrl && *wzUrl)
440 {
441 hr = StrAllocString(&pDownloadSource->sczUrl, wzUrl, 0);
442 ExitOnFailure(hr, "Failed to set download URL.");
443
444 if (wzUser && *wzUser)
445 {
446 hr = StrAllocString(&pDownloadSource->sczUser, wzUser, 0);
447 ExitOnFailure(hr, "Failed to set download user.");
448
449 if (wzPassword && *wzPassword)
450 {
451 hr = StrAllocString(&pDownloadSource->sczPassword, wzPassword, 0);
452 ExitOnFailure(hr, "Failed to set download password.");
453 }
454 else // no password.
455 {
456 ReleaseNullStr(pDownloadSource->sczPassword);
457 }
458 }
459 else // no user means no password either.
460 {
461 ReleaseNullStr(pDownloadSource->sczUser);
462 ReleaseNullStr(pDownloadSource->sczPassword);
463 }
464 }
465 else // no URL provided means clear out the whole download source.
466 {
467 ReleaseNullStr(pDownloadSource->sczUrl);
468 ReleaseNullStr(pDownloadSource->sczUser);
469 ReleaseNullStr(pDownloadSource->sczPassword);
470 }
471
472LExit:
473 ::LeaveCriticalSection(&pEngineState->csActive);
474
475 return hr;
476}
477
478HRESULT ExternalEngineSetVariableNumeric(
479 __in BURN_ENGINE_STATE* pEngineState,
480 __in_z LPCWSTR wzVariable,
481 __in const LONGLONG llValue
482 )
483{
484 HRESULT hr = S_OK;
485
486 if (wzVariable && *wzVariable)
487 {
488 hr = VariableSetNumeric(&pEngineState->variables, wzVariable, llValue, FALSE);
489 ExitOnFailure(hr, "Failed to set numeric variable.");
490 }
491 else
492 {
493 hr = E_INVALIDARG;
494 ExitOnFailure(hr, "SetVariableNumeric did not provide variable name.");
495 }
496
497LExit:
498 return hr;
499}
500
501HRESULT ExternalEngineSetVariableString(
502 __in BURN_ENGINE_STATE* pEngineState,
503 __in_z LPCWSTR wzVariable,
504 __in_z_opt LPCWSTR wzValue,
505 __in const BOOL fFormatted
506 )
507{
508 HRESULT hr = S_OK;
509
510 if (wzVariable && *wzVariable)
511 {
512 hr = VariableSetString(&pEngineState->variables, wzVariable, wzValue, FALSE, fFormatted);
513 ExitOnFailure(hr, "Failed to set string variable.");
514 }
515 else
516 {
517 hr = E_INVALIDARG;
518 ExitOnFailure(hr, "SetVariableString did not provide variable name.");
519 }
520
521LExit:
522 return hr;
523}
524
525HRESULT ExternalEngineSetVariableVersion(
526 __in BURN_ENGINE_STATE* pEngineState,
527 __in_z LPCWSTR wzVariable,
528 __in_z_opt LPCWSTR wzValue
529 )
530{
531 HRESULT hr = S_OK;
532 VERUTIL_VERSION* pVersion = NULL;
533
534 if (wzVariable && *wzVariable)
535 {
536 if (wzValue)
537 {
538 hr = VerParseVersion(wzValue, 0, FALSE, &pVersion);
539 ExitOnFailure(hr, "Failed to parse new version value.");
540 }
541
542 hr = VariableSetVersion(&pEngineState->variables, wzVariable, pVersion, FALSE);
543 ExitOnFailure(hr, "Failed to set version variable.");
544 }
545 else
546 {
547 hr = E_INVALIDARG;
548 ExitOnFailure(hr, "SetVariableVersion did not provide variable name.");
549 }
550
551LExit:
552 ReleaseVerutilVersion(pVersion);
553
554 return hr;
555}
556
557void ExternalEngineCloseSplashScreen(
558 __in BURN_ENGINE_STATE* pEngineState
559 )
560{
561 // If the splash screen is still around, close it.
562 if (::IsWindow(pEngineState->command.hwndSplashScreen))
563 {
564 ::PostMessageW(pEngineState->command.hwndSplashScreen, WM_CLOSE, 0, 0);
565 }
566}
567
568HRESULT ExternalEngineCompareVersions(
569 __in_z LPCWSTR wzVersion1,
570 __in_z LPCWSTR wzVersion2,
571 __out int* pnResult
572 )
573{
574 HRESULT hr = S_OK;
575
576 hr = VerCompareStringVersions(wzVersion1, wzVersion2, FALSE, pnResult);
577
578 return hr;
579}
580
581HRESULT ExternalEngineDetect(
582 __in const DWORD dwThreadId,
583 __in_opt const HWND hwndParent
584 )
585{
586 HRESULT hr = S_OK;
587
588 if (!::PostThreadMessageW(dwThreadId, WM_BURN_DETECT, 0, reinterpret_cast<LPARAM>(hwndParent)))
589 {
590 ExitWithLastError(hr, "Failed to post detect message.");
591 }
592
593LExit:
594 return hr;
595}
596
597HRESULT ExternalEnginePlan(
598 __in const DWORD dwThreadId,
599 __in const BOOTSTRAPPER_ACTION action
600 )
601{
602 HRESULT hr = S_OK;
603
604 if (!::PostThreadMessageW(dwThreadId, WM_BURN_PLAN, 0, action))
605 {
606 ExitWithLastError(hr, "Failed to post plan message.");
607 }
608
609LExit:
610 return hr;
611}
612
613HRESULT ExternalEngineElevate(
614 __in BURN_ENGINE_STATE* pEngineState,
615 __in const DWORD dwThreadId,
616 __in_opt const HWND hwndParent
617 )
618{
619 HRESULT hr = S_OK;
620
621 if (INVALID_HANDLE_VALUE != pEngineState->companionConnection.hPipe)
622 {
623 hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
624 }
625 else if (!::PostThreadMessageW(dwThreadId, WM_BURN_ELEVATE, 0, reinterpret_cast<LPARAM>(hwndParent)))
626 {
627 ExitWithLastError(hr, "Failed to post elevate message.");
628 }
629
630LExit:
631 return hr;
632}
633
634HRESULT ExternalEngineApply(
635 __in const DWORD dwThreadId,
636 __in_opt const HWND hwndParent
637 )
638{
639 HRESULT hr = S_OK;
640
641 ExitOnNull(hwndParent, hr, E_INVALIDARG, "BA passed NULL hwndParent to Apply.");
642 if (!::IsWindow(hwndParent))
643 {
644 ExitOnFailure(hr = E_INVALIDARG, "BA passed invalid hwndParent to Apply.");
645 }
646
647 if (!::PostThreadMessageW(dwThreadId, WM_BURN_APPLY, 0, reinterpret_cast<LPARAM>(hwndParent)))
648 {
649 ExitWithLastError(hr, "Failed to post apply message.");
650 }
651
652LExit:
653 return hr;
654}
655
656HRESULT ExternalEngineQuit(
657 __in const DWORD dwThreadId,
658 __in const DWORD dwExitCode
659 )
660{
661 HRESULT hr = S_OK;
662
663 if (!::PostThreadMessageW(dwThreadId, WM_BURN_QUIT, static_cast<WPARAM>(dwExitCode), 0))
664 {
665 ExitWithLastError(hr, "Failed to post shutdown message.");
666 }
667
668LExit:
669 return hr;
670}
671
672HRESULT ExternalEngineLaunchApprovedExe(
673 __in BURN_ENGINE_STATE* pEngineState,
674 __in const DWORD dwThreadId,
675 __in_opt const HWND hwndParent,
676 __in_z LPCWSTR wzApprovedExeForElevationId,
677 __in_z_opt LPCWSTR wzArguments,
678 __in const DWORD dwWaitForInputIdleTimeout
679 )
680{
681 HRESULT hr = S_OK;
682 BURN_APPROVED_EXE* pApprovedExe = NULL;
683 BOOL fLeaveCriticalSection = FALSE;
684 BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe = NULL;
685
686 pLaunchApprovedExe = (BURN_LAUNCH_APPROVED_EXE*)MemAlloc(sizeof(BURN_LAUNCH_APPROVED_EXE), TRUE);
687 ExitOnNull(pLaunchApprovedExe, hr, E_OUTOFMEMORY, "Failed to alloc BURN_LAUNCH_APPROVED_EXE");
688
689 ::EnterCriticalSection(&pEngineState->csActive);
690 fLeaveCriticalSection = TRUE;
691 hr = UserExperienceEnsureEngineInactive(&pEngineState->userExperience);
692 ExitOnFailure(hr, "Engine is active, cannot change engine state.");
693
694 if (!wzApprovedExeForElevationId || !*wzApprovedExeForElevationId)
695 {
696 ExitFunction1(hr = E_INVALIDARG);
697 }
698
699 hr = ApprovedExesFindById(&pEngineState->approvedExes, wzApprovedExeForElevationId, &pApprovedExe);
700 ExitOnFailure(hr, "BA requested unknown approved exe with id: %ls", wzApprovedExeForElevationId);
701
702 ::LeaveCriticalSection(&pEngineState->csActive);
703 fLeaveCriticalSection = FALSE;
704
705 hr = StrAllocString(&pLaunchApprovedExe->sczId, wzApprovedExeForElevationId, NULL);
706 ExitOnFailure(hr, "Failed to copy the id.");
707
708 if (wzArguments)
709 {
710 hr = StrAllocString(&pLaunchApprovedExe->sczArguments, wzArguments, NULL);
711 ExitOnFailure(hr, "Failed to copy the arguments.");
712 }
713
714 pLaunchApprovedExe->dwWaitForInputIdleTimeout = dwWaitForInputIdleTimeout;
715
716 pLaunchApprovedExe->hwndParent = hwndParent;
717
718 if (!::PostThreadMessageW(dwThreadId, WM_BURN_LAUNCH_APPROVED_EXE, 0, reinterpret_cast<LPARAM>(pLaunchApprovedExe)))
719 {
720 ExitWithLastError(hr, "Failed to post launch approved exe message.");
721 }
722
723LExit:
724 if (fLeaveCriticalSection)
725 {
726 ::LeaveCriticalSection(&pEngineState->csActive);
727 }
728
729 if (FAILED(hr))
730 {
731 ApprovedExesUninitializeLaunch(pLaunchApprovedExe);
732 }
733
734 return hr;
735}
736
8// TODO: callers need to provide the original size (at the time of first public release) of the struct instead of the current size. 737// TODO: callers need to provide the original size (at the time of first public release) of the struct instead of the current size.
9HRESULT WINAPI ExternalEngineValidateMessageParameter( 738HRESULT WINAPI ExternalEngineValidateMessageParameter(
10 __in_opt const LPVOID pv, 739 __in_opt const LPVOID pv,
@@ -28,3 +757,34 @@ HRESULT WINAPI ExternalEngineValidateMessageParameter(
28LExit: 757LExit:
29 return hr; 758 return hr;
30} 759}
760
761static HRESULT CopyStringToExternal(
762 __in_z LPWSTR wzValue,
763 __in_z_opt LPWSTR wzBuffer,
764 __inout DWORD* pcchBuffer
765 )
766{
767 HRESULT hr = S_OK;
768 BOOL fTooSmall = !wzBuffer;
769
770 if (!fTooSmall)
771 {
772 hr = ::StringCchCopyExW(wzBuffer, *pcchBuffer, wzValue, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
773 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
774 {
775 fTooSmall = TRUE;
776 }
777 }
778
779 if (fTooSmall)
780 {
781 hr = ::StringCchLengthW(wzValue, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(pcchBuffer));
782 if (SUCCEEDED(hr))
783 {
784 hr = E_MOREDATA;
785 *pcchBuffer += 1; // null terminator.
786 }
787 }
788
789 return hr;
790}