Magic the magic happen

This commit is contained in:
Raymond Lynch 2021-07-11 16:32:29 -04:00
parent 84769ae5b7
commit 658eedca37
188 changed files with 10329 additions and 3549 deletions

111
lib/CoreCLR/CoreCLR.cpp Normal file
View file

@ -0,0 +1,111 @@
#define WIN32_LEAN_AND_MEAN
#include "CoreCLR.h"
#include <Windows.h>
#include <iostream>
#include "nethost/nethost.h"
#pragma comment(lib, "nethost/libnethost.lib")
CoreCLR::CoreCLR() {}
/* Core public functions */
int CoreCLR::load_hostfxr()
{
return CoreCLR::load_hostfxr(nullptr);
}
int CoreCLR::load_hostfxr(const struct get_hostfxr_parameters* parameters)
{
// Get the path to CoreCLR's hostfxr
wchar_t buffer[MAX_PATH]{};
size_t buffer_size = sizeof buffer / sizeof(wchar_t);
if (int rc = get_hostfxr_path(buffer, &buffer_size, parameters); rc != 0)
return rc;
// Load hostfxr and get desired exports
auto lib = reinterpret_cast<void*>(load_library(buffer));
m_hostfxr_initialize_for_runtime_config_fptr = reinterpret_cast<hostfxr_initialize_for_runtime_config_fn>(
get_export(lib, "hostfxr_initialize_for_runtime_config"));
m_hostfxr_get_runtime_delegate_fptr = reinterpret_cast<hostfxr_get_runtime_delegate_fn>(
get_export(lib, "hostfxr_get_runtime_delegate"));
m_hostfxr_close_fptr = reinterpret_cast<hostfxr_close_fn>(
get_export(lib, "hostfxr_close"));
return m_hostfxr_initialize_for_runtime_config_fptr
&& m_hostfxr_get_runtime_delegate_fptr
&& m_hostfxr_close_fptr ? 0 : -1;
}
bool CoreCLR::load_runtime(const std::wstring& runtime_config_path)
{
return CoreCLR::load_runtime(runtime_config_path, nullptr);
}
bool CoreCLR::load_runtime(const std::wstring& runtime_config_path, const struct hostfxr_initialize_parameters* parameters)
{
int result;
// Load .NET Core
hostfxr_handle context = nullptr;
result = m_hostfxr_initialize_for_runtime_config_fptr(
runtime_config_path.c_str(),
parameters,
&context);
// Success_HostAlreadyInitialized
if (result == 1)
{
printf("Success_HostAlreadyInitialized (0x1) ");
result = 0;
}
if (result != 0 || context == nullptr)
{
m_hostfxr_close_fptr(context);
return result;
}
// Get the load assembly function pointer
result = m_hostfxr_get_runtime_delegate_fptr(
context,
hdt_load_assembly_and_get_function_pointer,
reinterpret_cast<void**>(&m_load_assembly_and_get_function_pointer_fptr));
if (result != 0 || m_load_assembly_and_get_function_pointer_fptr == nullptr)
{
m_hostfxr_close_fptr(context);
return result;
}
m_hostfxr_close_fptr(context);
return 0;
}
int CoreCLR::load_assembly_and_get_function_pointer(
const wchar_t* assembly_path,
const wchar_t* type_name,
const wchar_t* method_name,
const wchar_t* delegate_type_name,
void* reserved,
void** delegate) const
{
int result = m_load_assembly_and_get_function_pointer_fptr(assembly_path, type_name, method_name, delegate_type_name, reserved, delegate);
if (result != 0)
delegate = nullptr;
return result;
};
/* Helpers */
uint64_t CoreCLR::load_library(const wchar_t* path)
{
return reinterpret_cast<uint64_t>(LoadLibraryW(path));
}
uint64_t CoreCLR::get_export(void* h, const char* name)
{
return reinterpret_cast<uint64_t>(GetProcAddress(static_cast<HMODULE>(h), name));
}

38
lib/CoreCLR/CoreCLR.h Normal file
View file

