Skip to content

Commit

Permalink
[Windows] Improve console handling and execute/create_process.
Browse files Browse the repository at this point in the history
Always build with the GUI subsystem.
Redirect stdout and stderr output to the parent process console.
Use CreateProcessW for blocking `execute` calls with piped stdout and stderr (prevent console windows for popping up when used with the GUI subsystem build, and have more consistent behavior with `create_process`).
Add `open_console` argument to the `execute` and `create_process` to open a new console window.
Remove `interface/editor/hide_console_window` editor setting.
Remove `Toggle System Console` menu option.
Remove `set_console_visible` and `is_console_visible` functions.
  • Loading branch information
bruvzg committed Dec 18, 2021
1 parent b0e9371 commit ea5bb8b
Show file tree
Hide file tree
Showing 29 changed files with 116 additions and 258 deletions.
12 changes: 6 additions & 6 deletions core/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,14 @@ Error OS::shell_open(String p_uri) {
return ::OS::get_singleton()->shell_open(p_uri);
}

int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr) {
int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) {
List<String> args;
for (int i = 0; i < p_arguments.size(); i++) {
args.push_back(p_arguments[i]);
}
String pipe;
int exitcode = 0;
Error err = ::OS::get_singleton()->execute(p_path, args, &pipe, &exitcode, p_read_stderr);
Error err = ::OS::get_singleton()->execute(p_path, args, &pipe, &exitcode, p_read_stderr, nullptr, p_open_console);
r_output.push_back(pipe);
if (err != OK) {
return -1;
Expand All @@ -252,13 +252,13 @@ int OS::create_instance(const Vector<String> &p_arguments) {
return pid;
}

int OS::create_process(const String &p_path, const Vector<String> &p_arguments) {
int OS::create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console) {
List<String> args;
for (int i = 0; i < p_arguments.size(); i++) {
args.push_back(p_arguments[i]);
}
::OS::ProcessID pid = 0;
Error err = ::OS::get_singleton()->create_process(p_path, args, &pid);
Error err = ::OS::get_singleton()->create_process(p_path, args, &pid, p_open_console);
if (err != OK) {
return -1;
}
Expand Down Expand Up @@ -557,8 +557,8 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_processor_count"), &OS::get_processor_count);

ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path);
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr"), &OS::execute, DEFVAL(Array()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_process", "path", "arguments"), &OS::create_process);
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL(Array()), DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_instance", "arguments"), &OS::create_instance);
ClassDB::bind_method(D_METHOD("kill", "pid"), &OS::kill);
ClassDB::bind_method(D_METHOD("shell_open", "uri"), &OS::shell_open);
Expand Down
4 changes: 2 additions & 2 deletions core/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ class OS : public Object {
void crash(const String &p_message);

String get_executable_path() const;
int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false);
int create_process(const String &p_path, const Vector<String> &p_arguments);
int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false, bool p_open_console = false);
int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false);
int create_instance(const Vector<String> &p_arguments);
Error kill(int p_pid);
Error shell_open(String p_uri);
Expand Down
4 changes: 2 additions & 2 deletions core/os/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ class OS {
virtual int get_low_processor_usage_mode_sleep_usec() const;

virtual String get_executable_path() const;
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) = 0;
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) = 0;
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) = 0;
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) = 0;
virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) { return create_process(get_executable_path(), p_arguments, r_child_id); };
virtual Error kill(const ProcessID &p_pid) = 0;
virtual int get_process_id() const;
Expand Down
29 changes: 8 additions & 21 deletions doc/classes/DisplayServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@
[b]Note:[/b] This method is only implemented on Linux.
</description>
</method>
<method name="console_set_visible">
<return type="void" />
<argument index="0" name="console_visible" type="bool" />
<description>
</description>
</method>
<method name="create_sub_window">
<return type="int" />
<argument index="0" name="mode" type="int" enum="DisplayServer.WindowMode" />
Expand Down Expand Up @@ -281,11 +275,6 @@
<description>
</description>
</method>
<method name="is_console_visible" qualifiers="const">
<return type="bool" />
<description>
</description>
</method>
<method name="keyboard_get_current_layout" qualifiers="const">
<return type="int" />
<description>
Expand Down Expand Up @@ -803,23 +792,21 @@
</constant>
<constant name="FEATURE_NATIVE_DIALOG" value="9" enum="Feature">
</constant>
<constant name="FEATURE_CONSOLE_WINDOW" value="10" enum="Feature">
</constant>
<constant name="FEATURE_IME" value="11" enum="Feature">
<constant name="FEATURE_IME" value="10" enum="Feature">
</constant>
<constant name="FEATURE_WINDOW_TRANSPARENCY" value="12" enum="Feature">
<constant name="FEATURE_WINDOW_TRANSPARENCY" value="11" enum="Feature">
</constant>
<constant name="FEATURE_HIDPI" value="13" enum="Feature">
<constant name="FEATURE_HIDPI" value="12" enum="Feature">
</constant>
<constant name="FEATURE_ICON" value="14" enum="Feature">
<constant name="FEATURE_ICON" value="13" enum="Feature">
</constant>
<constant name="FEATURE_NATIVE_ICON" value="15" enum="Feature">
<constant name="FEATURE_NATIVE_ICON" value="14" enum="Feature">
</constant>
<constant name="FEATURE_ORIENTATION" value="16" enum="Feature">
<constant name="FEATURE_ORIENTATION" value="15" enum="Feature">
</constant>
<constant name="FEATURE_SWAP_BUFFERS" value="17" enum="Feature">
<constant name="FEATURE_SWAP_BUFFERS" value="16" enum="Feature">
</constant>
<constant name="FEATURE_CLIPBOARD_PRIMARY" value="19" enum="Feature">
<constant name="FEATURE_CLIPBOARD_PRIMARY" value="18" enum="Feature">
</constant>
<constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
Makes the mouse cursor visible if it is hidden.
Expand Down
6 changes: 5 additions & 1 deletion doc/classes/OS.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@
<return type="int" />
<argument index="0" name="path" type="String" />
<argument index="1" name="arguments" type="PackedStringArray" />
<argument index="2" name="open_console" type="bool" default="false" />
<description>
Creates a new process that runs independently of Godot. It will not terminate if Godot terminates. The path specified in [code]path[/code] must exist and be executable file or macOS .app bundle. Platform path resolution will be used. The [code]arguments[/code] are used in the given order and separated by a space.
On Windows, if [code]open_console[/code] is [code]true[/code] and process is console app, new terminal window will be opened, it's ignored on other platforms.
If the process creation succeeds, the method will return the new process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). If the process creation fails, the method will return [code]-1[/code].
For example, running another instance of the project:
[codeblocks]
Expand Down Expand Up @@ -109,8 +111,10 @@
<argument index="1" name="arguments" type="PackedStringArray" />
<argument index="2" name="output" type="Array" default="[]" />
<argument index="3" name="read_stderr" type="bool" default="false" />
<argument index="4" name="open_console" type="bool" default="false" />
<description>
Executes a command. The file specified in [code]path[/code] must exist and be executable. Platform path resolution will be used. The [code]arguments[/code] are used in the given order and separated by a space. If an [code]output[/code] [Array] is provided, the complete shell output of the process will be appended as a single [String] element in [code]output[/code]. If [code]read_stderr[/code] is [code]true[/code], the output to the standard error stream will be included too.
On Windows, if [code]open_console[/code] is [code]true[/code] and process is console app, new terminal window will be opened, it's ignored on other platforms.
If the command is successfully executed, the method will return the exit code of the command, or [code]-1[/code] if it fails.
[b]Note:[/b] The Godot thread will pause its execution until the executed command terminates. Use [Thread] to create a separate thread that will not pause the Godot thread, or use [method create_process] to create a completely independent process.
For example, to retrieve a list of the working directory's contents:
Expand All @@ -124,7 +128,7 @@
int exitCode = OS.Execute("ls", new string[] {"-l", "/tmp"}, output);
[/csharp]
[/codeblocks]
To execute a composite command, a platform-specific shell can be invoked. For example:
If you wish to access a shell built-in or perform a composite command, a platform-specific shell can be invoked. For example:
[codeblocks]
[gdscript]
var output = []
Expand Down
4 changes: 2 additions & 2 deletions drivers/unix/os_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ uint64_t OS_Unix::get_ticks_usec() const {
return longtime;
}

Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
#ifdef __EMSCRIPTEN__
// Don't compile this code at all to avoid undefined references.
// Actual virtual call goes to OS_JavaScript.
Expand Down Expand Up @@ -318,7 +318,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, St
#endif
}

