``` C
-int hostfxr_initialize_for_app(
+int hostfxr_initialize_for_dotnet_command_line(
int argc,
const char_t *argv[],
- const char_t *app_path,
const hostfxr_initialize_parameters *parameters,
hostfxr_handle * host_context_handle
);
```
Initialize the hosting components for running a managed application.
* `argc` / `argv` - command-line arguments
-* `app_path` - path to the application to run
* `parameters` - optional additional parameters
* `host_context_handle` - if initialization is successful, this receives an opaque value which identifies the initialized host context.
``` C
int hostfxr_run_app(const hostfxr_handle host_context_handle);
```
-Run the application specified by `hostfxr_initialize_for_app`.
+Run the application specified by `hostfxr_initialize_for_dotnet_command_line`.
* `host_context_handle` - handle to the initialized host context.
This function does not return until the application completes execution. It will shutdown CoreCLR after the application executes.
``` C
-int hostfxr_initialize_for_app(
+int hostfxr_initialize_for_dotnet_command_line(
int argc,
const char_t * argv[],
- const char_t * app_path,
const hostfxr_initialize_parameters * parameters,
hostfxr_handle * host_context_handle
);
```
Initializes the hosting components for running a managed application.
-When used to execute an app, the `app_path` (or CLI equivalent) will be used to locate the `.runtimeconfig.json` and the `.deps.json` which will be used to load the application and its dependent frameworks.
-* `argc` and `argv` - the command line - optional, if `argc` is `0` then `argv` is ignored.
-* `app_path` - path to the application (the managed `.dll`) to run. This can be `nullptr` if the app is specified in the command line arguments.
+The command line is parsed to determine the app path. The app path will be used to locate the `.runtimeconfig.json` and the `.deps.json` which will be used to load the application and its dependent frameworks.
+* `argc` and `argv` - the command line for running a managed application. These represent the arguments which would have been passed to the muxer if the app was being run from the command line.
* `parameters` - additional parameters - see `hostfxr_initialize_parameters` for details. (Could be made optional potentially)
* `host_context_handle` - output parameter. On success receives an opaque value which identifies the initialized host context. The handle should be closed by calling `hostfxr_close`.
+This function only supports arguments for running an application as through the muxer. It does not support SDK commands.
+
This function can only be called once per-process. It's not supported to run multiple apps in one process (even sequentially).
This function will fail if there already is a CoreCLR running in the process as it's not possible to run two apps in a single process.
```
This function would load the specified `.runtimeconfig.json`, resolve all frameworks, resolve all the assets from those frameworks and then prepare runtime initialization where the TPA contains only frameworks. Note that this case does NOT consume any `.deps.json` from the app/component (only processes the framework's `.deps.json`). This entry point is intended for `comhost`/`ijwhost`/`nethost` and similar scenarios.
-* `runtime_config_path` - path to the `.runtimeconfig.json` file to process. Unlike with the `hostfxr_initialize_for_app`, any `.deps.json` from the app/component will not be processed by the hosting layers.
+* `runtime_config_path` - path to the `.runtimeconfig.json` file to process. Unlike with `hostfxr_initialize_for_dotnet_command_line`, any `.deps.json` from the app/component will not be processed by the hosting layers.
* `parameters` - additional parameters - see `hostfxr_initialize_parameters` for details. (Could be made optional potentially)
* `host_context_handle` - output parameter. On success receives an opaque value which identifies the initialized host context. The handle should be closed by calling `hostfxr_close`.
* If it's called when there already is CoreCLR in the process (loaded through the `hostfxr`, direct usage of `coreclr` is not supported), then the function determines if the specified runtime configuration is compatible with the existing runtime and frameworks. If it is, it returns a valid handle, otherwise it fails.
It needs to be possible to call this function simultaneously from multiple threads at the same time.
-It also needs to be possible to call this function while there is an active host context created by `hostfxr_initialize_for_app` and running inside the `hostfxr_run_app`.
+It also needs to be possible to call this function while there is an active host context created by `hostfxr_initialize_for_dotnet_command_line` and running inside the `hostfxr_run_app`.
The function returns specific return code for the first initialized host context, and a different one for any subsequent one. Both return codes are considered "success". If there already was initialized host context in the process then the returned host context has these limitations:
* It won't allow setting runtime properties.
``` C
int hostfxr_run_app(const hostfxr_handle host_context_handle);
```
-Runs the application specified by the `hostfxr_initialize_for_app`. It is illegal to try to use this function when the host context was initialized through any other way.
+Runs the application specified by the `hostfxr_initialize_for_dotnet_command_line`. It is illegal to try to use this function when the host context was initialized through any other way.
* `host_context_handle` - handle to the initialized host context.
The function will return only once the managed application exits.
* `winrt_activation` - WinRT activation entry-point - see [WinRT activation](https://github.com/dotnet/core-setup/blob/master/Documentation/design-docs/WinRT-activation.md) for more details.
* `delegate` - when successful, the native function pointer to the requested runtime functionality.
-Initially the function will only work if `hostfxr_initialize_for_runtime_config` was used to initialize the host context. Later on this could be relaxed to allow being used in combination with `hostfxr_initialize_for_app`.
+Initially the function will only work if `hostfxr_initialize_for_runtime_config` was used to initialize the host context. Later on this could be relaxed to allow being used in combination with `hostfxr_initialize_for_dotnet_command_line`.
Initially there might be a limitation of calling this function only once on a given host context to simplify the implementation. Currently we don't have a scenario where it would be absolutely required to support multiple calls.
params.dotnet_root = get_directory(get_directory(get_directory(hostfxr_path))); // Three levels up from hostfxr typically
hostfxr_handle host_context_handle;
-hostfxr_initialize_for_app(
+hostfxr_initialize_for_dotnet_command_line(
_argc_,
_argv_,
- _app_path_,
¶ms,
&host_context_handle);
const pal::char_t *argv[],
/*out*/ int *new_argoff,
/*out*/ pal::string_t &app_candidate,
- /*out*/ opt_map_t &opts)
+ /*out*/ opt_map_t &opts,
+ bool args_include_running_executable)
{
+ int argoff = args_include_running_executable ? 1 : 0;
int result;
if (mode == host_mode_t::split_fx)
{
// Invoked as corehost
trace::verbose(_X("--- Executing in split/FX mode..."));
- result = parse_args(host_info, 1, argc, argv, false, mode, new_argoff, app_candidate, opts);
+ result = parse_args(host_info, argoff, argc, argv, false, mode, new_argoff, app_candidate, opts);
}
else if (mode == host_mode_t::apphost)
{
// Invoked from the application base.
trace::verbose(_X("--- Executing in a native executable mode..."));
- result = parse_args(host_info, 1, argc, argv, false, mode, new_argoff, app_candidate, opts);
+ result = parse_args(host_info, argoff, argc, argv, false, mode, new_argoff, app_candidate, opts);
}
else
{
assert(mode == host_mode_t::muxer);
trace::verbose(_X("--- Executing in muxer mode..."));
- if (argc <= 1)
+ if (argc <= argoff)
{
command_line::print_muxer_usage(!is_sdk_dir_present(host_info.dotnet_root));
return StatusCode::InvalidArgFailure;
}
- if (pal::strcasecmp(_X("exec"), argv[1]) == 0)
+ if (pal::strcasecmp(_X("exec"), argv[argoff]) == 0)
{
- // arg offset 2 for dotnet, exec
- result = parse_args(host_info, 2, argc, argv, true, mode, new_argoff, app_candidate, opts);
+ // arg offset +1 for exec
+ argoff++;
+ result = parse_args(host_info, argoff, argc, argv, true, mode, new_argoff, app_candidate, opts);
}
else
{
- // arg offset 1 for dotnet
- result = parse_args(host_info, 1, argc, argv, false, mode, new_argoff, app_candidate, opts);
+ result = parse_args(host_info, argoff, argc, argv, false, mode, new_argoff, app_candidate, opts);
}
}
const pal::char_t* argv[],
/*out*/ int *new_argoff,
/*out*/ pal::string_t &app_candidate,
- /*out*/ opt_map_t &opts);
+ /*out*/ opt_map_t &opts,
+ bool args_include_running_executable = true);
int parse_args_for_sdk_command(
const host_startup_info_t& host_info,
const int argc,
const host_startup_info_t &host_info,
int argc,
const pal::char_t* argv[],
+ const opt_map_t &opts,
hostfxr_handle *host_context_handle)
{
{
}
host_mode_t mode = host_mode_t::apphost;
- opt_map_t opts;
pal::string_t hostpolicy_dir;
std::unique_ptr<corehost_init_t> init;
int rc = get_init_info_for_app(
const host_startup_info_t& host_info,
int argc,
const pal::char_t* argv[],
+ const opt_map_t& opts,
hostfxr_handle *host_context_handle);
static int initialize_for_runtime_config(
const host_startup_info_t& host_info,
}
//
-// Initializes the hosting components for running an application
+// Initializes the hosting components for a dotnet command line running an application
//
// Parameters:
// argc
// Number of argv arguments
// argv
-// Arguments for the application. If argc is 0, this is ignored.
-// app_path
-// Path to the managed application. If this is nullptr, the first argument in argv is assumed to be
-// the application path.
+// 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 initalized host context
+// 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
//
-// The app_path will be used to 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 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.
//
-SHARED_API int32_t __cdecl hostfxr_initialize_for_app(
+SHARED_API int32_t __cdecl hostfxr_initialize_for_dotnet_command_line(
int argc,
const pal::char_t *argv[],
- const pal::char_t *app_path,
const hostfxr_initialize_parameters * parameters,
/*out*/ hostfxr_handle * host_context_handle)
{
- trace_hostfxr_entry_point(_X("hostfxr_initialize_for_app"));
+ trace_hostfxr_entry_point(_X("hostfxr_initialize_for_dotnet_command_line"));
- if (host_context_handle == nullptr || (argv == nullptr && argc != 0) || (app_path == nullptr && argc == 0))
+ if (host_context_handle == nullptr || argv == nullptr || argc == 0)
return StatusCode::InvalidArgFailure;
*host_context_handle = nullptr;
host_startup_info_t startup_info{};
- int new_argc;
- const pal::char_t **new_argv;
- if (app_path != nullptr)
- {
- startup_info.app_path = app_path;
- new_argc = argc;
- new_argv = argv;
- }
- else
- {
- // Take the first argument as the app path
- startup_info.app_path = argv[0];
- new_argc = argc-1;
- new_argv = argc > 0 ? &argv[1] : nullptr;
- }
-
int rc = populate_startup_info(parameters, startup_info);
if (rc != StatusCode::Success)
return rc;
+ int new_argoff;
+ opt_map_t opts;
+ rc = command_line::parse_args_for_mode(
+ host_mode_t::muxer,
+ startup_info,
+ argc,
+ argv,
+ &new_argoff,
+ startup_info.app_path,
+ opts,
+ false /*args_include_running_executable*/);
+ if (rc != StatusCode::Success)
+ return rc;
+
+ new_argoff++; // Skip the app path to get to app args
+ int app_argc = argc - new_argoff;
+ const pal::char_t **app_argv = app_argc > 0 ? &argv[new_argoff] : nullptr;
return fx_muxer_t::initialize_for_app(
startup_info,
- new_argc,
- new_argv,
+ app_argc,
+ app_argv,
+ opts,
host_context_handle);
}
// parameters
// Optional. Additional parameters for initialization
// host_context_handle
-// On success, this will be populated with an opaque value representing the initalized host context
+// On success, this will be populated with an opaque value representing the initialized host context
//
// Return value:
// Success - Hosting components were successfully initialized
// 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_app.
+// 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.
//
const pal::char_t *dotnet_root;
};
-using hostfxr_initialize_for_app_fn = int32_t(__cdecl *)(
+using hostfxr_initialize_for_dotnet_command_line_fn = int32_t(__cdecl *)(
int argc,
const pal::char_t *argv[],
- const pal::char_t *app_path,
const hostfxr_initialize_parameters *parameters,
/*out*/ hostfxr_handle *host_context_handle);
using hostfxr_initialize_for_runtime_config_fn = int32_t(__cdecl *)(
class hostfxr_exports
{
public:
- hostfxr_initialize_for_app_fn init_app;
+ hostfxr_initialize_for_dotnet_command_line_fn init_command_line;
hostfxr_run_app_fn run_app;
hostfxr_initialize_for_runtime_config_fn init_config;
throw StatusCode::CoreHostLibLoadFailure;
}
- init_app = (hostfxr_initialize_for_app_fn)pal::get_symbol(_dll, "hostfxr_initialize_for_app");
+ init_command_line = (hostfxr_initialize_for_dotnet_command_line_fn)pal::get_symbol(_dll, "hostfxr_initialize_for_dotnet_command_line");
run_app = (hostfxr_run_app_fn)pal::get_symbol(_dll, "hostfxr_run_app");
init_config = (hostfxr_initialize_for_runtime_config_fn)pal::get_symbol(_dll, "hostfxr_initialize_for_runtime_config");
main_startupinfo = (hostfxr_main_startupinfo_fn)pal::get_symbol(_dll, "hostfxr_main_startupinfo");
- if (init_app == nullptr || run_app == nullptr
+ if (init_command_line == nullptr || run_app == nullptr
|| init_config == nullptr || get_delegate == nullptr
|| get_prop_value == nullptr || set_prop_value == nullptr
|| get_properties == nullptr || close == nullptr
bool host_context_test::app(
check_properties check_properties,
const pal::string_t &hostfxr_path,
- const pal::char_t *app_path,
int argc,
const pal::char_t *argv[],
pal::stringstream_t &test_output)
hostfxr_exports hostfxr { hostfxr_path };
hostfxr_handle handle;
- int rc = hostfxr.init_app(argc, argv, app_path, nullptr, &handle);
+ int rc = hostfxr.init_command_line(argc, argv, nullptr, &handle);
if (rc != StatusCode::Success)
{
- test_output << _X("hostfxr_initialize_for_app failed: ") << std::hex << std::showbase << rc << std::endl;
+ test_output << _X("hostfxr_initialize_for_command_line failed: ") << std::hex << std::showbase << rc << std::endl;
return false;
}
{
hostfxr_exports hostfxr { hostfxr_path };
+ std::vector<const pal::char_t*> argv_local;
+ argv_local.push_back(app_path);
+ for (int i = 0; i < argc; ++i)
+ argv_local.push_back(argv[i]);
+
hostfxr_handle handle;
- int rc = hostfxr.init_app(argc, argv, app_path, nullptr, &handle);
+ int rc = hostfxr.init_command_line(argv_local.size(), argv_local.data(), nullptr, &handle);
if (rc != StatusCode::Success)
{
- test_output << _X("hostfxr_initialize_for_app failed: ") << std::hex << std::showbase << rc << std::endl;
+ test_output << _X("hostfxr_initialize_for_command_line failed: ") << std::hex << std::showbase << rc << std::endl;
return false;
}
bool app(
check_properties scenario,
const pal::string_t &hostfxr_path,
- const pal::char_t *app_path,
int argc,
const pal::char_t *argv[],
pal::stringstream_t &test_output);
bool success = false;
if (pal::strcmp(scenario, _X("app")) == 0)
{
- success = host_context_test::app(check_properties, hostfxr_path, app_or_config_path, remaining_argc, remaining_argv, test_output);
+ // Everything after hostfxr path is the command line to use
+ success = host_context_test::app(check_properties, hostfxr_path, remaining_argc + 1, &argv[5], test_output);
}
else if (pal::strcmp(scenario, _X("config")) == 0)
{
public const string Secondary = "[SECONDARY] ";
}
+ public enum CommandLine
+ {
+ AppPath,
+ Exec,
+ }
+
private const string HostContextArg = "host_context";
private const string PropertyValueFromHost = "VALUE_FROM_HOST";
}
[Theory]
- [InlineData(false, CheckProperties.None)]
- [InlineData(false, CheckProperties.Get)]
- [InlineData(false, CheckProperties.Set)]
- [InlineData(false, CheckProperties.Remove)]
- [InlineData(false, CheckProperties.GetAll)]
- [InlineData(false, CheckProperties.GetActive)]
- [InlineData(false, CheckProperties.GetAllActive)]
- [InlineData(true, CheckProperties.None)]
- [InlineData(true, CheckProperties.Get)]
- [InlineData(true, CheckProperties.Set)]
- [InlineData(true, CheckProperties.Remove)]
- [InlineData(true, CheckProperties.GetAll)]
- [InlineData(true, CheckProperties.GetActive)]
- [InlineData(true, CheckProperties.GetAllActive)]
- public void RunApp(bool isSelfContained, string checkProperties)
+ [InlineData(CommandLine.AppPath, false, CheckProperties.None)]
+ [InlineData(CommandLine.AppPath, false, CheckProperties.Get)]
+ [InlineData(CommandLine.AppPath, false, CheckProperties.Set)]
+ [InlineData(CommandLine.AppPath, false, CheckProperties.Remove)]
+ [InlineData(CommandLine.AppPath, false, CheckProperties.GetAll)]
+ [InlineData(CommandLine.AppPath, false, CheckProperties.GetActive)]
+ [InlineData(CommandLine.AppPath, false, CheckProperties.GetAllActive)]
+ [InlineData(CommandLine.AppPath, true, CheckProperties.None)]
+ [InlineData(CommandLine.AppPath, true, CheckProperties.Get)]
+ [InlineData(CommandLine.AppPath, true, CheckProperties.Set)]
+ [InlineData(CommandLine.AppPath, true, CheckProperties.Remove)]
+ [InlineData(CommandLine.AppPath, true, CheckProperties.GetAll)]
+ [InlineData(CommandLine.AppPath, true, CheckProperties.GetActive)]
+ [InlineData(CommandLine.AppPath, true, CheckProperties.GetAllActive)]
+ [InlineData(CommandLine.Exec, false, CheckProperties.None)]
+ [InlineData(CommandLine.Exec, false, CheckProperties.Get)]
+ [InlineData(CommandLine.Exec, false, CheckProperties.Set)]
+ [InlineData(CommandLine.Exec, false, CheckProperties.Remove)]
+ [InlineData(CommandLine.Exec, false, CheckProperties.GetAll)]
+ [InlineData(CommandLine.Exec, false, CheckProperties.GetActive)]
+ [InlineData(CommandLine.Exec, false, CheckProperties.GetAllActive)]
+ [InlineData(CommandLine.Exec, true, CheckProperties.None)]
+ [InlineData(CommandLine.Exec, true, CheckProperties.Get)]
+ [InlineData(CommandLine.Exec, true, CheckProperties.Set)]
+ [InlineData(CommandLine.Exec, true, CheckProperties.Remove)]
+ [InlineData(CommandLine.Exec, true, CheckProperties.GetAll)]
+ [InlineData(CommandLine.Exec, true, CheckProperties.GetActive)]
+ [InlineData(CommandLine.Exec, true, CheckProperties.GetAllActive)]
+ public void RunApp(CommandLine commandLine, bool isSelfContained, string checkProperties)
{
string expectedAppPath;
string hostFxrPath;
HostContextArg,
Scenario.App,
checkProperties,
- hostFxrPath,
- expectedAppPath
+ hostFxrPath
};
+
+ string[] commandArgs = { };
+ switch (commandLine)
+ {
+ case CommandLine.AppPath:
+ commandArgs = new string[]
+ {
+ expectedAppPath
+ };
+ break;
+ case CommandLine.Exec:
+ commandArgs = new string[]
+ {
+ "exec",
+ expectedAppPath
+ };
+ break;
+ }
+
string[] appArgs =
{
SharedTestState.AppPropertyName,
newPropertyName
};
- CommandResult result = Command.Create(sharedState.NativeHostPath, args.Concat(appArgs))
+ CommandResult result = Command.Create(sharedState.NativeHostPath, args.Concat(commandArgs).Concat(appArgs))
.CaptureStdErr()
.CaptureStdOut()
.EnvironmentVariable("COREHOST_TRACE", "1")