@ -0,0 +1,38 @@
#pragma once
#include <string>
#include "core/hostfxr.h"
#include "core/coreclr_delegates.h"
#include "nethost/nethost.h"
class CoreCLR {
public:
explicit CoreCLR();
~CoreCLR() = default;
int load_hostfxr();
int load_hostfxr(const get_hostfxr_parameters* parameters);
bool load_runtime(const std::wstring& runtime_config_path);
bool load_runtime(
const std::wstring& runtime_config_path,
const struct hostfxr_initialize_parameters* parameters);
int load_assembly_and_get_function_pointer(
const wchar_t* assembly_path,
const wchar_t* type_name,
const wchar_t* method_name,
const wchar_t* delegate_type_name,
void* reserved,
void** delegate) const;
private:
/* HostFXR delegates. */
hostfxr_initialize_for_runtime_config_fn m_hostfxr_initialize_for_runtime_config_fptr{};
hostfxr_get_runtime_delegate_fn m_hostfxr_get_runtime_delegate_fptr{};
hostfxr_close_fn m_hostfxr_close_fptr{};
load_assembly_and_get_function_pointer_fn m_load_assembly_and_get_function_pointer_fptr = nullptr;
/* Helper functions. */
static uint64_t load_library(const wchar_t* path);
static uint64_t get_export(void* h, const char* name);
};

110
lib/CoreCLR/boot.cpp Normal file
View file

@ -0,0 +1,110 @@
#define WIN32_LEAN_AND_MEAN
#include <cstdio>
#include <filesystem>
#include <Windows.h>
#include <Shlobj.h>
#include "CoreCLR.h"
FILE* g_CmdStream;
void ConsoleSetup(const std::wstring console_name)
{
if (!AllocConsole())
return;
SetConsoleTitleW(console_name.c_str());
freopen_s(&g_CmdStream, "CONOUT$", "w", stdout);
freopen_s(&g_CmdStream, "CONOUT$", "w", stderr);
freopen_s(&g_CmdStream, "CONIN$", "r", stdin);
}
void ConsoleTeardown()
{
FreeConsole();
}
int InitializeClrAndGetEntryPoint(
std::wstring runtimeconfig_path,
std::wstring module_path,
std::wstring entrypoint_assembly_name,
std::wstring entrypoint_method_name,
std::wstring entrypoint_delegate_type_name,
void** entrypoint_fn)
{
int result;
CoreCLR clr;
SetEnvironmentVariable(L"DOTNET_MULTILEVEL_LOOKUP", L"0");
wchar_t* _appdata;
result = SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, NULL, &_appdata);
if (result != 0)
{
printf("Error: Unable to get RoamingAppData path (err=%d)\n", result);
return result;
}
std::filesystem::path fs_app_data(_appdata);
wchar_t* dotnet_path = _wcsdup(fs_app_data.append("XIVLauncher").append("runtime").c_str());
// =========================================================================== //
wprintf(L"with dotnet_path: %s\n", dotnet_path);
wprintf(L"with config_path: %s\n", runtimeconfig_path.c_str());
wprintf(L"with module_path: %s\n", module_path.c_str());
if (!std::filesystem::exists(dotnet_path))
{
printf("Error: Unable to find .NET runtime path\n");
return 1;
}
get_hostfxr_parameters init_parameters
{
sizeof(get_hostfxr_parameters),
nullptr,
dotnet_path,
};
printf("Loading hostfxr... ");
if ((result = clr.load_hostfxr(&init_parameters)) != 0)
{
printf("\nError: Failed to load the `hostfxr` library (err=%d)\n", result);
return result;
}
printf("Done!\n");
// =========================================================================== //
hostfxr_initialize_parameters runtime_parameters
{
sizeof(hostfxr_initialize_parameters),
module_path.c_str(),
dotnet_path,
};
printf("Loading coreclr... ");;
if ((result = clr.load_runtime(runtimeconfig_path, &runtime_parameters)) != 0)
{
printf("\nError: Failed to load coreclr (err=%d)\n", result);
return result;
}
printf("Done!\n");
// =========================================================================== //
printf("Loading module... ");
if ((result = clr.load_assembly_and_get_function_pointer(
module_path.c_str(),
entrypoint_assembly_name.c_str(),
entrypoint_method_name.c_str(),
entrypoint_delegate_type_name.c_str(),
nullptr, entrypoint_fn)) != 0)
{
printf("\nError: Failed to load module (err=%d)\n", result);
return result;
}
printf("Done!\n");
// =========================================================================== //
return 0;
}

10
lib/CoreCLR/boot.h Normal file
View file

@ -0,0 +1,10 @@
void ConsoleSetup(const std::wstring console_name);
void ConsoleTeardown();
int InitializeClrAndGetEntryPoint(
std::wstring runtimeconfig_path,
std::wstring module_path,
std::wstring entrypoint_assembly_name,
std::wstring entrypoint_method_name,
std::wstring entrypoint_delegate_type_name,
void** entrypoint_fn);

View file

