From 39e930d9aaff250e0fd5019eeedaa40717a6c6fe Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Wed, 29 Apr 2020 19:28:50 +1000 Subject: Add DotNetCoreBootstrapperApplicationHost for an SCD-style .NET Core BA. --- src/dnchost/dnchost.cpp | 229 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 src/dnchost/dnchost.cpp (limited to 'src/dnchost/dnchost.cpp') diff --git a/src/dnchost/dnchost.cpp b/src/dnchost/dnchost.cpp new file mode 100644 index 00000000..c4b0d222 --- /dev/null +++ b/src/dnchost/dnchost.cpp @@ -0,0 +1,229 @@ +// 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 DNCSTATE vstate = { }; + + +// internal function declarations + +static HRESULT LoadModulePaths( + __in DNCSTATE* pState + ); +static HRESULT LoadDncConfiguration( + __in DNCSTATE* pState, + __in const BOOTSTRAPPER_CREATE_ARGS* pArgs + ); +static HRESULT LoadRuntime( + __in DNCSTATE* pState + ); +static HRESULT LoadManagedBootstrapperApplicationFactory( + __in DNCSTATE* pState + ); + + +// function definitions + +extern "C" BOOL WINAPI DllMain( + IN HINSTANCE hInstance, + IN DWORD dwReason, + IN LPVOID /* pvReserved */ + ) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + ::DisableThreadLibraryCalls(hInstance); + vstate.hInstance = hInstance; + break; + + case DLL_PROCESS_DETACH: + vstate.hInstance = NULL; + break; + } + + return TRUE; +} + +extern "C" HRESULT WINAPI BootstrapperApplicationCreate( + __in const BOOTSTRAPPER_CREATE_ARGS* pArgs, + __inout BOOTSTRAPPER_CREATE_RESULTS* pResults + ) +{ + HRESULT hr = S_OK; + IBootstrapperEngine* pEngine = NULL; + + // coreclr.dll doesn't support unloading, so the rest of the .NET Core hosting stack doesn't support it either. + // This means we also can't unload. + pResults->fDisableUnloading = TRUE; + + hr = BalInitializeFromCreateArgs(pArgs, &pEngine); + ExitOnFailure(hr, "Failed to initialize Bal."); + + if (!vstate.fInitialized) + { + hr = XmlInitialize(); + BalExitOnFailure(hr, "Failed to initialize XML."); + + hr = LoadModulePaths(&vstate); + BalExitOnFailure(hr, "Failed to get the host base path."); + + hr = LoadDncConfiguration(&vstate, pArgs); + BalExitOnFailure(hr, "Failed to get the dnc configuration."); + + vstate.fInitialized = TRUE; + } + + if (!vstate.fInitializedRuntime) + { + hr = LoadRuntime(&vstate); + BalExitOnFailure(hr, "Failed to load .NET Core runtime."); + + vstate.fInitializedRuntime = TRUE; + + hr = LoadManagedBootstrapperApplicationFactory(&vstate); + BalExitOnFailure(hr, "Failed to create the .NET Core bootstrapper application factory."); + } + + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading .NET Core SCD bootstrapper application."); + + hr = vstate.pAppFactory->Create(pArgs, pResults); + BalExitOnFailure(hr, "Failed to create the .NET Core bootstrapper application."); + +LExit: + ReleaseNullObject(pEngine); + + return hr; +} + +extern "C" void WINAPI BootstrapperApplicationDestroy() +{ + BalUninitialize(); +} + +static HRESULT LoadModulePaths( + __in DNCSTATE* pState + ) +{ + HRESULT hr = S_OK; + + hr = PathForCurrentProcess(&pState->sczModuleFullPath, pState->hInstance); + BalExitOnFailure(hr, "Failed to get the full host path."); + + hr = PathGetDirectory(pState->sczModuleFullPath, &pState->sczAppBase); + BalExitOnFailure(hr, "Failed to get the directory of the full process path."); + + hr = PathConcat(pState->sczAppBase, DNC_ASSEMBLY_FILE_NAME, &pState->sczManagedHostPath); + BalExitOnFailure(hr, "Failed to create managed host path."); + +LExit: + return hr; +} + +static HRESULT LoadDncConfiguration( + __in DNCSTATE* pState, + __in const BOOTSTRAPPER_CREATE_ARGS* pArgs + ) +{ + HRESULT hr = S_OK; + IXMLDOMDocument* pixdManifest = NULL; + IXMLDOMNode* pixnHost = NULL; + IXMLDOMNode* pixnPayload = NULL; + LPWSTR sczPayloadId = NULL; + LPWSTR sczPayloadXPath = NULL; + LPWSTR sczPayloadName = NULL; + + hr = XmlLoadDocumentFromFile(pArgs->pCommand->wzBootstrapperApplicationDataPath, &pixdManifest); + BalExitOnFailure(hr, "Failed to load BalManifest '%ls'", pArgs->pCommand->wzBootstrapperApplicationDataPath); + + hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixBalBAFactoryAssembly", &pixnHost); + BalExitOnFailure(hr, "Failed to get WixBalBAFactoryAssembly element."); + + if (S_FALSE == hr) + { + hr = E_NOTFOUND; + BalExitOnRootFailure(hr, "Failed to find WixBalBAFactoryAssembly element in bootstrapper application config."); + } + + hr = XmlGetAttributeEx(pixnHost, L"PayloadId", &sczPayloadId); + BalExitOnFailure(hr, "Failed to get WixBalBAFactoryAssembly/@PayloadId."); + + hr = StrAllocFormatted(&sczPayloadXPath, L"/BootstrapperApplicationData/WixPayloadProperties[@Payload='%ls']", sczPayloadId); + BalExitOnFailure(hr, "Failed to format BAFactoryAssembly payload XPath."); + + hr = XmlSelectSingleNode(pixdManifest, sczPayloadXPath, &pixnPayload); + if (S_FALSE == hr) + { + hr = E_NOTFOUND; + } + BalExitOnFailure(hr, "Failed to find WixPayloadProperties node for BAFactoryAssembly PayloadId: %ls.", sczPayloadId); + + hr = XmlGetAttributeEx(pixnPayload, L"Name", &sczPayloadName); + BalExitOnFailure(hr, "Failed to get BAFactoryAssembly payload Name."); + + hr = PathConcat(pArgs->pCommand->wzBootstrapperWorkingFolder, sczPayloadName, &pState->sczBaFactoryAssemblyPath); + BalExitOnFailure(hr, "Failed to create BaFactoryAssemblyPath."); + + LPCWSTR wzFileName = PathFile(pState->sczBaFactoryAssemblyPath); + LPCWSTR wzExtension = PathExtension(pState->sczBaFactoryAssemblyPath); + if (!wzExtension) + { + BalExitOnFailure(hr = E_FAIL, "BaFactoryAssemblyPath has no extension."); + } + + hr = StrAllocString(&pState->sczBaFactoryAssemblyName, wzFileName, wzExtension - wzFileName); + BalExitOnFailure(hr, "Failed to copy BAFactoryAssembly payload Name."); + + hr = StrAllocString(&pState->sczBaFactoryDepsJsonPath, pState->sczBaFactoryAssemblyPath, wzExtension - pState->sczBaFactoryAssemblyPath); + BalExitOnFailure(hr, "Failed to initialize deps json path."); + + hr = StrAllocString(&pState->sczBaFactoryRuntimeConfigPath, pState->sczBaFactoryDepsJsonPath, 0); + BalExitOnFailure(hr, "Failed to initialize runtime config path."); + + hr = StrAllocConcat(&pState->sczBaFactoryDepsJsonPath, L".deps.json", 0); + BalExitOnFailure(hr, "Failed to concat extension to deps json path."); + + hr = StrAllocConcat(&pState->sczBaFactoryRuntimeConfigPath, L".runtimeconfig.json", 0); + BalExitOnFailure(hr, "Failed to concat extension to runtime config path."); + +LExit: + ReleaseStr(sczPayloadName); + ReleaseObject(pixnPayload); + ReleaseStr(sczPayloadXPath); + ReleaseStr(sczPayloadId); + ReleaseObject(pixnHost); + ReleaseObject(pixdManifest); + + return hr; +} + +static HRESULT LoadRuntime( + __in DNCSTATE* pState + ) +{ + HRESULT hr = S_OK; + + hr = DnchostLoadRuntime( + &pState->hostfxrState, + pState->sczModuleFullPath, + pState->sczManagedHostPath, + pState->sczBaFactoryDepsJsonPath, + pState->sczBaFactoryRuntimeConfigPath); + + return hr; +} + +static HRESULT LoadManagedBootstrapperApplicationFactory( + __in DNCSTATE* pState + ) +{ + HRESULT hr = S_OK; + + hr = DnchostCreateFactory( + &pState->hostfxrState, + pState->sczBaFactoryAssemblyName, + pState->sczBaFactoryAssemblyPath, + &pState->pAppFactory); + + return hr; +} -- cgit v1.2.3-55-g6feb