From 0354a00e74492ad8d930c5bf499bc8606e48b1c9 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Sun, 29 Mar 2020 19:14:06 +1000 Subject: Add support for BundleExtensions. --- src/engine/EngineForApplication.cpp | 2 +- src/engine/EngineForApplication.h | 4 +- src/engine/EngineForExtension.cpp | 405 ++++++++++++++++++++++++++++++++++++ src/engine/EngineForExtension.h | 27 +++ src/engine/burnextension.cpp | 184 ++++++++++++++++ src/engine/burnextension.h | 51 +++++ src/engine/core.h | 1 + src/engine/engine.cpp | 12 ++ src/engine/engine.vcxproj | 13 +- src/engine/manifest.cpp | 4 + src/engine/packages.config | 2 +- src/engine/precomp.h | 4 + src/engine/userexperience.cpp | 2 +- src/engine/userexperience.h | 2 +- src/engine/variable.cpp | 2 +- 15 files changed, 701 insertions(+), 14 deletions(-) create mode 100644 src/engine/EngineForExtension.cpp create mode 100644 src/engine/EngineForExtension.h create mode 100644 src/engine/burnextension.cpp create mode 100644 src/engine/burnextension.h (limited to 'src/engine') diff --git a/src/engine/EngineForApplication.cpp b/src/engine/EngineForApplication.cpp index eda5fc64..c3600c7b 100644 --- a/src/engine/EngineForApplication.cpp +++ b/src/engine/EngineForApplication.cpp @@ -593,7 +593,7 @@ static HRESULT BAEngineSetVariableString( if (wzVariable && *wzVariable) { hr = VariableSetString(&pContext->pEngineState->variables, wzVariable, wzValue, FALSE); - ExitOnFailure(hr, "Failed to set numeric variable."); + ExitOnFailure(hr, "Failed to set string variable."); } else { diff --git a/src/engine/EngineForApplication.h b/src/engine/EngineForApplication.h index 1b755acc..e5e8f6d7 100644 --- a/src/engine/EngineForApplication.h +++ b/src/engine/EngineForApplication.h @@ -24,11 +24,11 @@ enum WM_BURN // structs -struct BOOTSTRAPPER_ENGINE_CONTEXT +typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT { BURN_ENGINE_STATE* pEngineState; DWORD dwThreadId; -}; +} BOOTSTRAPPER_ENGINE_CONTEXT; // function declarations diff --git a/src/engine/EngineForExtension.cpp b/src/engine/EngineForExtension.cpp new file mode 100644 index 00000000..9667dd18 --- /dev/null +++ b/src/engine/EngineForExtension.cpp @@ -0,0 +1,405 @@ +// 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. + +#include "precomp.h" + +static HRESULT BEEngineEscapeString( + __in BURN_EXTENSION_ENGINE_CONTEXT* /*pContext*/, + __in BUNDLE_EXTENSION_ENGINE_ESCAPESTRING_ARGS* pArgs, + __in BUNDLE_EXTENSION_ENGINE_ESCAPESTRING_RESULTS* pResults + ) +{ + HRESULT hr = S_OK; + LPWSTR sczValue = NULL; + size_t cchRemaining = 0; + LPCWSTR wzIn = pArgs->wzIn; + LPWSTR wzOut = pResults->wzOut; + DWORD* pcchOut = &pResults->cchOut; + + if (wzIn && *wzIn) + { + hr = VariableEscapeString(wzIn, &sczValue); + if (SUCCEEDED(hr)) + { + if (wzOut) + { + hr = ::StringCchCopyExW(wzOut, *pcchOut, sczValue, NULL, &cchRemaining, STRSAFE_FILL_BEHIND_NULL); + if (STRSAFE_E_INSUFFICIENT_BUFFER == hr) + { + hr = E_MOREDATA; + ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining); + *pcchOut = cchRemaining; + } + } + else + { + ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining); + *pcchOut = cchRemaining; + } + } + } + else + { + hr = E_INVALIDARG; + } + + StrSecureZeroFreeString(sczValue); + return hr; +} + +static HRESULT BEEngineEvaluateCondition( + __in BURN_EXTENSION_ENGINE_CONTEXT* pContext, + __in BUNDLE_EXTENSION_ENGINE_EVALUATECONDITION_ARGS* pArgs, + __in BUNDLE_EXTENSION_ENGINE_EVALUATECONDITION_RESULTS* pResults + ) +{ + HRESULT hr = S_OK; + LPCWSTR wzCondition = pArgs->wzCondition; + BOOL* pf = &pResults->f; + + if (wzCondition && *wzCondition) + { + hr = ConditionEvaluate(&pContext->pEngineState->variables, wzCondition, pf); + } + else + { + hr = E_INVALIDARG; + } + + return hr; +} + +static HRESULT BEEngineFormatString( + __in BURN_EXTENSION_ENGINE_CONTEXT* pContext, + __in BUNDLE_EXTENSION_ENGINE_FORMATSTRING_ARGS* pArgs, + __in BUNDLE_EXTENSION_ENGINE_FORMATSTRING_RESULTS* pResults + ) +{ + HRESULT hr = S_OK; + LPWSTR sczValue = NULL; + DWORD cchValue = 0; + LPCWSTR wzIn = pArgs->wzIn; + LPWSTR wzOut = pResults->wzOut; + DWORD* pcchOut = &pResults->cchOut; + + if (wzIn && *wzIn) + { + hr = VariableFormatString(&pContext->pEngineState->variables, wzIn, &sczValue, &cchValue); + if (SUCCEEDED(hr)) + { + if (wzOut) + { + hr = ::StringCchCopyExW(wzOut, *pcchOut, sczValue, NULL, NULL, STRSAFE_FILL_BEHIND_NULL); + if (FAILED(hr)) + { + *pcchOut = cchValue; + if (STRSAFE_E_INSUFFICIENT_BUFFER == hr) + { + hr = E_MOREDATA; + } + } + } + else + { + hr = E_MOREDATA; + *pcchOut = cchValue; + } + } + } + else + { + hr = E_INVALIDARG; + } + + StrSecureZeroFreeString(sczValue); + return hr; +} + +static HRESULT BEEngineGetVariableNumeric( + __in BURN_EXTENSION_ENGINE_CONTEXT* pContext, + __in BUNDLE_EXTENSION_ENGINE_GETVARIABLENUMERIC_ARGS* pArgs, + __in BUNDLE_EXTENSION_ENGINE_GETVARIABLENUMERIC_RESULTS* pResults + ) +{ + HRESULT hr = S_OK; + LPCWSTR wzVariable = pArgs->wzVariable; + LONGLONG* pllValue = &pResults->llValue; + + if (wzVariable && *wzVariable) + { + hr = VariableGetNumeric(&pContext->pEngineState->variables, wzVariable, pllValue); + } + else + { + hr = E_INVALIDARG; + } + + return hr; +} + +static HRESULT BEEngineGetVariableString( + __in BURN_EXTENSION_ENGINE_CONTEXT* pContext, + __in BUNDLE_EXTENSION_ENGINE_GETVARIABLESTRING_ARGS* pArgs, + __in BUNDLE_EXTENSION_ENGINE_GETVARIABLESTRING_RESULTS* pResults + ) +{ + HRESULT hr = S_OK; + LPWSTR sczValue = NULL; + size_t cchRemaining = 0; + LPCWSTR wzVariable = pArgs->wzVariable; + LPWSTR wzValue = pResults->wzValue; + DWORD* pcchValue = &pResults->cchValue; + + if (wzVariable && *wzVariable) + { + hr = VariableGetString(&pContext->pEngineState->variables, wzVariable, &sczValue); + if (SUCCEEDED(hr)) + { + if (wzValue) + { + hr = ::StringCchCopyExW(wzValue, *pcchValue, sczValue, NULL, &cchRemaining, STRSAFE_FILL_BEHIND_NULL); + if (STRSAFE_E_INSUFFICIENT_BUFFER == hr) + { + hr = E_MOREDATA; + + ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining); + *pcchValue = cchRemaining + 1; + } + } + else + { + hr = E_MOREDATA; + + ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchRemaining); + *pcchValue = cchRemaining + 1; + } + } + } + else + { + hr = E_INVALIDARG; + } + + StrSecureZeroFreeString(sczValue); + return hr; +} + +static HRESULT BEEngineGetVariableVersion( + __in BURN_EXTENSION_ENGINE_CONTEXT* pContext, + __in BUNDLE_EXTENSION_ENGINE_GETVARIABLEVERSION_ARGS* pArgs, + __in BUNDLE_EXTENSION_ENGINE_GETVARIABLEVERSION_RESULTS* pResults + ) +{ + HRESULT hr = S_OK; + LPCWSTR wzVariable = pArgs->wzVariable; + DWORD64* pqwValue = &pResults->qwValue; + + if (wzVariable && *wzVariable) + { + hr = VariableGetVersion(&pContext->pEngineState->variables, wzVariable, pqwValue); + } + else + { + hr = E_INVALIDARG; + } + + return hr; +} + +static HRESULT BEEngineLog( + __in BURN_EXTENSION_ENGINE_CONTEXT* /*pContext*/, + __in BUNDLE_EXTENSION_ENGINE_LOG_ARGS* pArgs, + __in BUNDLE_EXTENSION_ENGINE_LOG_RESULTS* /*pResults*/ + ) +{ + HRESULT hr = S_OK; + REPORT_LEVEL rl = REPORT_NONE; + BUNDLE_EXTENSION_LOG_LEVEL level = pArgs->level; + LPCWSTR wzMessage = pArgs->wzMessage; + + switch (level) + { + case BUNDLE_EXTENSION_LOG_LEVEL_STANDARD: + rl = REPORT_STANDARD; + break; + + case BUNDLE_EXTENSION_LOG_LEVEL_VERBOSE: + rl = REPORT_VERBOSE; + break; + + case BUNDLE_EXTENSION_LOG_LEVEL_DEBUG: + rl = REPORT_DEBUG; + break; + + case BUNDLE_EXTENSION_LOG_LEVEL_ERROR: + rl = REPORT_ERROR; + break; + + default: + ExitFunction1(hr = E_INVALIDARG); + } + + hr = LogStringLine(rl, "%ls", wzMessage); + ExitOnFailure(hr, "Failed to log Bundle Extension message."); + +LExit: + return hr; +} + +static HRESULT BEEngineSetVariableLiteralString( + __in BURN_EXTENSION_ENGINE_CONTEXT* pContext, + __in const BUNDLE_EXTENSION_ENGINE_SETVARIABLELITERALSTRING_ARGS* pArgs, + __in BUNDLE_EXTENSION_ENGINE_SETVARIABLELITERALSTRING_RESULTS* /*pResults*/ + ) +{ + HRESULT hr = S_OK; + LPCWSTR wzVariable = pArgs->wzVariable; + LPCWSTR wzValue = pArgs->wzValue; + + if (wzVariable && *wzVariable) + { + hr = VariableSetLiteralString(&pContext->pEngineState->variables, wzVariable, wzValue, FALSE); + ExitOnFailure(hr, "Failed to set literal string variable."); + } + else + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "Bundle Extension did not provide variable name."); + } + +LExit: + return hr; +} + +static HRESULT BEEngineSetVariableNumeric( + __in BURN_EXTENSION_ENGINE_CONTEXT* pContext, + __in const BUNDLE_EXTENSION_ENGINE_SETVARIABLENUMERIC_ARGS* pArgs, + __in BUNDLE_EXTENSION_ENGINE_SETVARIABLENUMERIC_RESULTS* /*pResults*/ + ) +{ + HRESULT hr = S_OK; + LPCWSTR wzVariable = pArgs->wzVariable; + LONGLONG llValue = pArgs->llValue; + + if (wzVariable && *wzVariable) + { + hr = VariableSetNumeric(&pContext->pEngineState->variables, wzVariable, llValue, FALSE); + ExitOnFailure(hr, "Failed to set numeric variable."); + } + else + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "Bundle Extension did not provide variable name."); + } + +LExit: + return hr; +} + +static HRESULT BEEngineSetVariableString( + __in BURN_EXTENSION_ENGINE_CONTEXT* pContext, + __in const BUNDLE_EXTENSION_ENGINE_SETVARIABLESTRING_ARGS* pArgs, + __in BUNDLE_EXTENSION_ENGINE_SETVARIABLESTRING_RESULTS* /*pResults*/ + ) +{ + HRESULT hr = S_OK; + LPCWSTR wzVariable = pArgs->wzVariable; + LPCWSTR wzValue = pArgs->wzValue; + + if (wzVariable && *wzVariable) + { + hr = VariableSetString(&pContext->pEngineState->variables, wzVariable, wzValue, FALSE); + ExitOnFailure(hr, "Failed to set string variable."); + } + else + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "Bundle Extension did not provide variable name."); + } + +LExit: + return hr; +} + +static HRESULT BEEngineSetVariableVersion( + __in BURN_EXTENSION_ENGINE_CONTEXT* pContext, + __in const BUNDLE_EXTENSION_ENGINE_SETVARIABLEVERSION_ARGS* pArgs, + __in BUNDLE_EXTENSION_ENGINE_SETVARIABLEVERSION_RESULTS* /*pResults*/ + ) +{ + HRESULT hr = S_OK; + LPCWSTR wzVariable = pArgs->wzVariable; + DWORD64 qwValue = pArgs->qwValue; + + if (wzVariable && *wzVariable) + { + hr = VariableSetVersion(&pContext->pEngineState->variables, wzVariable, qwValue, FALSE); + ExitOnFailure(hr, "Failed to set version variable."); + } + else + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "Bundle Extension did not provide variable name."); + } + +LExit: + return hr; +} + +HRESULT WINAPI EngineForExtensionProc( + __in BUNDLE_EXTENSION_ENGINE_MESSAGE message, + __in const LPVOID pvArgs, + __inout LPVOID pvResults, + __in_opt LPVOID pvContext + ) +{ + HRESULT hr = S_OK; + BURN_EXTENSION_ENGINE_CONTEXT* pContext = reinterpret_cast(pvContext); + + if (!pContext || !pvArgs || !pvResults) + { + ExitFunction1(hr = E_INVALIDARG); + } + + switch (message) + { + case BUNDLE_EXTENSION_ENGINE_MESSAGE_ESCAPESTRING: + hr = BEEngineEscapeString(pContext, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; + case BUNDLE_EXTENSION_ENGINE_MESSAGE_EVALUATECONDITION: + hr = BEEngineEvaluateCondition(pContext, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; + case BUNDLE_EXTENSION_ENGINE_MESSAGE_FORMATSTRING: + hr = BEEngineFormatString(pContext, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; + case BUNDLE_EXTENSION_ENGINE_MESSAGE_GETVARIABLENUMERIC: + hr = BEEngineGetVariableNumeric(pContext, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; + case BUNDLE_EXTENSION_ENGINE_MESSAGE_GETVARIABLESTRING: + hr = BEEngineGetVariableString(pContext, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; + case BUNDLE_EXTENSION_ENGINE_MESSAGE_GETVARIABLEVERSION: + hr = BEEngineGetVariableVersion(pContext, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; + case BUNDLE_EXTENSION_ENGINE_MESSAGE_LOG: + hr = BEEngineLog(pContext, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; + case BUNDLE_EXTENSION_ENGINE_MESSAGE_SETVARIABLELITERALSTRING: + hr = BEEngineSetVariableLiteralString(pContext, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; + case BUNDLE_EXTENSION_ENGINE_MESSAGE_SETVARIABLENUMERIC: + hr = BEEngineSetVariableNumeric(pContext, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; + case BUNDLE_EXTENSION_ENGINE_MESSAGE_SETVARIABLESTRING: + hr = BEEngineSetVariableString(pContext, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; + case BUNDLE_EXTENSION_ENGINE_MESSAGE_SETVARIABLEVERSION: + hr = BEEngineSetVariableVersion(pContext, reinterpret_cast(pvArgs), reinterpret_cast(pvResults)); + break; + default: + hr = E_NOTIMPL; + break; + } + +LExit: + return hr; +} diff --git a/src/engine/EngineForExtension.h b/src/engine/EngineForExtension.h new file mode 100644 index 00000000..bad5f08a --- /dev/null +++ b/src/engine/EngineForExtension.h @@ -0,0 +1,27 @@ +#pragma once +// 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. + + +#if defined(__cplusplus) +extern "C" { +#endif + +// structs + +typedef struct _BURN_EXTENSION_ENGINE_CONTEXT +{ + BURN_ENGINE_STATE* pEngineState; +} BURN_EXTENSION_ENGINE_CONTEXT; + +// function declarations + +HRESULT WINAPI EngineForExtensionProc( + __in BUNDLE_EXTENSION_ENGINE_MESSAGE message, + __in const LPVOID pvArgs, + __inout LPVOID pvResults, + __in_opt LPVOID pvContext + ); + +#if defined(__cplusplus) +} +#endif diff --git a/src/engine/burnextension.cpp b/src/engine/burnextension.cpp new file mode 100644 index 00000000..99673cd9 --- /dev/null +++ b/src/engine/burnextension.cpp @@ -0,0 +1,184 @@ +// 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. + +#include "precomp.h" + +// function definitions + +/******************************************************************* + BurnExtensionParseFromXml - + +*******************************************************************/ +EXTERN_C HRESULT BurnExtensionParseFromXml( + __in BURN_EXTENSIONS* pBurnExtensions, + __in BURN_PAYLOADS* pBaPayloads, + __in IXMLDOMNode* pixnBundle + ) +{ + HRESULT hr = S_OK; + IXMLDOMNodeList* pixnNodes = NULL; + IXMLDOMNode* pixnNode = NULL; + DWORD cNodes = 0; + + // Select BundleExtension nodes. + hr = XmlSelectNodes(pixnBundle, L"BundleExtension", &pixnNodes); + ExitOnFailure(hr, "Failed to select BundleExtension nodes."); + + // Get BundleExtension node count. + hr = pixnNodes->get_length((long*)&cNodes); + ExitOnFailure(hr, "Failed to get BundleExtension node count."); + + if (!cNodes) + { + ExitFunction(); + } + + // Allocate memory for BundleExtensions. + pBurnExtensions->rgExtensions = (BURN_EXTENSION*)MemAlloc(sizeof(BURN_EXTENSION) * cNodes, TRUE); + ExitOnNull(pBurnExtensions->rgExtensions, hr, E_OUTOFMEMORY, "Failed to allocate memory for BundleExtension structs."); + + pBurnExtensions->cExtensions = cNodes; + + // parse search elements + for (DWORD i = 0; i < cNodes; ++i) + { + BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i]; + + hr = XmlNextElement(pixnNodes, &pixnNode, NULL); + ExitOnFailure(hr, "Failed to get next node."); + + // @Id + hr = XmlGetAttributeEx(pixnNode, L"Id", &pExtension->sczId); + ExitOnFailure(hr, "Failed to get @Id."); + + // @EntryPayloadId + hr = XmlGetAttributeEx(pixnNode, L"EntryPayloadId", &pExtension->sczEntryPayloadId); + ExitOnFailure(hr, "Failed to get @EntryPayloadId."); + + hr = PayloadFindById(pBaPayloads, pExtension->sczEntryPayloadId, &pExtension->pEntryPayload); + ExitOnFailure(hr, "Failed to find BundleExtension EntryPayload '%ls'.", pExtension->sczEntryPayloadId); + + // prepare next iteration + ReleaseNullObject(pixnNode); + } + + hr = S_OK; + +LExit: + ReleaseObject(pixnNode); + ReleaseObject(pixnNodes); + + return hr; +} + +/******************************************************************* + BurnExtensionUninitialize - + +*******************************************************************/ +EXTERN_C void BurnExtensionUninitialize( + __in BURN_EXTENSIONS* pBurnExtensions + ) +{ + if (pBurnExtensions->rgExtensions) + { + for (DWORD i = 0; i < pBurnExtensions->cExtensions; ++i) + { + BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i]; + + ReleaseStr(pExtension->sczEntryPayloadId); + ReleaseStr(pExtension->sczId); + } + MemFree(pBurnExtensions->rgExtensions); + } + + // clear struct + memset(pBurnExtensions, 0, sizeof(BURN_EXTENSIONS)); +} + +/******************************************************************* + BurnExtensionLoad - + +*******************************************************************/ +EXTERN_C HRESULT BurnExtensionLoad( + __in BURN_EXTENSIONS * pBurnExtensions, + __in BURN_EXTENSION_ENGINE_CONTEXT* pEngineContext + ) +{ + HRESULT hr = S_OK; + BUNDLE_EXTENSION_CREATE_ARGS args = { }; + BUNDLE_EXTENSION_CREATE_RESULTS results = { }; + + if (!pBurnExtensions->rgExtensions || !pBurnExtensions->cExtensions) + { + ExitFunction(); + } + + for (DWORD i = 0; i < pBurnExtensions->cExtensions; ++i) + { + BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i]; + + memset(&args, 0, sizeof(BUNDLE_EXTENSION_CREATE_ARGS)); + memset(&results, 0, sizeof(BUNDLE_EXTENSION_CREATE_RESULTS)); + + args.cbSize = sizeof(BUNDLE_EXTENSION_CREATE_ARGS); + args.pfnBundleExtensionEngineProc = EngineForExtensionProc; + args.pvBundleExtensionEngineProcContext = pEngineContext; + args.qwEngineAPIVersion = MAKEQWORDVERSION(0, 0, 0, 1); // TODO: need to decide whether to keep this, and if so when to update it. + + results.cbSize = sizeof(BUNDLE_EXTENSION_CREATE_RESULTS); + + // Load BundleExtension DLL. + pExtension->hBextModule = ::LoadLibraryExW(pExtension->pEntryPayload->sczLocalFilePath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + ExitOnNullWithLastError(pExtension->hBextModule, hr, "Failed to load BundleExtension DLL '%ls': '%ls'.", pExtension->sczId, pExtension->pEntryPayload->sczLocalFilePath); + + // Get BundleExtensionCreate entry-point. + PFN_BUNDLE_EXTENSION_CREATE pfnCreate = (PFN_BUNDLE_EXTENSION_CREATE)::GetProcAddress(pExtension->hBextModule, "BundleExtensionCreate"); + ExitOnNullWithLastError(pfnCreate, hr, "Failed to get BundleExtensionCreate entry-point '%ls'.", pExtension->sczId); + + // Create BundleExtension. + hr = pfnCreate(&args, &results); + ExitOnFailure(hr, "Failed to create BundleExtension '%ls'.", pExtension->sczId); + + pExtension->pfnBurnExtensionProc = results.pfnBundleExtensionProc; + pExtension->pvBurnExtensionProcContext = results.pvBundleExtensionProcContext; + } + +LExit: + return hr; +} + +/******************************************************************* + BurnExtensionUnload - + +*******************************************************************/ +EXTERN_C void BurnExtensionUnload( + __in BURN_EXTENSIONS * pBurnExtensions + ) +{ + HRESULT hr = S_OK; + + if (pBurnExtensions->rgExtensions) + { + for (DWORD i = 0; i < pBurnExtensions->cExtensions; ++i) + { + BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i]; + + if (pExtension->hBextModule) + { + // Get BundleExtensionDestroy entry-point and call it if it exists. + PFN_BUNDLE_EXTENSION_DESTROY pfnDestroy = (PFN_BUNDLE_EXTENSION_DESTROY)::GetProcAddress(pExtension->hBextModule, "BundleExtensionDestroy"); + if (pfnDestroy) + { + pfnDestroy(); + } + + // Free BundleExtension DLL. + if (!::FreeLibrary(pExtension->hBextModule)) + { + hr = HRESULT_FROM_WIN32(::GetLastError()); + TraceError(hr, "Failed to unload BundleExtension DLL."); + } + pExtension->hBextModule = NULL; + } + } + } +} diff --git a/src/engine/burnextension.h b/src/engine/burnextension.h new file mode 100644 index 00000000..43c8afe6 --- /dev/null +++ b/src/engine/burnextension.h @@ -0,0 +1,51 @@ +#pragma once +// 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. + +#define BEEAPI HRESULT __stdcall + +#if defined(__cplusplus) +extern "C" { +#endif + +// structs + +typedef struct _BURN_EXTENSION_ENGINE_CONTEXT BURN_EXTENSION_ENGINE_CONTEXT; + +typedef struct _BURN_EXTENSION +{ + LPWSTR sczEntryPayloadId; + LPWSTR sczId; + + BURN_PAYLOAD* pEntryPayload; + + HMODULE hBextModule; + PFN_BUNDLE_EXTENSION_PROC pfnBurnExtensionProc; + LPVOID pvBurnExtensionProcContext; +} BURN_EXTENSION; + +typedef struct _BURN_EXTENSIONS +{ + BURN_EXTENSION* rgExtensions; + DWORD cExtensions; +} BURN_EXTENSIONS; + +// functions + +HRESULT BurnExtensionParseFromXml( + __in BURN_EXTENSIONS* pBurnExtensions, + __in BURN_PAYLOADS* pBaPayloads, + __in IXMLDOMNode* pixnBundle + ); +void BurnExtensionUninitialize( + __in BURN_EXTENSIONS* pBurnExtensions + ); +HRESULT BurnExtensionLoad( + __in BURN_EXTENSIONS* pBurnExtensions, + __in BURN_EXTENSION_ENGINE_CONTEXT* pEngineContext + ); +void BurnExtensionUnload( + __in BURN_EXTENSIONS* pBurnExtensions + ); +#if defined(__cplusplus) +} +#endif diff --git a/src/engine/core.h b/src/engine/core.h index 6a6da2b1..544c1786 100644 --- a/src/engine/core.h +++ b/src/engine/core.h @@ -103,6 +103,7 @@ typedef struct _BURN_ENGINE_STATE BURN_PACKAGES packages; BURN_UPDATE update; BURN_APPROVED_EXES approvedExes; + BURN_EXTENSIONS extensions; HWND hMessageWindow; HANDLE hMessageWindowThread; diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 341fd471..488dbfe8 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -352,6 +352,8 @@ static void UninitializeEngineState( ReleaseHandle(pEngineState->hMessageWindowThread); + BurnExtensionUninitialize(&pEngineState->extensions); + ::DeleteCriticalSection(&pEngineState->userExperience.csEngineActive); UserExperienceUninitialize(&pEngineState->userExperience); @@ -493,6 +495,7 @@ static HRESULT RunNormal( HANDLE hPipesCreatedEvent = NULL; BOOL fContinueExecution = TRUE; BOOL fReloadApp = FALSE; + BURN_EXTENSION_ENGINE_CONTEXT extensionEngineContext = { }; // Initialize logging. hr = LoggingOpen(&pEngineState->log, &pEngineState->variables, pEngineState->command.display, pEngineState->registration.sczDisplayName); @@ -537,6 +540,13 @@ static HRESULT RunNormal( ExitOnFailure(hr, "Failed to set layout directory variable to value provided from command-line."); } + // Setup the extension engine. + extensionEngineContext.pEngineState = pEngineState; + + // Load the extensions. + hr = BurnExtensionLoad(&pEngineState->extensions, &extensionEngineContext); + ExitOnFailure(hr, "Failed to load BundleExtensions."); + do { fReloadApp = FALSE; @@ -546,6 +556,8 @@ static HRESULT RunNormal( } while (fReloadApp); LExit: + BurnExtensionUnload(&pEngineState->extensions); + // If the message window is still around, close it. UiCloseMessageWindow(pEngineState); diff --git a/src/engine/engine.vcxproj b/src/engine/engine.vcxproj index 499fcd4d..c2e8f34c 100644 --- a/src/engine/engine.vcxproj +++ b/src/engine/engine.vcxproj @@ -2,7 +2,7 @@ - + @@ -50,10 +50,12 @@ + + @@ -90,15 +92,11 @@ - - - - - + @@ -110,6 +108,7 @@ + @@ -167,7 +166,7 @@ rc.exe -fo "$(OutDir)engine.res" "$(IntDir)engine.messages.rc" This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/src/engine/manifest.cpp b/src/engine/manifest.cpp index c2214a89..a20f1980 100644 --- a/src/engine/manifest.cpp +++ b/src/engine/manifest.cpp @@ -116,6 +116,10 @@ extern "C" HRESULT ManifestLoadXmlFromBuffer( hr = ApprovedExesParseFromXml(&pEngineState->approvedExes, pixeBundle); ExitOnFailure(hr, "Failed to parse approved exes."); + // parse extensions + hr = BurnExtensionParseFromXml(&pEngineState->extensions, &pEngineState->userExperience.payloads, pixeBundle); + ExitOnFailure(hr, "Failed to parse extensions."); + LExit: ReleaseObject(pixnChain); ReleaseObject(pixnLog); diff --git a/src/engine/packages.config b/src/engine/packages.config index 01a9390c..75a6476b 100644 --- a/src/engine/packages.config +++ b/src/engine/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/engine/precomp.h b/src/engine/precomp.h index 477dc310..780822a1 100644 --- a/src/engine/precomp.h +++ b/src/engine/precomp.h @@ -61,6 +61,8 @@ #include "BootstrapperEngine.h" #include "BootstrapperApplication.h" +#include "BundleExtensionEngine.h" +#include "BundleExtension.h" #include "platform.h" #include "variant.h" @@ -73,6 +75,7 @@ #include "catalog.h" #include "payload.h" #include "cabextract.h" +#include "burnextension.h" #include "userexperience.h" #include "package.h" #include "update.h" @@ -100,4 +103,5 @@ #include "netfxchainer.h" #include "EngineForApplication.h" +#include "EngineForExtension.h" #include "engine.messages.h" diff --git a/src/engine/userexperience.cpp b/src/engine/userexperience.cpp index 8d5271aa..26b20f39 100644 --- a/src/engine/userexperience.cpp +++ b/src/engine/userexperience.cpp @@ -103,7 +103,7 @@ extern "C" HRESULT UserExperienceLoad( // Load BA DLL. pUserExperience->hUXModule = ::LoadLibraryExW(pUserExperience->payloads.rgPayloads[0].sczLocalFilePath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - ExitOnNullWithLastError(pUserExperience->hUXModule, hr, "Failed to load UX DLL."); + ExitOnNullWithLastError(pUserExperience->hUXModule, hr, "Failed to load BA DLL."); // Get BootstrapperApplicationCreate entry-point. PFN_BOOTSTRAPPER_APPLICATION_CREATE pfnCreate = (PFN_BOOTSTRAPPER_APPLICATION_CREATE)::GetProcAddress(pUserExperience->hUXModule, "BootstrapperApplicationCreate"); diff --git a/src/engine/userexperience.h b/src/engine/userexperience.h index 27a94115..bec6d292 100644 --- a/src/engine/userexperience.h +++ b/src/engine/userexperience.h @@ -15,7 +15,7 @@ const DWORD MB_RETRYTRYAGAIN = 0xF; // structs -struct BOOTSTRAPPER_ENGINE_CONTEXT; +typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT BOOTSTRAPPER_ENGINE_CONTEXT; typedef struct _BURN_USER_EXPERIENCE { diff --git a/src/engine/variable.cpp b/src/engine/variable.cpp index 7377b116..8b1fd279 100644 --- a/src/engine/variable.cpp +++ b/src/engine/variable.cpp @@ -309,7 +309,7 @@ extern "C" HRESULT VariablesParseFromXml( hr = pixnNodes->get_length((long*)&cNodes); ExitOnFailure(hr, "Failed to get variable node count."); - // parse package elements + // parse variable elements for (DWORD i = 0; i < cNodes; ++i) { hr = XmlNextElement(pixnNodes, &pixnNode, NULL); -- cgit v1.2.3-55-g6feb