@ -0,0 +1,47 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#ifndef __CORECLR_DELEGATES_H__
#define __CORECLR_DELEGATES_H__
#include <stdint.h>
#if defined(_WIN32)
#define CORECLR_DELEGATE_CALLTYPE __stdcall
#ifdef _WCHAR_T_DEFINED
typedef wchar_t char_t;
#else
typedef unsigned short char_t;
#endif
#else
#define CORECLR_DELEGATE_CALLTYPE
typedef char char_t;
#endif
#define UNMANAGEDCALLERSONLY_METHOD ((const char_t*)-1)
// Signature of delegate returned by coreclr_delegate_type::load_assembly_and_get_function_pointer
typedef int (CORECLR_DELEGATE_CALLTYPE* load_assembly_and_get_function_pointer_fn)(
const char_t* assembly_path /* Fully qualified path to assembly */,
const char_t* type_name /* Assembly qualified type name */,
const char_t* method_name /* Public static method name compatible with delegateType */,
const char_t* delegate_type_name /* Assembly qualified delegate type name or null
or UNMANAGEDCALLERSONLY_METHOD if the method is marked with
the UnmanagedCallersOnlyAttribute. */,
void* reserved /* Extensibility parameter (currently unused and must be 0) */,
/*out*/ void** delegate /* Pointer where to store the function pointer result */);
// Signature of delegate returned by load_assembly_and_get_function_pointer_fn when delegate_type_name == null (default)
typedef int (CORECLR_DELEGATE_CALLTYPE* component_entry_point_fn)(void* arg, int32_t arg_size_in_bytes);
typedef int (CORECLR_DELEGATE_CALLTYPE* get_function_pointer_fn)(
const char_t* type_name /* Assembly qualified type name */,
const char_t* method_name /* Public static method name compatible with delegateType */,
const char_t* delegate_type_name /* Assembly qualified delegate type name or null,
or UNMANAGEDCALLERSONLY_METHOD if the method is marked with
the UnmanagedCallersOnlyAttribute. */,
void* load_context /* Extensibility parameter (currently unused and must be 0) */,
void* reserved /* Extensibility parameter (currently unused and must be 0) */,
/*out*/ void** delegate /* Pointer where to store the function pointer result */);
#endif // __CORECLR_DELEGATES_H__

288
lib/CoreCLR/core/hostfxr.h Normal file
View file

