Add hostfxr_initialize_for_dotnet_command_line entry point (dotnet/core-setup#6548)
authorElinor Fung <47805090+elinor-fung@users.noreply.github.com>
Wed, 29 May 2019 00:40:59 +0000 (17:40 -0700)
committerGitHub <noreply@github.com>
Wed, 29 May 2019 00:40:59 +0000 (17:40 -0700)
Commit migrated from https://github.com/dotnet/core-setup/commit/aec6c77a664561249ecf763a642c6429c7891cdd

12 files changed:
docs/installer/design-docs/hosting-layer-apis.md
docs/installer/design-docs/native-hosting.md
src/installer/corehost/cli/fxr/command_line.cpp
src/installer/corehost/cli/fxr/command_line.h
src/installer/corehost/cli/fxr/fx_muxer.cpp
src/installer/corehost/cli/fxr/fx_muxer.h
src/installer/corehost/cli/fxr/hostfxr.cpp
src/installer/corehost/cli/hostfxr.h
src/installer/corehost/cli/test/nativehost/host_context_test.cpp
src/installer/corehost/cli/test/nativehost/host_context_test.h
src/installer/corehost/cli/test/nativehost/nativehost.cpp
src/installer/test/HostActivationTests/NativeHosting/HostContext.cs

index 6c97158..f15a0fc 100644 (file)
@@ -143,17 +143,15 @@ If `hostfxr` invokes functions in `hostpolicy` as part of its operation, the err
 
 
 ``` 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.
 
@@ -221,7 +219,7 @@ See [Native hosting](native-hosting.md#runtime-properties)
 ``` 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.
index 52bfc5e..e78b508 100644 (file)
@@ -148,22 +148,22 @@ The `hostfxr_initialize_parameters` structure stores parameters which are common
 
 
 ``` 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.
@@ -180,7 +180,7 @@ int hostfxr_initialize_for_runtime_config(
 ```
 
 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`.
 
@@ -189,7 +189,7 @@ This function can be called multiple times in a process.
 * 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.
@@ -272,7 +272,7 @@ Note that `hostfxr_set_runtime_property_value` can remove or add new 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.
@@ -293,7 +293,7 @@ Starts the runtime and returns a function pointer to specified functionality of
   * `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.
 
@@ -375,10 +375,9 @@ params.host_path = get_path_to_the_host_exe(); // Path to the current executable
 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_,
     &params,
     &host_context_handle);
 
index 84712fe..928818c 100644 (file)
@@ -223,20 +223,22 @@ int command_line::parse_args_for_mode(
     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
     {
@@ -244,21 +246,21 @@ int command_line::parse_args_for_mode(
         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);
         }
     }
 
index 4eace7d..60ccb6d 100644 (file)
@@ -48,7 +48,8 @@ namespace command_line
         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,
index 49eee54..0551047 100644 (file)
@@ -663,6 +663,7 @@ int fx_muxer_t::initialize_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)
 {
     {
@@ -679,7 +680,6 @@ int fx_muxer_t::initialize_for_app(
     }
 
     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(
index cf8f2b0..364683f 100644 (file)
@@ -25,6 +25,7 @@ public:
         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,
index 3472cc4..6cd9e00 100644 (file)
@@ -436,69 +436,70 @@ namespace
 }
 
 //
-// 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);
 }
 
@@ -511,7 +512,7 @@ SHARED_API int32_t __cdecl hostfxr_initialize_for_app(
 //    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
@@ -565,7 +566,7 @@ SHARED_API int32_t __cdecl hostfxr_initialize_for_runtime_config(
 // 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.
 //
index 949b8a5..6da46fd 100644 (file)
@@ -43,10 +43,9 @@ struct hostfxr_initialize_parameters
     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 *)(
index 04c7664..b0c0897 100644 (file)
@@ -22,7 +22,7 @@ namespace
     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;
@@ -45,7 +45,7 @@ namespace
                 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");
@@ -59,7 +59,7 @@ namespace
 
             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
@@ -266,7 +266,6 @@ host_context_test::check_properties host_context_test::check_properties_from_str
 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)
@@ -274,10 +273,10 @@ bool host_context_test::app(
     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;
     }
 
@@ -377,11 +376,16 @@ bool host_context_test::mixed(
 {
     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;
     }
 
index 90f2912..d5667fd 100644 (file)
@@ -25,7 +25,6 @@ namespace host_context_test
     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);
index 8f854f6..ded2ffc 100644 (file)
@@ -99,7 +99,8 @@ int main(const int argc, const pal::char_t *argv[])
         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)
         {
index dae88c6..8a2f638 100644 (file)
@@ -39,6 +39,12 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.NativeHosting
             public const string Secondary = "[SECONDARY] ";
         }
 
+        public enum CommandLine
+        {
+            AppPath,
+            Exec,
+        }
+
         private const string HostContextArg = "host_context";
         private const string PropertyValueFromHost = "VALUE_FROM_HOST";
 
@@ -57,21 +63,35 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.NativeHosting
         }
 
         [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;
@@ -92,15 +112,33 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.NativeHosting
                 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")