Error OS_Unix::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) {
Error OS_Unix::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
#ifdef __EMSCRIPTEN__
// Don't compile this code at all to avoid undefined references.
// Actual virtual call goes to OS_JavaScript.
Expand Down
4 changes: 2 additions & 2 deletions drivers/unix/os_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ class OS_Unix : public OS {
virtual void delay_usec(uint32_t p_usec) const override;
virtual uint64_t get_ticks_usec() const override;

virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override;
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override;
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
virtual Error kill(const ProcessID &p_pid) override;
virtual int get_process_id() const override;

Expand Down
10 changes: 0 additions & 10 deletions editor/editor_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2852,11 +2852,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
DisplayServer::get_singleton()->window_set_mode(DisplayServer::get_singleton()->window_get_mode() == DisplayServer::WINDOW_MODE_FULLSCREEN ? DisplayServer::WINDOW_MODE_WINDOWED : DisplayServer::WINDOW_MODE_FULLSCREEN);

} break;
case SETTINGS_TOGGLE_CONSOLE: {
bool was_visible = DisplayServer::get_singleton()->is_console_visible();
DisplayServer::get_singleton()->console_set_visible(!was_visible);
EditorSettings::get_singleton()->set_setting("interface/editor/hide_console_window", was_visible);
} break;
case EDITOR_SCREENSHOT: {
screenshot_timer->start();
} break;
Expand Down Expand Up @@ -6500,11 +6495,6 @@ EditorNode::EditorNode() {
ED_SHORTCUT_OVERRIDE("editor/fullscreen_mode", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::F);
p->add_shortcut(ED_GET_SHORTCUT("editor/fullscreen_mode"), SETTINGS_TOGGLE_FULLSCREEN);

#if defined(WINDOWS_ENABLED) && defined(WINDOWS_SUBSYSTEM_CONSOLE)
// The console can only be toggled if the application was built for the console subsystem,
// not the GUI subsystem.
p->add_item(TTR("Toggle System Console"), SETTINGS_TOGGLE_CONSOLE);
#endif
p->add_separator();

if (OS::get_singleton()->get_data_path() == OS::get_singleton()->get_config_path()) {
Expand Down
1 change: 0 additions & 1 deletion editor/editor_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ class EditorNode : public Node {
SETTINGS_MANAGE_FEATURE_PROFILES,
SETTINGS_INSTALL_ANDROID_BUILD_TEMPLATE,
SETTINGS_PICK_MAIN_SCENE,
SETTINGS_TOGGLE_CONSOLE,
SETTINGS_TOGGLE_FULLSCREEN,
SETTINGS_HELP,
SCENE_TAB_CLOSE,
Expand Down
1 change: 0 additions & 1 deletion editor/editor_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("interface/editor/separate_distraction_mode", false);
_initial_set("interface/editor/automatically_open_screenshots", true);
EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/single_window_mode", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
_initial_set("interface/editor/hide_console_window", false);
_initial_set("interface/editor/mouse_extra_buttons_navigate_history", true);
_initial_set("interface/editor/save_each_scene_on_quit", true); // Regression
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/show_internal_errors_in_toast_notifications", 0, "Auto,Enabled,Disabled")
Expand Down
7 changes: 0 additions & 7 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2529,13 +2529,6 @@ bool Main::start() {
}

if (project_manager || editor) {
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CONSOLE_WINDOW)) {
// Hide console window if requested (Windows-only).
bool hide_console = EditorSettings::get_singleton()->get_setting(
"interface/editor/hide_console_window");
DisplayServer::get_singleton()->console_set_visible(!hide_console);
}

// Load SSL Certificates from Editor Settings (or builtin)
Crypto::load_default_certificates(
EditorSettings::get_singleton()->get_setting("network/ssl/editor_ssl_certificates").operator String());
Expand Down
1 change: 0 additions & 1 deletion platform/android/display_server_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ DisplayServerAndroid *DisplayServerAndroid::get_singleton() {

bool DisplayServerAndroid::has_feature(Feature p_feature) const {
switch (p_feature) {
//case FEATURE_CONSOLE_WINDOW:
case FEATURE_CURSOR_SHAPE:
//case FEATURE_CUSTOM_CURSOR_SHAPE:
//case FEATURE_GLOBAL_MENU:
Expand Down
1 change: 0 additions & 1 deletion platform/iphone/display_server_iphone.mm
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,6 @@

bool DisplayServerIPhone::has_feature(Feature p_feature) const {
switch (p_feature) {
// case FEATURE_CONSOLE_WINDOW:
// case FEATURE_CURSOR_SHAPE:
// case FEATURE_CUSTOM_CURSOR_SHAPE:
// case FEATURE_GLOBAL_MENU:
Expand Down
1 change: 0 additions & 1 deletion platform/javascript/display_server_javascript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,6 @@ DisplayServerJavaScript::~DisplayServerJavaScript() {

bool DisplayServerJavaScript::has_feature(Feature p_feature) const {
switch (p_feature) {
//case FEATURE_CONSOLE_WINDOW:
//case FEATURE_GLOBAL_MENU:
//case FEATURE_HIDPI:
//case FEATURE_IME:
Expand Down
4 changes: 2 additions & 2 deletions platform/javascript/os_javascript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@ void OS_JavaScript::finalize() {

// Miscellaneous

Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
return create_process(p_path, p_arguments);
}

Error OS_JavaScript::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) {
Error OS_JavaScript::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
Array args;
for (const String &E : p_arguments) {
args.push_back(E);
Expand Down
4 changes: 2 additions & 2 deletions platform/javascript/os_javascript.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ class OS_JavaScript : public OS_Unix {
MainLoop *get_main_loop() const override;
bool main_loop_iterate();

Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override;
Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;
Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override;
Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
Error kill(const ProcessID &p_pid) override;
int get_process_id() const override;
int get_processor_count() const override;
Expand Down
3 changes: 0 additions & 3 deletions platform/osx/display_server_osx.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,6 @@ class DisplayServerOSX : public DisplayServer {
virtual void set_native_icon(const String &p_filename) override;
virtual void set_icon(const Ref<Image> &p_icon) override;

virtual void console_set_visible(bool p_enabled) override;
virtual bool is_console_visible() const override;

static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
static Vector<String> get_rendering_drivers_func();

Expand Down
9 changes: 0 additions & 9 deletions platform/osx/display_server_osx.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1480,7 +1480,6 @@ - (BOOL)canBecomeMainWindow {
case FEATURE_CURSOR_SHAPE:
case FEATURE_CUSTOM_CURSOR_SHAPE:
case FEATURE_NATIVE_DIALOG:
//case FEATURE_CONSOLE_WINDOW:
case FEATURE_IME:
case FEATURE_WINDOW_TRANSPARENCY:
case FEATURE_HIDPI:
Expand Down Expand Up @@ -3682,14 +3681,6 @@ void _update_keyboard_layouts() {
#endif
}

void DisplayServerOSX::console_set_visible(bool p_enabled) {
//TODO - open terminal and redirect
}

bool DisplayServerOSX::is_console_visible() const {
return isatty(STDIN_FILENO);
}

DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);

Expand Down
2 changes: 1 addition & 1 deletion platform/osx/os_osx.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class OS_OSX : public OS_Unix {
String get_locale() const override;

virtual String get_executable_path() const override;
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;

virtual String get_unique_id() const override; //++
Expand Down
10 changes: 5 additions & 5 deletions platform/osx/os_osx.mm
Original file line number Diff line number Diff line change
Expand Up @@ -497,13 +497,13 @@ _FORCE_INLINE_ String _get_framework_executable(const String p_path) {
if (nsappname != nil) {
String path;
path.parse_utf8([[[NSBundle mainBundle] bundlePath] UTF8String]);
return create_process(path, p_arguments, r_child_id);
return create_process(path, p_arguments, r_child_id, false);
} else {
return create_process(get_executable_path(), p_arguments, r_child_id);
return create_process(get_executable_path(), p_arguments, r_child_id, false);
}
}

Error OS_OSX::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) {
Error OS_OSX::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
if (@available(macOS 10.15, *)) {
// Use NSWorkspace if path is an .app bundle.
NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())];
Expand Down Expand Up @@ -542,10 +542,10 @@ _FORCE_INLINE_ String _get_framework_executable(const String p_path) {

return err;
} else {
return OS_Unix::create_process(p_path, p_arguments, r_child_id);
return OS_Unix::create_process(p_path, p_arguments, r_child_id, p_open_console);
}
} else {
return OS_Unix::create_process(p_path, p_arguments, r_child_id);
return OS_Unix::create_process(p_path, p_arguments, r_child_id, p_open_console);
}
}

Expand Down
Loading

0 comments on commit ea5bb8b

Please sign in to comment.