@ -0,0 +1,288 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#ifndef __HOSTFXR_H__
#define __HOSTFXR_H__
#include <stddef.h>
#include <stdint.h>
#if defined(_WIN32)
#define HOSTFXR_CALLTYPE __cdecl
#ifdef _WCHAR_T_DEFINED
typedef wchar_t char_t;
#else
typedef unsigned short char_t;
#endif
#else
#define HOSTFXR_CALLTYPE
typedef char char_t;
#endif
enum hostfxr_delegate_type
{
hdt_com_activation,
hdt_load_in_memory_assembly,
hdt_winrt_activation,
hdt_com_register,
hdt_com_unregister,
hdt_load_assembly_and_get_function_pointer,
hdt_get_function_pointer,
};
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_main_fn)(const int argc, const char_t** argv);
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_main_startupinfo_fn)(
const int argc,
const char_t** argv,
const char_t* host_path,
const char_t* dotnet_root,
const char_t* app_path);
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_main_bundle_startupinfo_fn)(
const int argc,
const char_t** argv,
const char_t* host_path,
const char_t* dotnet_root,
const char_t* app_path,
int64_t bundle_header_offset);
typedef void(HOSTFXR_CALLTYPE* hostfxr_error_writer_fn)(const char_t* message);
//
// Sets a callback which is to be used to write errors to.
//
// Parameters:
// error_writer
// A callback function which will be invoked every time an error is to be reported.
// Or nullptr to unregister previously registered callback and return to the default behavior.
// Return value:
// The previously registered callback (which is now unregistered), or nullptr if no previous callback
// was registered
//
// The error writer is registered per-thread, so the registration is thread-local. On each thread
// only one callback can be registered. Subsequent registrations overwrite the previous ones.
//
// By default no callback is registered in which case the errors are written to stderr.
//
// Each call to the error writer is sort of like writing a single line (the EOL character is omitted).
// Multiple calls to the error writer may occure for one failure.
//
// If the hostfxr invokes functions in hostpolicy as part of its operation, the error writer
// will be propagated to hostpolicy for the duration of the call. This means that errors from
// both hostfxr and hostpolicy will be reporter through the same error writer.
//
typedef hostfxr_error_writer_fn(HOSTFXR_CALLTYPE* hostfxr_set_error_writer_fn)(hostfxr_error_writer_fn error_writer);
typedef void* hostfxr_handle;
struct hostfxr_initialize_parameters
{
size_t size;
const char_t* host_path;
const char_t* dotnet_root;
};
//
// Initializes the hosting components for a dotnet command line running an application
//
// Parameters:
// argc
// Number of argv arguments
// argv
// Command-line arguments for running an application (as if through the dotnet executable).
// parameters
// Optional. Additional parameters for initialization
// host_context_handle
// On success, this will be populated with an opaque value representing the initialized host context
//
// Return value:
// Success - Hosting components were successfully initialized
// HostInvalidState - Hosting components are already initialized
//
// This function parses the specified command-line arguments to determine the application to run. It will
// then find the corresponding .runtimeconfig.json and .deps.json with which to resolve frameworks and
// dependencies and prepare everything needed to load the runtime.
//
// This function only supports arguments for running an application. It does not support SDK commands.
//
// This function does not load the runtime.
//
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_initialize_for_dotnet_command_line_fn)(
int argc,
const char_t** argv,
const struct hostfxr_initialize_parameters* parameters,
/*out*/ hostfxr_handle* host_context_handle);
//
// Initializes the hosting components using a .runtimeconfig.json file
//
// Parameters:
// runtime_config_path
// Path to the .runtimeconfig.json file
// parameters
// Optional. Additional parameters for initialization
// host_context_handle
// On success, this will be populated with an opaque value representing the initialized host context
//
// Return value:
// Success - Hosting components were successfully initialized
// Success_HostAlreadyInitialized - Config is compatible with already initialized hosting components
// Success_DifferentRuntimeProperties - Config has runtime properties that differ from already initialized hosting components
// CoreHostIncompatibleConfig - Config is incompatible with already initialized hosting components
//
// This function will process the .runtimeconfig.json to resolve frameworks and prepare everything needed
// to load the runtime. It will only process the .deps.json from frameworks (not any app/component that
// may be next to the .runtimeconfig.json).
//
// This function does not load the runtime.
//
// If called when the runtime has already been loaded, this function will check if the specified runtime
// config is compatible with the existing runtime.
//
// Both Success_HostAlreadyInitialized and Success_DifferentRuntimeProperties codes are considered successful
// initializations. In the case of Success_DifferentRuntimeProperties, it is left to the consumer to verify that
// the difference in properties is acceptable.
//
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_initialize_for_runtime_config_fn)(
const char_t* runtime_config_path,
const struct hostfxr_initialize_parameters* parameters,
/*out*/ hostfxr_handle* host_context_handle);
//
// Gets the runtime property value for an initialized host context
//
// Parameters:
// host_context_handle
// Handle to the initialized host context
// name
// Runtime property name
// value
// Out parameter. Pointer to a buffer with the property value.
//
// Return value:
// The error code result.
//
// The buffer pointed to by value is owned by the host context. The lifetime of the buffer is only
// guaranteed until any of the below occur:
// - a 'run' method is called for the host context
// - properties are changed via hostfxr_set_runtime_property_value
// - the host context is closed via 'hostfxr_close'
//
// If host_context_handle is nullptr and an active host context exists, this function will get the
// property value for the active host context.
//
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_get_runtime_property_value_fn)(
const hostfxr_handle host_context_handle,
const char_t* name,
/*out*/ const char_t** value);
//
// Sets the value of a runtime property for an initialized host context
//
// Parameters:
// host_context_handle
// Handle to the initialized host context
// name
// Runtime property name
// value
// Value to set
//
// Return value:
// The error code result.
//
// Setting properties is only supported for the first host context, before the runtime has been loaded.
//
// If the property already exists in the host context, it will be overwritten. If value is nullptr, the
// property will be removed.
//
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_set_runtime_property_value_fn)(
const hostfxr_handle host_context_handle,
const char_t* name,
const char_t* value);
//
// Gets all the runtime properties for an initialized host context
//
// Parameters:
// host_context_handle
// Handle to the initialized host context
// count
// [in] Size of the keys and values buffers
// [out] Number of properties returned (size of keys/values buffers used). If the input value is too
// small or keys/values is nullptr, this is populated with the number of available properties
// keys
// Array of pointers to buffers with runtime property keys
// values
// Array of pointers to buffers with runtime property values
//
// Return value:
// The error code result.
//
// The buffers pointed to by keys and values are owned by the host context. The lifetime of the buffers is only
// guaranteed until any of the below occur:
// - a 'run' method is called for the host context
// - properties are changed via hostfxr_set_runtime_property_value
// - the host context is closed via 'hostfxr_close'
//
// If host_context_handle is nullptr and an active host context exists, this function will get the
// properties for the active host context.
//
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_get_runtime_properties_fn)(
const hostfxr_handle host_context_handle,
/*inout*/ size_t* count,
/*out*/ const char_t** keys,
/*out*/ const char_t** values);
//
// Load CoreCLR and run the application for an initialized host context
//
// Parameters:
// host_context_handle
// Handle to the initialized host context
//
// Return value:
// If the app was successfully run, the exit code of the application. Otherwise, the error code result.
//
// The host_context_handle must have been initialized using hostfxr_initialize_for_dotnet_command_line.
//
// This function will not return until the managed application exits.
//
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_run_app_fn)(const hostfxr_handle host_context_handle);
//
// Gets a typed delegate from the currently loaded CoreCLR or from a newly created one.
//
// Parameters:
// host_context_handle
// Handle to the initialized host context
// type
// Type of runtime delegate requested
// delegate
// An out parameter that will be assigned the delegate.
//
// Return value:
// The error code result.
//
// If the host_context_handle was initialized using hostfxr_initialize_for_runtime_config,
// then all delegate types are supported.
// If the host_context_handle was initialized using hostfxr_initialize_for_dotnet_command_line,
// then only the following delegate types are currently supported:
// hdt_load_assembly_and_get_function_pointer
// hdt_get_function_pointer
//
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_get_runtime_delegate_fn)(
const hostfxr_handle host_context_handle,
enum hostfxr_delegate_type type,
/*out*/ void** delegate);
//
// Closes an initialized host context
//
// Parameters:
// host_context_handle
// Handle to the initialized host context
//
// Return value:
// The error code result.
//
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_close_fn)(const hostfxr_handle host_context_handle);
#endif //__HOSTFXR_H__

