diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.cpp index f291e227c7..b05a4d1a50 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.cpp @@ -30,7 +30,6 @@ void HostFxrErrorRedirector::HostFxrErrorRedirectorCallback(const WCHAR* message m_writeFunction->Append(std::wstring(message) + L"\r\n"); } - void HostFxr::Load() { HMODULE hModule; @@ -43,9 +42,12 @@ void HostFxr::Load(HMODULE moduleHandle) m_hHostFxrDll = moduleHandle; try { - m_hostfxr_main_fn = ModuleHelpers::GetKnownProcAddress(moduleHandle, "hostfxr_main"); m_hostfxr_get_native_search_directories_fn = ModuleHelpers::GetKnownProcAddress(moduleHandle, "hostfxr_get_native_search_directories"); m_corehost_set_error_writer_fn = ModuleHelpers::GetKnownProcAddress(moduleHandle, "hostfxr_set_error_writer", /* optional */ true); + m_hostfxr_initialize_for_dotnet_commandline_fn = ModuleHelpers::GetKnownProcAddress(moduleHandle, "hostfxr_initialize_for_dotnet_command_line", /* optional */ true); + m_hostfxr_set_runtime_property_value_fn = ModuleHelpers::GetKnownProcAddress(moduleHandle, "hostfxr_set_runtime_property_value", /* optional */ true); + m_hostfxr_run_app_fn = ModuleHelpers::GetKnownProcAddress(moduleHandle, "hostfxr_run_app", /* optional */ true); + m_hostfxr_close_fn = ModuleHelpers::GetKnownProcAddress(moduleHandle, "hostfxr_close", /* optional */ true); } catch (...) { @@ -59,7 +61,6 @@ void HostFxr::Load(HMODULE moduleHandle) } } - void HostFxr::Load(const std::wstring& location) { try @@ -87,7 +88,14 @@ void HostFxr::SetMain(hostfxr_main_fn hostfxr_main_fn) int HostFxr::Main(DWORD argc, const PCWSTR* argv) const noexcept(false) { - return m_hostfxr_main_fn(argc, argv); + if (m_host_context_handle != nullptr && m_hostfxr_run_app_fn != nullptr) + { + return m_hostfxr_run_app_fn(m_host_context_handle); + } + else + { + return m_hostfxr_main_fn(argc, argv); + } } int HostFxr::GetNativeSearchDirectories(INT argc, const PCWSTR* argv, PWSTR buffer, DWORD buffer_size, DWORD* required_buffer_size) const noexcept @@ -99,3 +107,62 @@ HostFxrErrorRedirector HostFxr::RedirectOutput(RedirectionOutput* writer) const { return HostFxrErrorRedirector(m_corehost_set_error_writer_fn, writer); } + +int HostFxr::InitializeForApp(int argc, PCWSTR* argv, const std::wstring& dotnetExe) const noexcept +{ + if (m_hostfxr_initialize_for_dotnet_commandline_fn == nullptr || m_hostfxr_main_fn != nullptr) + { + return 0; + } + + hostfxr_initialize_parameters params; + params.size = sizeof(hostfxr_initialize_parameters); + params.host_path = L""; + + // Transformation occurs here rather than hostfxr arguments as hostfxr_get_native_directories still needs + // exe as the first argument. + if (!dotnetExe.empty()) + { + // Portable application + // argv[0] = dotnet.exe + // argv[1] = app.dll + // argv[2] = rest of the args + + std::filesystem::path dotnetExePath(dotnetExe); + auto dotnetFolderPath = dotnetExePath.parent_path(); + params.dotnet_root = dotnetFolderPath.c_str(); + + RETURN_INT_IF_NOT_ZERO(m_hostfxr_initialize_for_dotnet_commandline_fn(argc - 1, &argv[1], ¶ms, &m_host_context_handle)); + } + else + { + // Standalone application + // argv[0] = app.exe + // argv[1] = rest of the args + params.dotnet_root = L""; + std::filesystem::path applicationPath(argv[0]); + applicationPath.replace_extension(".dll"); + argv[0] = applicationPath.c_str(); + + RETURN_INT_IF_NOT_ZERO(m_hostfxr_initialize_for_dotnet_commandline_fn(argc, argv, ¶ms, &m_host_context_handle)); + } + + return 0; +} + +int HostFxr::SetRuntimePropertyValue(PCWSTR name, PCWSTR value) const noexcept +{ + if (m_host_context_handle != nullptr && m_hostfxr_set_runtime_property_value_fn != nullptr) + { + return m_hostfxr_set_runtime_property_value_fn(m_host_context_handle, name, value); + } + return 0; +} + +void HostFxr::Close() const noexcept +{ + if (m_host_context_handle != nullptr && m_hostfxr_close_fn != nullptr) + { + m_hostfxr_close_fn(m_host_context_handle); + } +} diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h index 85cae5b1ba..ccd8fff54f 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h @@ -7,10 +7,26 @@ #include "exceptions.h" #include "RedirectionOutput.h" +struct hostfxr_initialize_parameters +{ + size_t size; + PCWSTR host_path; + PCWSTR dotnet_root; +}; + +#define DOTNETCORE_STARTUP_HOOK L"STARTUP_HOOKS" +#define DOTNETCORE_USE_ENTRYPOINT_FILTER L"USE_ENTRYPOINT_FILTER" +#define DOTNETCORE_STACK_SIZE L"DEFAULT_STACK_SIZE" +#define ASPNETCORE_STARTUP_ASSEMBLY L"Microsoft.AspNetCore.Server.IIS" + typedef INT(*hostfxr_get_native_search_directories_fn) (INT argc, CONST PCWSTR* argv, PWSTR buffer, DWORD buffer_size, DWORD* required_buffer_size); typedef INT(*hostfxr_main_fn) (DWORD argc, CONST PCWSTR argv[]); typedef void(*corehost_error_writer_fn) (const WCHAR* message); typedef corehost_error_writer_fn(*corehost_set_error_writer_fn) (corehost_error_writer_fn error_writer); +typedef int(*hostfxr_initialize_for_dotnet_runtime_fn)(int argc, const PCWSTR* argv, hostfxr_initialize_parameters* parameters, void* const* host_context_handle); +typedef int(*hostfxr_set_runtime_property_value_fn)(void* host_context_handle, PCWSTR name, PCWSTR value); +typedef int(*hostfxr_run_app_fn)(void* host_context_handle); +typedef int(*hostfxr_close_fn)(void* hostfxr_context_handle); struct ErrorContext { @@ -49,7 +65,8 @@ public: corehost_set_error_writer_fn corehost_set_error_writer_fn) noexcept : m_hostfxr_main_fn(hostfxr_main_fn), m_hostfxr_get_native_search_directories_fn(hostfxr_get_native_search_directories_fn), - m_corehost_set_error_writer_fn(corehost_set_error_writer_fn) + m_corehost_set_error_writer_fn(corehost_set_error_writer_fn), + m_host_context_handle(nullptr) { } @@ -66,10 +83,18 @@ public: int GetNativeSearchDirectories(INT argc, CONST PCWSTR* argv, PWSTR buffer, DWORD buffer_size, DWORD* required_buffer_size) const noexcept; HostFxrErrorRedirector RedirectOutput(RedirectionOutput* writer) const noexcept; + int SetRuntimePropertyValue(PCWSTR name, PCWSTR value) const noexcept; + int InitializeForApp(int argc, PCWSTR* argv, const std::wstring& m_dotnetExeKnownLocation) const noexcept; + void Close() const noexcept; private: HandleWrapper m_hHostFxrDll; hostfxr_main_fn m_hostfxr_main_fn; hostfxr_get_native_search_directories_fn m_hostfxr_get_native_search_directories_fn; + hostfxr_initialize_for_dotnet_runtime_fn m_hostfxr_initialize_for_dotnet_commandline_fn; + hostfxr_set_runtime_property_value_fn m_hostfxr_set_runtime_property_value_fn; + hostfxr_run_app_fn m_hostfxr_run_app_fn; corehost_set_error_writer_fn m_corehost_set_error_writer_fn; + hostfxr_close_fn m_hostfxr_close_fn; + void* m_host_context_handle; }; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/exceptions.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/exceptions.h index 7f3717ec7b..f4cd95c7f0 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/exceptions.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/exceptions.h @@ -89,6 +89,9 @@ #define SUCCEEDED_LOG(hr) SUCCEEDED(LOG_IF_FAILED(hr)) #define FAILED_LOG(hr) FAILED(LOG_IF_FAILED(hr)) +#define RETURN_INT_IF_NOT_ZERO(val) do { if ((val) != 0) { return val; }} while (0, 0) +#define RETURN_IF_NOT_ZERO(val) do { if ((val) != 0) { return; }} while (0, 0) + inline thread_local IHttpTraceContext* g_traceContext; __declspec(noinline) inline VOID TraceHRESULT(LOCATION_ARGUMENTS HRESULT hr) diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp index f261436690..cbc741959d 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp @@ -55,7 +55,7 @@ IN_PROCESS_APPLICATION::StopInternal(bool fServerInitiated) VOID IN_PROCESS_APPLICATION::StopClr() { - // This has the state lock around it. + // This has the state lock around it. LOG_INFO(L"Stopping CLR"); if (!m_blockManagedCallbacks) @@ -241,25 +241,19 @@ IN_PROCESS_APPLICATION::ExecuteApplication() LOG_INFOF(L"Setting current directory to %s", this->QueryApplicationPhysicalPath().c_str()); } - if (m_pConfig->QueryCallStartupHook()) + auto startupReturnCode = context->m_hostFxr.InitializeForApp(context->m_argc, context->m_argv.get(), m_dotnetExeKnownLocation); + if (startupReturnCode != 0) { - // Used to display developer exception page when there is an exception in main. - auto currentStartupHookEnv = Environment::GetEnvironmentVariableValue(DOTNETCORE_STARTUP_HOOK); - - if (currentStartupHookEnv.has_value()) - { - currentStartupHookEnv = currentStartupHookEnv.value() + L";" + ASPNETCORE_STARTUP_ASSEMBLY; - LOG_LAST_ERROR_IF(!SetEnvironmentVariable(DOTNETCORE_STARTUP_HOOK, currentStartupHookEnv.value().c_str())); - } - else - { - LOG_LAST_ERROR_IF(!SetEnvironmentVariable(DOTNETCORE_STARTUP_HOOK, ASPNETCORE_STARTUP_ASSEMBLY)); - } + throw InvalidOperationException(format(L"Error occured when initializing inprocess application, Return code: 0x%x", startupReturnCode)); } - // Used to make .NET Runtime always log to event log when there is an unhandled exception. - LOG_LAST_ERROR_IF(!SetEnvironmentVariable(L"COMPlus_UseEntryPointFilter", L"1")); - LOG_LAST_ERROR_IF(!SetEnvironmentVariable(L"COMPlus_DefaultStackSize", m_pConfig->QueryStackSize().c_str())); + if (m_pConfig->QueryCallStartupHook()) + { + RETURN_IF_NOT_ZERO(context->m_hostFxr.SetRuntimePropertyValue(DOTNETCORE_STARTUP_HOOK, ASPNETCORE_STARTUP_ASSEMBLY)); + } + + RETURN_IF_NOT_ZERO(context->m_hostFxr.SetRuntimePropertyValue(DOTNETCORE_USE_ENTRYPOINT_FILTER, L"1")); + RETURN_IF_NOT_ZERO(context->m_hostFxr.SetRuntimePropertyValue(DOTNETCORE_STACK_SIZE, m_pConfig->QueryStackSize().c_str())); bool clrThreadExited; { @@ -434,6 +428,7 @@ IN_PROCESS_APPLICATION::ExecuteClr(const std::shared_ptr& con LOG_INFOF(L"Managed application exited with code %d", exitCode); context->m_exitCode = exitCode; + context->m_hostFxr.Close(); } __except(GetExceptionCode() != 0) { diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h index 0f3ae289b9..4eda1fd7da 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.h @@ -15,8 +15,6 @@ typedef BOOL(WINAPI * PFN_SHUTDOWN_HANDLER) (void* pvShutdownHandlerContext); typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_ASYNC_COMPLETION_HANDLER)(void *pvManagedHttpContext, HRESULT hrCompletionStatus, DWORD cbCompletion); typedef void(WINAPI * PFN_REQUESTS_DRAINED_HANDLER) (void* pvShutdownHandlerContext); -#define DOTNETCORE_STARTUP_HOOK L"DOTNET_STARTUP_HOOKS" -#define ASPNETCORE_STARTUP_ASSEMBLY L"Microsoft.AspNetCore.Server.IIS" class IN_PROCESS_APPLICATION : public InProcessApplicationBase { public: