aspnetcore/src/CommonLib/hostfxr_utility.cpp

372 lines
8.9 KiB
C++

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
#include "stdafx.h"
HOSTFXR_UTILITY::HOSTFXR_UTILITY()
{
}
HOSTFXR_UTILITY::~HOSTFXR_UTILITY()
{
}
//
// Runs a standalone appliction.
// The folder structure looks like this:
// Application/
// hostfxr.dll
// Application.exe
// Application.dll
// etc.
// We get the full path to hostfxr.dll and Application.dll and run hostfxr_main,
// passing in Application.dll.
// Assuming we don't need Application.exe as the dll is the actual application.
//
HRESULT
HOSTFXR_UTILITY::GetStandaloneHostfxrParameters(
PCWSTR pwzExePath,
ASPNETCORE_CONFIG *pConfig
)
{
HRESULT hr = S_OK;
STRU struDllPath;
STRU struArguments;
DWORD dwPosition;
if (FAILED(hr))
{
goto Finished;
}
if (FAILED(hr = struDllPath.Copy(pwzExePath)))
{
goto Finished;
}
dwPosition = struDllPath.LastIndexOf(L'.', 0);
if (dwPosition == -1)
{
hr = E_FAIL;
goto Finished;
}
struDllPath.QueryStr()[dwPosition] = L'\0';
if (FAILED(hr = struDllPath.SyncWithBuffer()) ||
FAILED(hr = struDllPath.Append(L".dll")))
{
goto Finished;
}
if (!UTILITY::CheckIfFileExists(struDllPath.QueryStr()))
{
// Treat access issue as File not found
hr = ERROR_FILE_NOT_FOUND;
goto Finished;
}
if (FAILED(hr = struArguments.Copy(struDllPath)) ||
FAILED(hr = struArguments.Append(L" ")) ||
FAILED(hr = struArguments.Append(pConfig->QueryArguments())))
{
goto Finished;
}
if (FAILED(hr = SetHostFxrArguments(struArguments.QueryStr(), pwzExePath, pConfig)))
{
goto Finished;
}
Finished:
return hr;
}
HRESULT
HOSTFXR_UTILITY::GetHostFxrParameters(
ASPNETCORE_CONFIG *pConfig
)
{
HRESULT hr = S_OK;
STRU struSystemPathVariable;
STRU struHostFxrPath;
STRU struExeLocation;
STRU struHostFxrSearchExpression;
STRU struHighestDotnetVersion;
std::vector<std::wstring> vVersionFolders;
DWORD dwPosition;
DWORD dwPathLength = MAX_PATH;
DWORD dwDotnetLength = 0;
BOOL fFound = FALSE;
// Convert the process path an absolute path.
hr = UTILITY::ConvertPathToFullPath(
pConfig->QueryProcessPath()->QueryStr(),
pConfig->QueryApplicationPhysicalPath()->QueryStr(),
&struExeLocation
);
if (FAILED(hr))
{
goto Finished;
}
if (UTILITY::CheckIfFileExists(struExeLocation.QueryStr()))
{
// Check if hostfxr is in this folder, if it is, we are a standalone application,
// else we assume we received an absolute path to dotnet.exe
hr = UTILITY::ConvertPathToFullPath(L".\\hostfxr.dll", pConfig->QueryApplicationPhysicalPath()->QueryStr(), &struHostFxrPath);
if (FAILED(hr))
{
goto Finished;
}
if (UTILITY::CheckIfFileExists(struHostFxrPath.QueryStr()))
{
// Standalone application
if (FAILED(hr = pConfig->SetHostFxrFullPath(struHostFxrPath.QueryStr())))
{
goto Finished;
}
hr = GetStandaloneHostfxrParameters(struExeLocation.QueryStr(), pConfig);
goto Finished;
}
}
else
{
if (FAILED(hr = struExeLocation.Resize(MAX_PATH)))
{
goto Finished;
}
while (!fFound)
{
dwDotnetLength = SearchPath(NULL, L"dotnet", L".exe", dwPathLength, struExeLocation.QueryStr(), NULL);
if (dwDotnetLength == 0)
{
hr = GetLastError();
// Could not find dotnet
goto Finished;
}
else if (dwDotnetLength == dwPathLength)
{
// Increase size
dwPathLength *= 2;
if (FAILED(hr = struExeLocation.Resize(dwPathLength)))
{
goto Finished;
}
}
else
{
fFound = TRUE;
}
}
}
if (FAILED(hr = struExeLocation.SyncWithBuffer())
|| FAILED(hr = struHostFxrPath.Copy(struExeLocation)))
{
goto Finished;
}
dwPosition = struHostFxrPath.LastIndexOf(L'\\', 0);
if (dwPosition == -1)
{
hr = E_FAIL;
goto Finished;
}
struHostFxrPath.QueryStr()[dwPosition] = L'\0';
if (FAILED(hr = struHostFxrPath.SyncWithBuffer())
|| FAILED(hr = struHostFxrPath.Append(L"\\")))
{
goto Finished;
}
hr = struHostFxrPath.Append(L"host\\fxr");
if (FAILED(hr))
{
goto Finished;
}
if (!UTILITY::DirectoryExists(&struHostFxrPath))
{
// error, not found in folder
hr = ERROR_BAD_ENVIRONMENT;
goto Finished;
}
// Find all folders under host\\fxr\\ for version numbers.
hr = struHostFxrSearchExpression.Copy(struHostFxrPath);
if (FAILED(hr))
{
goto Finished;
}
hr = struHostFxrSearchExpression.Append(L"\\*");
if (FAILED(hr))
{
goto Finished;
}
// As we use the logic from core-setup, we are opting to use std here.
// TODO remove all uses of std?
UTILITY::FindDotNetFolders(struHostFxrSearchExpression.QueryStr(), &vVersionFolders);
if (vVersionFolders.size() == 0)
{
// no core framework was found
hr = ERROR_BAD_ENVIRONMENT;
goto Finished;
}
hr = UTILITY::FindHighestDotNetVersion(vVersionFolders, &struHighestDotnetVersion);
if (FAILED(hr))
{
goto Finished;
}
if (FAILED(hr = struHostFxrPath.Append(L"\\"))
|| FAILED(hr = struHostFxrPath.Append(struHighestDotnetVersion.QueryStr()))
|| FAILED(hr = struHostFxrPath.Append(L"\\hostfxr.dll")))
{
goto Finished;
}
if (!UTILITY::CheckIfFileExists(struHostFxrPath.QueryStr()))
{
hr = ERROR_FILE_INVALID;
goto Finished;
}
if (FAILED(hr = SetHostFxrArguments(pConfig->QueryArguments()->QueryStr(), struExeLocation.QueryStr(), pConfig)))
{
goto Finished;
}
if (FAILED(hr = pConfig->SetHostFxrFullPath(struHostFxrPath.QueryStr())))
{
goto Finished;
}
Finished:
return hr;
}
//
// Forms the argument list in HOSTFXR_PARAMETERS.
// Sets the ArgCount and Arguments.
// Arg structure:
// argv[0] = Path to exe activating hostfxr.
// argv[1] = L"exec"
// argv[2] = absolute path to dll.
//
HRESULT
HOSTFXR_UTILITY::SetHostFxrArguments(
PCWSTR pwzArgumentsFromConfig,
PCWSTR pwzExePath,
ASPNETCORE_CONFIG* pConfig
)
{
HRESULT hr = S_OK;
INT argc = 0;
PCWSTR* argv = NULL;
LPWSTR* pwzArgs = NULL;
STRU struTempPath;
DWORD dwArgsProcessed = 0;
pwzArgs = CommandLineToArgvW(pwzArgumentsFromConfig, &argc);
if (pwzArgs == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Failure;
}
if (argc < 1)
{
// Invalid arguments
hr = E_INVALIDARG;
goto Failure;
}
argv = new PCWSTR[argc + 2];
if (argv == NULL)
{
hr = E_OUTOFMEMORY;
goto Failure;
}
argv[0] = SysAllocString(pwzExePath);
if (argv[0] == NULL)
{
hr = E_OUTOFMEMORY;
goto Failure;
}
dwArgsProcessed++;
argv[1] = SysAllocString(L"exec");
if (argv[1] == NULL)
{
hr = E_OUTOFMEMORY;
goto Failure;
}
dwArgsProcessed++;
// Try to convert the application dll from a relative to an absolute path
// Don't record this failure as pwzArgs[0] may already be an absolute path to the dll.
if (SUCCEEDED(UTILITY::ConvertPathToFullPath(pwzArgs[0], pConfig->QueryApplicationPhysicalPath()->QueryStr(), &struTempPath)))
{
argv[2] = SysAllocString(struTempPath.QueryStr());
}
else
{
argv[2] = SysAllocString(pwzArgs[0]);
}
if (argv[2] == NULL)
{
hr = E_OUTOFMEMORY;
goto Failure;
}
dwArgsProcessed++;
for (INT i = 1; i < argc; i++)
{
argv[i + 2] = SysAllocString(pwzArgs[i]);
if (argv[i + 2] == NULL)
{
hr = E_OUTOFMEMORY;
goto Failure;
}
dwArgsProcessed++;
}
pConfig->SetHostFxrArguments(argc + 2, argv);
goto Finished;
Failure:
if (argv != NULL)
{
for (DWORD i = 0; i < dwArgsProcessed; i++)
{
SysFreeString((BSTR)argv[i]);
}
}
delete[] argv;
Finished:
if (pwzArgs != NULL)
{
LocalFree(pwzArgs);
DBG_ASSERT(pwzArgs == NULL);
}
return hr;
}