7
lib/CoreCLR/framework.h Normal file
View file

@ -0,0 +1,7 @@
#pragma once
// Exclude rarely-used stuff from Windows headers
#define WIN32_LEAN_AND_MEAN
// Windows Header Files
#include <windows.h>

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,99 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#ifndef __NETHOST_H__
#define __NETHOST_H__
#include <stddef.h>
#ifdef _WIN32
#ifdef NETHOST_EXPORT
#define NETHOST_API __declspec(dllexport)
#else
// Consuming the nethost as a static library
// Shouldn't export attempt to dllimport.
#ifdef NETHOST_USE_AS_STATIC
#define NETHOST_API
#else
#define NETHOST_API __declspec(dllimport)
#endif
#endif
#define NETHOST_CALLTYPE __stdcall
#ifdef _WCHAR_T_DEFINED
typedef wchar_t char_t;
#else
typedef unsigned short char_t;
#endif
#else
#ifdef NETHOST_EXPORT
#define NETHOST_API __attribute__((__visibility__("default")))
#else
#define NETHOST_API
#endif
#define NETHOST_CALLTYPE
typedef char char_t;
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Parameters for get_hostfxr_path
//
// Fields:
// size
// Size of the struct. This is used for versioning.
//
// assembly_path
// Path to the compenent's assembly.
// If specified, hostfxr is located as if the assembly_path is the apphost
//
// dotnet_root
// Path to directory containing the dotnet executable.
// If specified, hostfxr is located as if an application is started using
// 'dotnet app.dll', which means it will be searched for under the dotnet_root
// path and the assembly_path is ignored.
//
struct get_hostfxr_parameters {
size_t size;
const char_t *assembly_path;
const char_t *dotnet_root;
};
//
// Get the path to the hostfxr library
//
// Parameters:
// buffer
// Buffer that will be populated with the hostfxr path, including a null terminator.
//
// buffer_size
// [in] Size of buffer in char_t units.
// [out] Size of buffer used in char_t units. If the input value is too small
// or buffer is nullptr, this is populated with the minimum required size
// in char_t units for a buffer to hold the hostfxr path
//
// get_hostfxr_parameters
// Optional. Parameters that modify the behaviour for locating the hostfxr library.
// If nullptr, hostfxr is located using the enviroment variable or global registration
//
// Return value:
// 0 on success, otherwise failure
// 0x80008098 - buffer is too small (HostApiBufferTooSmall)
//
// Remarks:
// The full search for the hostfxr library is done on every call. To minimize the need
// to call this function multiple times, pass a large buffer (e.g. PATH_MAX).
//
NETHOST_API int NETHOST_CALLTYPE get_hostfxr_path(
char_t * buffer,
size_t * buffer_size,
const struct get_hostfxr_parameters *parameters);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __NETHOST_H__

Binary file not shown.

5
lib/CoreCLR/pch.cpp Normal file
View file

@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

13
lib/CoreCLR/pch.h Normal file
View file

@ -0,0 +1,13 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#endif //PCH_H