Use std::filesystem in hostfxr utilities (#926)
This commit is contained in:
parent
17fdbf6514
commit
60711bfca1
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define EVENTLOG(log, name, ...) UTILITY::LogEventF(log, ASPNETCORE_EVENT_ ## name ## _LEVEL, ASPNETCORE_EVENT_ ## name, ASPNETCORE_EVENT_ ## name ## _MSG, __VA_ARGS__)
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include <experimental/filesystem>
|
|
||||||
|
|
||||||
namespace fs = std::experimental::filesystem;
|
namespace fs = std::experimental::filesystem;
|
||||||
|
|
||||||
|
|
@ -96,7 +95,7 @@ GlobalVersionUtility::RemoveFileNameFromFolderPath(std::wstring fileName)
|
||||||
return path.parent_path();
|
return path.parent_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring
|
std::wstring
|
||||||
GlobalVersionUtility::GetModuleName(HMODULE hModuleName)
|
GlobalVersionUtility::GetModuleName(HMODULE hModuleName)
|
||||||
{
|
{
|
||||||
DWORD dwSize = MAX_PATH;
|
DWORD dwSize = MAX_PATH;
|
||||||
|
|
@ -126,6 +125,6 @@ GlobalVersionUtility::GetModuleName(HMODULE hModuleName)
|
||||||
fDone = TRUE;
|
fDone = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,15 @@ class GlobalVersionUtility
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static
|
static
|
||||||
std::wstring
|
std::wstring
|
||||||
GetGlobalRequestHandlerPath(PCWSTR pwzAspNetCoreFolderPath, PCWSTR pwzHandlerVersion, PCWSTR pwzHandlerName);
|
GetGlobalRequestHandlerPath(PCWSTR pwzAspNetCoreFolderPath, PCWSTR pwzHandlerVersion, PCWSTR pwzHandlerName);
|
||||||
|
|
||||||
static
|
static
|
||||||
std::wstring
|
std::wstring
|
||||||
FindHighestGlobalVersion(PCWSTR pwzAspNetCoreFolderPath);
|
FindHighestGlobalVersion(PCWSTR pwzAspNetCoreFolderPath);
|
||||||
|
|
||||||
static
|
static
|
||||||
std::wstring
|
std::wstring
|
||||||
RemoveFileNameFromFolderPath(std::wstring fileName);
|
RemoveFileNameFromFolderPath(std::wstring fileName);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,12 @@ Language=English
|
||||||
%1
|
%1
|
||||||
.
|
.
|
||||||
|
|
||||||
|
Messageid=1031
|
||||||
|
SymbolicName=ASPNETCORE_EVENT_INVALID_PROCESS_PATH
|
||||||
|
Language=English
|
||||||
|
%1
|
||||||
|
.
|
||||||
|
|
||||||
;
|
;
|
||||||
;#endif // _ASPNETCORE_MODULE_MSG_H_
|
;#endif // _ASPNETCORE_MODULE_MSG_H_
|
||||||
;
|
;
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,9 @@
|
||||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
HOSTFXR_UTILITY::HOSTFXR_UTILITY()
|
namespace fs = std::experimental::filesystem;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HOSTFXR_UTILITY::~HOSTFXR_UTILITY()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Runs a standalone appliction.
|
// Runs a standalone appliction.
|
||||||
|
|
@ -25,131 +20,72 @@ HOSTFXR_UTILITY::~HOSTFXR_UTILITY()
|
||||||
//
|
//
|
||||||
HRESULT
|
HRESULT
|
||||||
HOSTFXR_UTILITY::GetStandaloneHostfxrParameters(
|
HOSTFXR_UTILITY::GetStandaloneHostfxrParameters(
|
||||||
PCWSTR pwzExeAbsolutePath, // includes .exe file extension.
|
PCWSTR pwzExeAbsolutePath, // includes .exe file extension.
|
||||||
PCWSTR pcwzApplicationPhysicalPath,
|
PCWSTR pcwzApplicationPhysicalPath,
|
||||||
PCWSTR pcwzArguments,
|
PCWSTR pcwzArguments,
|
||||||
HANDLE hEventLog,
|
HANDLE hEventLog,
|
||||||
_Inout_ STRU* pStruHostFxrDllLocation,
|
_Inout_ STRU* pStruHostFxrDllLocation,
|
||||||
_Out_ DWORD* pdwArgCount,
|
_Out_ DWORD* pdwArgCount,
|
||||||
_Out_ BSTR** ppwzArgv
|
_Out_ BSTR** ppwzArgv
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
STRU struDllPath;
|
|
||||||
STRU struArguments;
|
|
||||||
STRU struHostFxrPath;
|
|
||||||
STRU struRuntimeConfigLocation;
|
|
||||||
DWORD dwPosition;
|
|
||||||
|
|
||||||
// Obtain the app name from the processPath section.
|
const fs::path exePath(pwzExeAbsolutePath);
|
||||||
if (FAILED(hr = struDllPath.Copy(pwzExeAbsolutePath)))
|
|
||||||
|
if (!exePath.has_extension())
|
||||||
{
|
{
|
||||||
goto Finished;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dwPosition = struDllPath.LastIndexOf(L'.', 0);
|
const fs::path physicalPath(pcwzApplicationPhysicalPath);
|
||||||
if (dwPosition == -1)
|
const fs::path hostFxrLocation = physicalPath / "hostfxr.dll";
|
||||||
{
|
|
||||||
hr = E_FAIL;
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = UTILITY::ConvertPathToFullPath(L".\\hostfxr.dll", pcwzApplicationPhysicalPath, &struHostFxrPath);
|
if (!is_regular_file(hostFxrLocation))
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
{
|
||||||
goto Finished;
|
fs::path runtimeConfigLocation = exePath;
|
||||||
}
|
runtimeConfigLocation.replace_extension(L".runtimeconfig.json");
|
||||||
|
|
||||||
struDllPath.QueryStr()[dwPosition] = L'\0';
|
if (!is_regular_file(runtimeConfigLocation))
|
||||||
if (FAILED(hr = struDllPath.SyncWithBuffer()))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UTILITY::CheckIfFileExists(struHostFxrPath.QueryStr()))
|
|
||||||
{
|
|
||||||
// Most likely a full framework app.
|
|
||||||
// Check that the runtime config file doesn't exist in the folder as another heuristic.
|
|
||||||
if (FAILED(hr = struRuntimeConfigLocation.Copy(struDllPath)) ||
|
|
||||||
FAILED(hr = struRuntimeConfigLocation.Append(L".runtimeconfig.json")))
|
|
||||||
{
|
{
|
||||||
goto Finished;
|
EVENTLOG(hEventLog, INPROCESS_FULL_FRAMEWORK_APP, pcwzApplicationPhysicalPath, 0);
|
||||||
}
|
return E_FAIL;
|
||||||
if (!UTILITY::CheckIfFileExists(struRuntimeConfigLocation.QueryStr()))
|
|
||||||
{
|
|
||||||
|
|
||||||
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
|
|
||||||
UTILITY::LogEventF(hEventLog,
|
|
||||||
EVENTLOG_ERROR_TYPE,
|
|
||||||
ASPNETCORE_EVENT_INPROCESS_FULL_FRAMEWORK_APP,
|
|
||||||
ASPNETCORE_EVENT_INPROCESS_FULL_FRAMEWORK_APP_MSG,
|
|
||||||
pcwzApplicationPhysicalPath,
|
|
||||||
hr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If a runtime config file does exist, report a file not found on the app.exe
|
|
||||||
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
||||||
UTILITY::LogEventF(hEventLog,
|
|
||||||
EVENTLOG_ERROR_TYPE,
|
|
||||||
ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND,
|
|
||||||
ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND_MSG,
|
|
||||||
pcwzApplicationPhysicalPath,
|
|
||||||
hr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
goto Finished;
|
EVENTLOG(hEventLog, APPLICATION_EXE_NOT_FOUND, pcwzApplicationPhysicalPath, 0);
|
||||||
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr = pStruHostFxrDllLocation->Copy(struHostFxrPath)))
|
fs::path dllPath = exePath;
|
||||||
|
dllPath.replace_extension(".dll");
|
||||||
|
|
||||||
|
if (!is_regular_file(dllPath))
|
||||||
{
|
{
|
||||||
goto Finished;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto arguments = std::wstring(dllPath) + L" " + pcwzArguments;
|
||||||
|
|
||||||
if (FAILED(hr = struDllPath.Append(L".dll")))
|
if (FAILED(hr = pStruHostFxrDllLocation->Copy(hostFxrLocation.c_str())))
|
||||||
{
|
{
|
||||||
goto Finished;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!UTILITY::CheckIfFileExists(struDllPath.QueryStr()))
|
return ParseHostfxrArguments(
|
||||||
{
|
arguments.c_str(),
|
||||||
// Treat access issue as File not found
|
|
||||||
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(hr = struArguments.Copy(struDllPath)) ||
|
|
||||||
FAILED(hr = struArguments.Append(L" ")) ||
|
|
||||||
FAILED(hr = struArguments.Append(pcwzArguments)))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(hr = ParseHostfxrArguments(
|
|
||||||
struArguments.QueryStr(),
|
|
||||||
pwzExeAbsolutePath,
|
pwzExeAbsolutePath,
|
||||||
pcwzApplicationPhysicalPath,
|
pcwzApplicationPhysicalPath,
|
||||||
hEventLog,
|
hEventLog,
|
||||||
pdwArgCount,
|
pdwArgCount,
|
||||||
ppwzArgv)))
|
ppwzArgv);
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
Finished:
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
HOSTFXR_UTILITY::IsDotnetExecutable(STRU *struExecutablePath)
|
HOSTFXR_UTILITY::IsDotnetExecutable(const std::experimental::filesystem::path & dotnetPath)
|
||||||
{
|
{
|
||||||
if (struExecutablePath == NULL)
|
auto name = dotnetPath.filename();
|
||||||
{
|
name.replace_extension("");
|
||||||
return FALSE;
|
return _wcsnicmp(name.c_str(), L"dotnet", 6) == 0;
|
||||||
}
|
|
||||||
return struExecutablePath->EndsWith(L"dotnet.exe") || struExecutablePath->EndsWith(L"dotnet");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
|
|
@ -165,70 +101,58 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
STRU struSystemPathVariable;
|
|
||||||
STRU struAbsolutePathToHostFxr;
|
|
||||||
STRU struAbsolutePathToDotnet;
|
|
||||||
STRU struEventMsg;
|
|
||||||
STACK_STRU(struExpandedProcessPath, MAX_PATH);
|
|
||||||
STACK_STRU(struExpandedArguments, MAX_PATH);
|
|
||||||
|
|
||||||
// Copy and Expand the processPath and Arguments.
|
const fs::path applicationPhysicalPath = pcwzApplicationPhysicalPath;
|
||||||
if (FAILED(hr = struExpandedProcessPath.CopyAndExpandEnvironmentStrings(pcwzProcessPath))
|
fs::path processPath = ExpandEnvironmentVariables(pcwzProcessPath);
|
||||||
|| FAILED(hr = struExpandedArguments.CopyAndExpandEnvironmentStrings(pcwzArguments)))
|
std::wstring arguments = ExpandEnvironmentVariables(pcwzArguments);
|
||||||
|
|
||||||
|
if (processPath.is_relative())
|
||||||
{
|
{
|
||||||
goto Finished;
|
processPath = applicationPhysicalPath / processPath;
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the process path an absolute path to our current application directory.
|
|
||||||
// If the path is already an absolute path, it will be unchanged.
|
|
||||||
hr = UTILITY::ConvertPathToFullPath(
|
|
||||||
struExpandedProcessPath.QueryStr(),
|
|
||||||
pcwzApplicationPhysicalPath,
|
|
||||||
&struAbsolutePathToDotnet
|
|
||||||
);
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the absolute path is to dotnet or not.
|
// Check if the absolute path is to dotnet or not.
|
||||||
if (HOSTFXR_UTILITY::IsDotnetExecutable(&struAbsolutePathToDotnet))
|
if (IsDotnetExecutable(processPath))
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// The processPath ends with dotnet.exe or dotnet
|
// The processPath ends with dotnet.exe or dotnet
|
||||||
// like: C:\Program Files\dotnet\dotnet.exe, C:\Program Files\dotnet\dotnet, dotnet.exe, or dotnet.
|
// like: C:\Program Files\dotnet\dotnet.exe, C:\Program Files\dotnet\dotnet, dotnet.exe, or dotnet.
|
||||||
// Get the absolute path to dotnet. If the path is already an absolute path, it will return that path
|
// Get the absolute path to dotnet. If the path is already an absolute path, it will return that path
|
||||||
//
|
//
|
||||||
if (FAILED(hr = HOSTFXR_UTILITY::GetAbsolutePathToDotnet(&struAbsolutePathToDotnet))) // Make sure to append the dotnet.exe path correctly here (pass in regular path)?
|
// Make sure to append the dotnet.exe path correctly here (pass in regular path)?
|
||||||
|
auto fullProcessPath = GetAbsolutePathToDotnet(processPath);
|
||||||
|
if (!fullProcessPath.has_value())
|
||||||
{
|
{
|
||||||
goto Finished;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr = GetAbsolutePathToHostFxr(&struAbsolutePathToDotnet, hEventLog, &struAbsolutePathToHostFxr)))
|
processPath = fullProcessPath.value();
|
||||||
|
|
||||||
|
auto hostFxrPath = GetAbsolutePathToHostFxr(processPath, hEventLog);
|
||||||
|
if (!hostFxrPath.has_value())
|
||||||
{
|
{
|
||||||
goto Finished;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr = HOSTFXR_UTILITY::ParseHostfxrArguments(
|
if (FAILED(hr = HOSTFXR_UTILITY::ParseHostfxrArguments(
|
||||||
struExpandedArguments.QueryStr(),
|
arguments.c_str(),
|
||||||
struAbsolutePathToDotnet.QueryStr(),
|
processPath.c_str(),
|
||||||
pcwzApplicationPhysicalPath,
|
pcwzApplicationPhysicalPath,
|
||||||
hEventLog,
|
hEventLog,
|
||||||
pdwArgCount,
|
pdwArgCount,
|
||||||
pbstrArgv)))
|
pbstrArgv)))
|
||||||
{
|
{
|
||||||
goto Finished;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr = pStruHostFxrDllLocation->Copy(struAbsolutePathToHostFxr)))
|
if (FAILED(hr = pStruHostFxrDllLocation->Copy(hostFxrPath->c_str())))
|
||||||
{
|
{
|
||||||
goto Finished;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr = pStruExeAbsolutePath->Copy(struAbsolutePathToDotnet)))
|
if (FAILED(hr = pStruExeAbsolutePath->Copy(processPath.c_str())))
|
||||||
{
|
{
|
||||||
goto Finished;
|
return hr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -238,25 +162,25 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
|
||||||
// like: C:\test\MyApp.Exe or MyApp.Exe
|
// like: C:\test\MyApp.Exe or MyApp.Exe
|
||||||
// Check if the file exists, and if it does, get the parameters for a standalone application
|
// Check if the file exists, and if it does, get the parameters for a standalone application
|
||||||
//
|
//
|
||||||
if (UTILITY::CheckIfFileExists(struAbsolutePathToDotnet.QueryStr()))
|
if (is_regular_file(processPath))
|
||||||
{
|
{
|
||||||
hr = HOSTFXR_UTILITY::GetStandaloneHostfxrParameters(
|
if (FAILED(hr = GetStandaloneHostfxrParameters(
|
||||||
struAbsolutePathToDotnet.QueryStr(),
|
processPath.c_str(),
|
||||||
pcwzApplicationPhysicalPath,
|
pcwzApplicationPhysicalPath,
|
||||||
struExpandedArguments.QueryStr(),
|
arguments.c_str(),
|
||||||
hEventLog,
|
hEventLog,
|
||||||
pStruHostFxrDllLocation,
|
pStruHostFxrDllLocation,
|
||||||
pdwArgCount,
|
pdwArgCount,
|
||||||
pbstrArgv);
|
pbstrArgv)))
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
{
|
||||||
goto Finished;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr = pStruExeAbsolutePath->Copy(struAbsolutePathToDotnet)))
|
if (FAILED(hr = pStruExeAbsolutePath->Copy(processPath.c_str())))
|
||||||
{
|
{
|
||||||
goto Finished;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -264,19 +188,13 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
|
||||||
// If the processPath file does not exist and it doesn't include dotnet.exe or dotnet
|
// If the processPath file does not exist and it doesn't include dotnet.exe or dotnet
|
||||||
// then it is an invalid argument.
|
// then it is an invalid argument.
|
||||||
//
|
//
|
||||||
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);;
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||||
UTILITY::LogEventF(hEventLog,
|
UTILITY::LogEventF(hEventLog, ASPNETCORE_EVENT_INVALID_PROCESS_PATH_LEVEL, ASPNETCORE_EVENT_INVALID_PROCESS_PATH, ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG, processPath.c_str(), hr);
|
||||||
EVENTLOG_ERROR_TYPE,
|
return hr;
|
||||||
ASPNETCORE_EVENT_GENERAL_ERROR_MSG,
|
|
||||||
ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG,
|
|
||||||
struExpandedProcessPath.QueryStr(),
|
|
||||||
hr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Finished:
|
return S_OK;
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -394,163 +312,82 @@ Finished:
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
std::optional<fs::path>
|
||||||
HOSTFXR_UTILITY::GetAbsolutePathToDotnet(
|
HOSTFXR_UTILITY::GetAbsolutePathToDotnet(
|
||||||
_Inout_ STRU* pStruAbsolutePathToDotnet
|
const fs::path & requestedPath
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// If we are given an absolute path to dotnet.exe, we are done
|
// If we are given an absolute path to dotnet.exe, we are done
|
||||||
//
|
//
|
||||||
if (UTILITY::CheckIfFileExists(pStruAbsolutePathToDotnet->QueryStr()))
|
if (is_regular_file(requestedPath))
|
||||||
{
|
{
|
||||||
goto Finished;
|
return std::make_optional(requestedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
auto pathWithExe = requestedPath;
|
||||||
// If the path was C:\Program Files\dotnet\dotnet
|
pathWithExe.concat(L".exe");
|
||||||
// We need to try appending .exe and check if the file exists too.
|
|
||||||
//
|
|
||||||
if (FAILED(hr = pStruAbsolutePathToDotnet->Append(L".exe")))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UTILITY::CheckIfFileExists(pStruAbsolutePathToDotnet->QueryStr()))
|
if (is_regular_file(pathWithExe))
|
||||||
{
|
{
|
||||||
goto Finished;
|
return std::make_optional(pathWithExe);
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point, we are calling where.exe to find dotnet.
|
// At this point, we are calling where.exe to find dotnet.
|
||||||
// If we encounter any failures, try getting dotnet.exe from the
|
// If we encounter any failures, try getting dotnet.exe from the
|
||||||
// backup location.
|
// backup location.
|
||||||
if (!InvokeWhereToFindDotnet(pStruAbsolutePathToDotnet))
|
// Only do it if no path is specified
|
||||||
|
if (!requestedPath.has_parent_path())
|
||||||
{
|
{
|
||||||
hr = GetAbsolutePathToDotnetFromProgramFiles(pStruAbsolutePathToDotnet);
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Finished:
|
const auto dotnetViaWhere = InvokeWhereToFindDotnet();
|
||||||
|
if (dotnetViaWhere.has_value())
|
||||||
|
{
|
||||||
|
return dotnetViaWhere;
|
||||||
|
}
|
||||||
|
|
||||||
return hr;
|
return GetAbsolutePathToDotnetFromProgramFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
std::optional<fs::path>
|
||||||
HOSTFXR_UTILITY::GetAbsolutePathToHostFxr(
|
HOSTFXR_UTILITY::GetAbsolutePathToHostFxr(
|
||||||
STRU* pStruAbsolutePathToDotnet,
|
const fs::path & dotnetPath,
|
||||||
HANDLE hEventLog,
|
HANDLE hEventLog
|
||||||
STRU* pStruAbsolutePathToHostfxr
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
std::vector<std::wstring> versionFolders;
|
||||||
STRU struHostFxrPath;
|
const auto hostFxrBase = dotnetPath.parent_path() / "host" / "fxr";
|
||||||
STRU struHostFxrSearchExpression;
|
|
||||||
STRU struHighestDotnetVersion;
|
|
||||||
STRU struEventMsg;
|
|
||||||
std::vector<std::wstring> vVersionFolders;
|
|
||||||
DWORD dwPosition = 0;
|
|
||||||
|
|
||||||
if (FAILED(hr = struHostFxrPath.Copy(pStruAbsolutePathToDotnet)))
|
if (!is_directory(hostFxrBase))
|
||||||
{
|
{
|
||||||
goto Finished;
|
EVENTLOG(hEventLog, HOSTFXR_DIRECTORY_NOT_FOUND, hostFxrBase.c_str(), HRESULT_FROM_WIN32(ERROR_BAD_ENVIRONMENT));
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
dwPosition = struHostFxrPath.LastIndexOf(L'\\', 0);
|
auto searchPattern = std::wstring(hostFxrBase) + L"\\*";
|
||||||
if (dwPosition == -1)
|
FindDotNetFolders(searchPattern.c_str(), versionFolders);
|
||||||
|
|
||||||
|
if (versionFolders.empty())
|
||||||
{
|
{
|
||||||
hr = E_FAIL;
|
EVENTLOG(hEventLog, HOSTFXR_DIRECTORY_NOT_FOUND, hostFxrBase.c_str(), HRESULT_FROM_WIN32(ERROR_BAD_ENVIRONMENT));
|
||||||
goto Finished;
|
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
struHostFxrPath.QueryStr()[dwPosition] = L'\0';
|
const auto highestVersion = FindHighestDotNetVersion(versionFolders);
|
||||||
|
const auto hostFxrPath = hostFxrBase / highestVersion / "hostfxr.dll";
|
||||||
|
|
||||||
if (FAILED(hr = struHostFxrPath.SyncWithBuffer()) ||
|
if (!is_regular_file(hostFxrPath))
|
||||||
FAILED(hr = struHostFxrPath.Append(L"\\")))
|
|
||||||
{
|
{
|
||||||
goto Finished;
|
EVENTLOG(hEventLog, HOSTFXR_DLL_NOT_FOUND, hostFxrPath.c_str(), HRESULT_FROM_WIN32(ERROR_FILE_INVALID));
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = struHostFxrPath.Append(L"host\\fxr");
|
return std::make_optional(hostFxrPath);
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UTILITY::DirectoryExists(&struHostFxrPath))
|
|
||||||
{
|
|
||||||
hr = ERROR_BAD_ENVIRONMENT;
|
|
||||||
UTILITY::LogEventF(hEventLog,
|
|
||||||
EVENTLOG_ERROR_TYPE,
|
|
||||||
ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND,
|
|
||||||
struEventMsg.QueryStr(),
|
|
||||||
ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND_MSG,
|
|
||||||
struHostFxrPath.QueryStr(),
|
|
||||||
hr);
|
|
||||||
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.
|
|
||||||
HOSTFXR_UTILITY::FindDotNetFolders(struHostFxrSearchExpression.QueryStr(), &vVersionFolders);
|
|
||||||
|
|
||||||
if (vVersionFolders.size() == 0)
|
|
||||||
{
|
|
||||||
hr = HRESULT_FROM_WIN32(ERROR_BAD_ENVIRONMENT);
|
|
||||||
UTILITY::LogEventF(hEventLog,
|
|
||||||
EVENTLOG_ERROR_TYPE,
|
|
||||||
ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND,
|
|
||||||
ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND_MSG,
|
|
||||||
struHostFxrPath.QueryStr(),
|
|
||||||
hr);
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = 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()))
|
|
||||||
{
|
|
||||||
// ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND_MSG
|
|
||||||
hr = HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
|
|
||||||
UTILITY::LogEventF(hEventLog,
|
|
||||||
EVENTLOG_ERROR_TYPE,
|
|
||||||
ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND,
|
|
||||||
ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND_MSG,
|
|
||||||
struHostFxrPath.QueryStr(),
|
|
||||||
hr);
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(hr = pStruAbsolutePathToHostfxr->Copy(struHostFxrPath)))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
Finished:
|
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -559,10 +396,8 @@ Finished:
|
||||||
// worker process bitness.
|
// worker process bitness.
|
||||||
// Returns true if a valid dotnet was found, else false.
|
// Returns true if a valid dotnet was found, else false.
|
||||||
//
|
//
|
||||||
BOOL
|
std::optional<fs::path>
|
||||||
HOSTFXR_UTILITY::InvokeWhereToFindDotnet(
|
HOSTFXR_UTILITY::InvokeWhereToFindDotnet()
|
||||||
_Inout_ STRU* pStruAbsolutePathToDotnet
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
// Arguments to call where.exe
|
// Arguments to call where.exe
|
||||||
|
|
@ -586,16 +421,13 @@ HOSTFXR_UTILITY::InvokeWhereToFindDotnet(
|
||||||
INT prevIndex = 0;
|
INT prevIndex = 0;
|
||||||
BOOL fProcessCreationResult = FALSE;
|
BOOL fProcessCreationResult = FALSE;
|
||||||
BOOL fResult = FALSE;
|
BOOL fResult = FALSE;
|
||||||
|
std::optional<fs::path> result;
|
||||||
|
|
||||||
// Set the security attributes for the read/write pipe
|
// Set the security attributes for the read/write pipe
|
||||||
securityAttributes.nLength = sizeof(securityAttributes);
|
securityAttributes.nLength = sizeof(securityAttributes);
|
||||||
securityAttributes.lpSecurityDescriptor = NULL;
|
securityAttributes.lpSecurityDescriptor = NULL;
|
||||||
securityAttributes.bInheritHandle = TRUE;
|
securityAttributes.bInheritHandle = TRUE;
|
||||||
|
|
||||||
// Reset the path to dotnet as we will be using whether the string is
|
|
||||||
// empty or not as state
|
|
||||||
pStruAbsolutePathToDotnet->Reset();
|
|
||||||
|
|
||||||
// Create a read/write pipe that will be used for reading the result of where.exe
|
// Create a read/write pipe that will be used for reading the result of where.exe
|
||||||
if (!CreatePipe(&hStdOutReadPipe, &hStdOutWritePipe, &securityAttributes, 0))
|
if (!CreatePipe(&hStdOutReadPipe, &hStdOutWritePipe, &securityAttributes, 0))
|
||||||
{
|
{
|
||||||
|
|
@ -736,10 +568,7 @@ HOSTFXR_UTILITY::InvokeWhereToFindDotnet(
|
||||||
fIsCurrentProcess64Bit == (dwBinaryType == SCS_64BIT_BINARY))
|
fIsCurrentProcess64Bit == (dwBinaryType == SCS_64BIT_BINARY))
|
||||||
{
|
{
|
||||||
// The bitness of dotnet matched with the current worker process bitness.
|
// The bitness of dotnet matched with the current worker process bitness.
|
||||||
if (FAILED(hr = pStruAbsolutePathToDotnet->Copy(struDotnetSubstring)))
|
result = std::make_optional(struDotnetSubstring.QueryStr());
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
fResult = TRUE;
|
fResult = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -768,71 +597,21 @@ Finished:
|
||||||
SysFreeString(pwzDotnetName);
|
SysFreeString(pwzDotnetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fResult;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<fs::path>
|
||||||
HRESULT
|
HOSTFXR_UTILITY::GetAbsolutePathToDotnetFromProgramFiles()
|
||||||
HOSTFXR_UTILITY::GetAbsolutePathToDotnetFromProgramFiles(
|
|
||||||
_Inout_ STRU* pStruAbsolutePathToDotnet
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
const auto programFilesDotnet = fs::path(ExpandEnvironmentVariables(L"%ProgramFiles%")) / "dotnet" / "dotnet.exe";
|
||||||
BOOL fFound = FALSE;
|
return is_regular_file(programFilesDotnet) ? std::make_optional(programFilesDotnet) : std::nullopt;
|
||||||
DWORD dwNumBytesRead = 0;
|
|
||||||
DWORD dwPathSize = MAX_PATH;
|
|
||||||
STRU struDotnetSubstring;
|
|
||||||
|
|
||||||
while (!fFound)
|
|
||||||
{
|
|
||||||
if (FAILED(hr = struDotnetSubstring.Resize(dwPathSize)))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
dwNumBytesRead = GetEnvironmentVariable(L"ProgramFiles", struDotnetSubstring.QueryStr(), dwPathSize);
|
|
||||||
if (dwNumBytesRead == 0)
|
|
||||||
{
|
|
||||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
else if (dwNumBytesRead >= dwPathSize)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// The path to ProgramFiles should never be this long, but resize and try again.
|
|
||||||
dwPathSize *= 2 + 30; // for dotnet substring
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (FAILED(hr = struDotnetSubstring.SyncWithBuffer()) ||
|
|
||||||
FAILED(hr = struDotnetSubstring.Append(L"\\dotnet\\dotnet.exe")))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
if (!UTILITY::CheckIfFileExists(struDotnetSubstring.QueryStr()))
|
|
||||||
{
|
|
||||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
if (FAILED(hr = pStruAbsolutePathToDotnet->Copy(struDotnetSubstring)))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
fFound = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Finished:
|
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
std::wstring
|
||||||
HOSTFXR_UTILITY::FindHighestDotNetVersion(
|
HOSTFXR_UTILITY::FindHighestDotNetVersion(
|
||||||
_In_ std::vector<std::wstring> vFolders,
|
_In_ std::vector<std::wstring> & vFolders
|
||||||
_Out_ STRU *pstrResult
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
|
||||||
fx_ver_t max_ver(-1, -1, -1);
|
fx_ver_t max_ver(-1, -1, -1);
|
||||||
for (const auto& dir : vFolders)
|
for (const auto& dir : vFolders)
|
||||||
{
|
{
|
||||||
|
|
@ -844,16 +623,13 @@ HOSTFXR_UTILITY::FindHighestDotNetVersion(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = pstrResult->Copy(max_ver.as_str().c_str());
|
return max_ver.as_str();
|
||||||
|
|
||||||
// we check FAILED(hr) outside of function
|
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
HOSTFXR_UTILITY::FindDotNetFolders(
|
HOSTFXR_UTILITY::FindDotNetFolders(
|
||||||
_In_ PCWSTR pszPath,
|
_In_ PCWSTR pszPath,
|
||||||
_Out_ std::vector<std::wstring> *pvFolders
|
_Out_ std::vector<std::wstring> & pvFolders
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
HANDLE handle = NULL;
|
HANDLE handle = NULL;
|
||||||
|
|
@ -868,8 +644,34 @@ HOSTFXR_UTILITY::FindDotNetFolders(
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
std::wstring folder(data.cFileName);
|
std::wstring folder(data.cFileName);
|
||||||
pvFolders->push_back(folder);
|
pvFolders.push_back(folder);
|
||||||
} while (FindNextFileW(handle, &data));
|
} while (FindNextFileW(handle, &data));
|
||||||
|
|
||||||
FindClose(handle);
|
FindClose(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::wstring
|
||||||
|
HOSTFXR_UTILITY::ExpandEnvironmentVariables(const std::wstring & str)
|
||||||
|
{
|
||||||
|
DWORD requestedSize = ExpandEnvironmentStringsW(str.c_str(), nullptr, 0);
|
||||||
|
if (requestedSize == 0)
|
||||||
|
{
|
||||||
|
throw std::system_error(GetLastError(), std::system_category(), "ExpandEnvironmentVariables");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring expandedStr;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
expandedStr.resize(requestedSize);
|
||||||
|
requestedSize = ExpandEnvironmentStringsW(str.c_str(), &expandedStr[0], requestedSize);
|
||||||
|
if (requestedSize == 0)
|
||||||
|
{
|
||||||
|
throw std::system_error(GetLastError(), std::system_category(), "ExpandEnvironmentVariables");
|
||||||
|
}
|
||||||
|
} while (expandedStr.size() != requestedSize);
|
||||||
|
|
||||||
|
// trim null character as ExpandEnvironmentStringsW returns size including null character
|
||||||
|
expandedStr.resize(requestedSize - 1);
|
||||||
|
|
||||||
|
return expandedStr;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <experimental/filesystem>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
typedef INT(*hostfxr_get_native_search_directories_fn) (CONST INT argc, CONST PCWSTR* argv, PWSTR buffer, DWORD buffer_size, DWORD* required_buffer_size);
|
typedef INT(*hostfxr_get_native_search_directories_fn) (CONST INT argc, CONST PCWSTR* argv, PWSTR buffer, DWORD buffer_size, DWORD* required_buffer_size);
|
||||||
typedef INT(*hostfxr_main_fn) (CONST DWORD argc, CONST PCWSTR argv[]);
|
typedef INT(*hostfxr_main_fn) (CONST DWORD argc, CONST PCWSTR argv[]);
|
||||||
|
|
@ -42,7 +44,7 @@ public:
|
||||||
static
|
static
|
||||||
BOOL
|
BOOL
|
||||||
IsDotnetExecutable(
|
IsDotnetExecutable(
|
||||||
STRU* struExecutablePath
|
_In_ const std::experimental::filesystem::path & dotnetPath
|
||||||
);
|
);
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|
@ -58,47 +60,41 @@ public:
|
||||||
_Out_ BSTR **ppwzArgv
|
_Out_ BSTR **ppwzArgv
|
||||||
);
|
);
|
||||||
|
|
||||||
static
|
|
||||||
HRESULT
|
|
||||||
GetAbsolutePathToDotnet(
|
|
||||||
STRU* pStruAbsolutePathToDotnet
|
|
||||||
);
|
|
||||||
|
|
||||||
static
|
|
||||||
HRESULT
|
|
||||||
GetAbsolutePathToHostFxr(
|
|
||||||
_In_ STRU* pStruAbsolutePathToDotnet,
|
|
||||||
_In_ HANDLE hEventLog,
|
|
||||||
_Out_ STRU* pStruAbsolutePathToHostfxr
|
|
||||||
);
|
|
||||||
|
|
||||||
static
|
|
||||||
BOOL
|
|
||||||
InvokeWhereToFindDotnet(
|
|
||||||
_Inout_ STRU* pStruAbsolutePathToDotnet
|
|
||||||
);
|
|
||||||
|
|
||||||
static
|
|
||||||
HRESULT
|
|
||||||
GetAbsolutePathToDotnetFromProgramFiles(
|
|
||||||
_Inout_ STRU* pStruAbsolutePathToDotnet
|
|
||||||
);
|
|
||||||
|
|
||||||
static
|
|
||||||
HRESULT
|
|
||||||
FindHighestDotNetVersion(
|
|
||||||
_In_ std::vector<std::wstring> vFolders,
|
|
||||||
_Out_ STRU *pstrResult
|
|
||||||
);
|
|
||||||
|
|
||||||
static
|
static
|
||||||
VOID
|
VOID
|
||||||
FindDotNetFolders(
|
FindDotNetFolders(
|
||||||
_In_ PCWSTR pszPath,
|
_In_ PCWSTR pszPath,
|
||||||
_Out_ std::vector<std::wstring> *pvFolders
|
_Out_ std::vector<std::wstring> & pvFolders
|
||||||
);
|
);
|
||||||
|
|
||||||
HOSTFXR_UTILITY();
|
static
|
||||||
~HOSTFXR_UTILITY();
|
std::wstring
|
||||||
|
FindHighestDotNetVersion(
|
||||||
|
_In_ std::vector<std::wstring> & vFolders
|
||||||
|
);
|
||||||
|
|
||||||
|
static
|
||||||
|
std::optional<std::experimental::filesystem::path>
|
||||||
|
GetAbsolutePathToHostFxr(
|
||||||
|
_In_ const std::experimental::filesystem::path & dotnetPath,
|
||||||
|
_In_ HANDLE hEventLog
|
||||||
|
);
|
||||||
|
|
||||||
|
static
|
||||||
|
std::optional<std::experimental::filesystem::path>
|
||||||
|
GetAbsolutePathToDotnetFromProgramFiles();
|
||||||
|
|
||||||
|
static
|
||||||
|
std::optional<std::experimental::filesystem::path>
|
||||||
|
InvokeWhereToFindDotnet();
|
||||||
|
|
||||||
|
static
|
||||||
|
std::optional<std::experimental::filesystem::path>
|
||||||
|
GetAbsolutePathToDotnet(
|
||||||
|
_In_ const std::experimental::filesystem::path & requestedPath
|
||||||
|
);
|
||||||
|
|
||||||
|
static
|
||||||
|
std::wstring ExpandEnvironmentVariables(const std::wstring & str);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ HRESULT HOSTFXR_OPTIONS::Create(
|
||||||
goto Finished;
|
goto Finished;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (HOSTFXR_UTILITY::IsDotnetExecutable(&struExeLocation))
|
else if (HOSTFXR_UTILITY::IsDotnetExecutable(struExeLocation.QueryStr()))
|
||||||
{
|
{
|
||||||
if (FAILED(hr = HOSTFXR_UTILITY::ParseHostfxrArguments(
|
if (FAILED(hr = HOSTFXR_UTILITY::ParseHostfxrArguments(
|
||||||
pcwzArguments,
|
pcwzArguments,
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,17 @@
|
||||||
#define ASPNETCORE_EVENT_RECYCLE_CONFIGURATION_MSG L"Application '%s' was recycled due to configuration change"
|
#define ASPNETCORE_EVENT_RECYCLE_CONFIGURATION_MSG L"Application '%s' was recycled due to configuration change"
|
||||||
#define ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG L"Failed to recycle application due to a configuration change at '%s'. Recycling worker process."
|
#define ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG L"Failed to recycle application due to a configuration change at '%s'. Recycling worker process."
|
||||||
#define ASPNETCORE_EVENT_MODULE_DISABLED_MSG L"AspNetCore Module is disabled"
|
#define ASPNETCORE_EVENT_MODULE_DISABLED_MSG L"AspNetCore Module is disabled"
|
||||||
|
#define ASPNETCORE_EVENT_INPROCESS_FULL_FRAMEWORK_APP_LEVEL EVENTLOG_ERROR_TYPE
|
||||||
#define ASPNETCORE_EVENT_INPROCESS_FULL_FRAMEWORK_APP_MSG L"Application '%s' was compiled for .NET Framework. Please compile for .NET core to run the inprocess application or change the process mode to out of process. ErrorCode = '0x%x'."
|
#define ASPNETCORE_EVENT_INPROCESS_FULL_FRAMEWORK_APP_MSG L"Application '%s' was compiled for .NET Framework. Please compile for .NET core to run the inprocess application or change the process mode to out of process. ErrorCode = '0x%x'."
|
||||||
#define ASPNETCORE_EVENT_PORTABLE_APP_DOTNET_MISSING_MSG L"Could not find dotnet.exe on the system PATH environment variable for portable application '%s'. Check that a valid path to dotnet is on the PATH and the bitness of dotnet matches the bitness of the IIS worker process. ErrorCode = '0x%x'."
|
#define ASPNETCORE_EVENT_PORTABLE_APP_DOTNET_MISSING_MSG L"Could not find dotnet.exe on the system PATH environment variable for portable application '%s'. Check that a valid path to dotnet is on the PATH and the bitness of dotnet matches the bitness of the IIS worker process. ErrorCode = '0x%x'."
|
||||||
|
#define ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND_LEVEL EVENTLOG_ERROR_TYPE
|
||||||
#define ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND_MSG L"Could not find the hostfxr directory '%s' in the dotnet directory. ErrorCode = '0x%x'."
|
#define ASPNETCORE_EVENT_HOSTFXR_DIRECTORY_NOT_FOUND_MSG L"Could not find the hostfxr directory '%s' in the dotnet directory. ErrorCode = '0x%x'."
|
||||||
|
#define ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND_LEVEL EVENTLOG_ERROR_TYPE
|
||||||
#define ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND_MSG L"Could not find hostfxr.dll in '%s'. ErrorCode = '0x%x'."
|
#define ASPNETCORE_EVENT_HOSTFXR_DLL_NOT_FOUND_MSG L"Could not find hostfxr.dll in '%s'. ErrorCode = '0x%x'."
|
||||||
|
#define ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND_LEVEL EVENTLOG_ERROR_TYPE
|
||||||
#define ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND_MSG L"Could not find application executable in '%s'. ErrorCode = '0x%x'."
|
#define ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND_MSG L"Could not find application executable in '%s'. ErrorCode = '0x%x'."
|
||||||
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, ErrorCode = '0x%x. Please check the stderr logs for more information."
|
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, ErrorCode = '0x%x. Please check the stderr logs for more information."
|
||||||
|
#define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_LEVEL EVENTLOG_ERROR_TYPE
|
||||||
#define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG L"Invalid or unknown processPath provided in web.config: processPath = %s, ErrorCode = '0x%x'."
|
#define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG L"Invalid or unknown processPath provided in web.config: processPath = %s, ErrorCode = '0x%x'."
|
||||||
#define ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application."
|
#define ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application."
|
||||||
#define ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for out-of-process application. Please confirm the assembly is installed correctly for IIS or IISExpress."
|
#define ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for out-of-process application. Please confirm the assembly is installed correctly for IIS or IISExpress."
|
||||||
|
|
|
||||||
|
|
@ -38,5 +38,6 @@
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "aspnetcore_msg.h"
|
#include "aspnetcore_msg.h"
|
||||||
#include "hostfxr_utility.h"
|
#include "hostfxr_utility.h"
|
||||||
|
#include "EventLog.h"
|
||||||
#include "hostfxroptions.h"
|
#include "hostfxroptions.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include "debugutil.h"
|
||||||
|
|
||||||
// static
|
// static
|
||||||
HRESULT
|
HRESULT
|
||||||
|
|
@ -569,9 +570,12 @@ UTILITY::LogEvent(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwEventInfoType == EVENTLOG_ERROR_TYPE)
|
STACK_STRA(converted, 256);
|
||||||
|
if (converted.CopyW(pstrMsg))
|
||||||
{
|
{
|
||||||
fwprintf(stderr, L"ERROR: %s\n", pstrMsg);
|
DebugPrintf(
|
||||||
|
dwEventInfoType == EVENTLOG_ERROR_TYPE ? ASPNETCORE_DEBUG_FLAG_ERROR : ASPNETCORE_DEBUG_FLAG_INFO,
|
||||||
|
"Event Log: %s", converted.QueryStr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,6 @@
|
||||||
#include "debugutil.h"
|
#include "debugutil.h"
|
||||||
|
|
||||||
// Common lib
|
// Common lib
|
||||||
#include "hostfxr_utility.h"
|
|
||||||
#include "requesthandler.h"
|
#include "requesthandler.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,6 @@ TEST(ParseHostFxrArguments, ProvideNoArgs_InvalidArgs)
|
||||||
TEST(GetAbsolutePathToDotnetFromProgramFiles, BackupWorks)
|
TEST(GetAbsolutePathToDotnetFromProgramFiles, BackupWorks)
|
||||||
{
|
{
|
||||||
STRU struAbsolutePathToDotnet;
|
STRU struAbsolutePathToDotnet;
|
||||||
HRESULT hr = S_OK;
|
|
||||||
BOOL fDotnetInProgramFiles;
|
BOOL fDotnetInProgramFiles;
|
||||||
BOOL is64Bit;
|
BOOL is64Bit;
|
||||||
BOOL fIsWow64 = FALSE;
|
BOOL fIsWow64 = FALSE;
|
||||||
|
|
@ -109,15 +108,14 @@ TEST(GetAbsolutePathToDotnetFromProgramFiles, BackupWorks)
|
||||||
fDotnetInProgramFiles = UTILITY::CheckIfFileExists(L"C:/Program Files (x86)/dotnet/dotnet.exe");
|
fDotnetInProgramFiles = UTILITY::CheckIfFileExists(L"C:/Program Files (x86)/dotnet/dotnet.exe");
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = HOSTFXR_UTILITY::GetAbsolutePathToDotnetFromProgramFiles(&struAbsolutePathToDotnet);
|
auto dotnetPath = HOSTFXR_UTILITY::GetAbsolutePathToDotnetFromProgramFiles();
|
||||||
if (fDotnetInProgramFiles)
|
if (fDotnetInProgramFiles)
|
||||||
{
|
{
|
||||||
EXPECT_EQ(hr, S_OK);
|
EXPECT_TRUE(dotnetPath.has_value());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EXPECT_NE(hr, S_OK);
|
EXPECT_FALSE(dotnetPath.has_value());
|
||||||
EXPECT_TRUE(struAbsolutePathToDotnet.IsEmpty());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,5 +136,5 @@ TEST(GetHostFxrArguments, InvalidParams)
|
||||||
&retVal, // arg count
|
&retVal, // arg count
|
||||||
&bstrArray); // args array.
|
&bstrArray); // args array.
|
||||||
|
|
||||||
EXPECT_EQ(E_INVALIDARG, hr);
|
EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,9 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
|
||||||
using IISIntegration.FunctionalTests.Utilities;
|
using IISIntegration.FunctionalTests.Utilities;
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
|
|
@ -18,30 +17,22 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
[SkipIfIISExpressSchemaMissingInProcess]
|
[SkipIfIISExpressSchemaMissingInProcess]
|
||||||
public class StartupTests : IISFunctionalTestBase
|
public class StartupTests : IISFunctionalTestBase
|
||||||
{
|
{
|
||||||
|
private readonly string _dotnetLocation = DotNetMuxer.MuxerPathOrDefault();
|
||||||
|
|
||||||
public StartupTests(ITestOutputHelper output) : base(output)
|
public StartupTests(ITestOutputHelper output) : base(output)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[ConditionalFact]
|
||||||
public async Task ExpandEnvironmentVariableInWebConfig()
|
public async Task ExpandEnvironmentVariableInWebConfig()
|
||||||
{
|
{
|
||||||
var dotnetLocation = DotNetMuxer.MuxerPathOrDefault();
|
|
||||||
var deploymentParameters = GetBaseDeploymentParameters();
|
|
||||||
|
|
||||||
// Point to dotnet installed in user profile.
|
// Point to dotnet installed in user profile.
|
||||||
deploymentParameters.EnvironmentVariables["DotnetPath"] = dotnetLocation;
|
await AssertStarts(
|
||||||
|
deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", "%DotnetPath%"),
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
deploymentParameters => deploymentParameters.EnvironmentVariables["DotnetPath"] = _dotnetLocation);
|
||||||
|
|
||||||
Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", "%DotnetPath%");
|
|
||||||
|
|
||||||
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
|
|
||||||
|
|
||||||
var responseText = await response.Content.ReadAsStringAsync();
|
|
||||||
Assert.Equal("Hello World", responseText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[ConditionalFact]
|
||||||
public async Task InvalidProcessPath_ExpectServerError()
|
public async Task InvalidProcessPath_ExpectServerError()
|
||||||
{
|
{
|
||||||
var dotnetLocation = "bogus";
|
var dotnetLocation = "bogus";
|
||||||
|
|
@ -60,6 +51,51 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
public async Task StartsWithDotnetLocationWithoutExe()
|
||||||
|
{
|
||||||
|
var dotnetLocationWithoutExtension = _dotnetLocation.Substring(0, _dotnetLocation.LastIndexOf("."));
|
||||||
|
|
||||||
|
await AssertStarts(
|
||||||
|
deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", dotnetLocationWithoutExtension));
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
public async Task StartsWithDotnetLocationUppercase()
|
||||||
|
{
|
||||||
|
var dotnetLocationWithoutExtension = _dotnetLocation.Substring(0, _dotnetLocation.LastIndexOf(".")).ToUpperInvariant();
|
||||||
|
|
||||||
|
await AssertStarts(
|
||||||
|
deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", dotnetLocationWithoutExtension));
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalTheory]
|
||||||
|
[InlineData("dotnet")]
|
||||||
|
[InlineData("dotnet.EXE")]
|
||||||
|
public async Task StartsWithDotnetOnThePath(string path)
|
||||||
|
{
|
||||||
|
await AssertStarts(
|
||||||
|
deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", path),
|
||||||
|
deploymentParameters => deploymentParameters.EnvironmentVariables["PATH"] = Path.GetDirectoryName(_dotnetLocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AssertStarts(Action<IISDeploymentResult> postDeploy, Action<DeploymentParameters> preDeploy = null)
|
||||||
|
{
|
||||||
|
var deploymentParameters = GetBaseDeploymentParameters();
|
||||||
|
|
||||||
|
preDeploy?.Invoke(deploymentParameters);
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
postDeploy?.Invoke(deploymentResult);
|
||||||
|
|
||||||
|
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
|
||||||
|
|
||||||
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.Equal("Hello World", responseText);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static TestMatrix TestVariants
|
public static TestMatrix TestVariants
|
||||||
=> TestMatrix.ForServers(ServerType.IISExpress)
|
=> TestMatrix.ForServers(ServerType.IISExpress)
|
||||||
.WithTfms(Tfm.NetCoreApp22)
|
.WithTfms(Tfm.NetCoreApp22)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue