Après un rapide coup d'œil au code source de Godot 4 et un peu de débogage, j'ai trouvé pas mal de paramètres de ligne de commande. dans widechar_main
Error err = Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]);
Dans Main::setup, chaque paramètre de ligne de commande est ajouté aux arguments List<Stirng>, et les paramètres de ligne de commande liés à la plate-forme sont obtenus via OS::get_singleton()->get_cmdline_platform_args(), puis les arguments sont traités élément par élément.
référence de la ligne de commande
Options générales - Affiche une liste d'options de ligne de commande
|
Affiche une liste d'options de ligne de commande. |
if (I->get() == "-h" || I->get() == "--help" || I->get() == "/?") { // display help
show_help = true;
exit_code = ERR_HELP; // Hack to force an early exit in `main()` with a success code.
goto error;
}
puis appelez print_help
void Main::print_help(const char *p_binary) {
print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE));
OS::get_singleton()->print("Free and open source software under the terms of the MIT license.\n");
OS::get_singleton()->print("(c) 2014-present Godot Engine contributors.\n");
OS::get_singleton()->print("(c) 2007-2014 Juan Linietsky, Ariel Manzur.\n");
OS::get_singleton()->print("\n");
OS::get_singleton()->print("Usage: %s [options] [path to scene or 'project.godot' file]\n", p_binary);
OS::get_singleton()->print("\n");
OS::get_singleton()->print("General options:\n");
OS::get_singleton()->print(" -h, --help Display this help message.\n");
OS::get_singleton()->print(" --version Display the version string.\n");
OS::get_singleton()->print(" -v, --verbose Use verbose stdout mode.\n");
OS::get_singleton()->print(" -q, --quiet Quiet mode, silences stdout messages. Errors are still displayed.\n");
OS::get_singleton()->print("\n");
OS::get_singleton()->print("Run options:\n");
OS::get_singleton()->print(" --, ++ Separator for user-provided arguments. Following arguments are not used by the engine, but can be read from `OS.get_cmdline_user_args()`.\n");
#ifdef TOOLS_ENABLED
OS::get_singleton()->print(" -e, --editor Start the editor instead of running the scene.\n");
OS::get_singleton()->print(" -p, --project-manager Start the project manager, even if a project is auto-detected.\n");
OS::get_singleton()->print(" --debug-server <uri> Start the editor debug server (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007)\n");
#endif
OS::get_singleton()->print(" --quit Quit after the first iteration.\n");
OS::get_singleton()->print(" -l, --language <locale> Use a specific locale (<locale> being a two-letter code).\n");
OS::get_singleton()->print(" --path <directory> Path to a project (<directory> must contain a 'project.godot' file).\n");
OS::get_singleton()->print(" -u, --upwards Scan folders upwards for project.godot file.\n");
OS::get_singleton()->print(" --main-pack <file> Path to a pack (.pck) file to load.\n");
OS::get_singleton()->print(" --render-thread <mode> Render thread mode ['unsafe', 'safe', 'separate'].\n");
OS::get_singleton()->print(" --remote-fs <address> Remote filesystem (<host/IP>[:<port>] address).\n");
OS::get_singleton()->print(" --remote-fs-password <password> Password for remote filesystem.\n");
OS::get_singleton()->print(" --audio-driver <driver> Audio driver [");
for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
if (i > 0) {
OS::get_singleton()->print(", ");
}
OS::get_singleton()->print("'%s'", AudioDriverManager::get_driver(i)->get_name());
}
OS::get_singleton()->print("].\n");
OS::get_singleton()->print(" --display-driver <driver> Display driver (and rendering driver) [");
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
if (i > 0) {
OS::get_singleton()->print(", ");
}
OS::get_singleton()->print("'%s' (", DisplayServer::get_create_function_name(i));
Vector<String> rd = DisplayServer::get_create_function_rendering_drivers(i);
for (int j = 0; j < rd.size(); j++) {
if (j > 0) {
OS::get_singleton()->print(", ");
}
OS::get_singleton()->print("'%s'", rd[j].utf8().get_data());
}
OS::get_singleton()->print(")");
}
OS::get_singleton()->print("].\n");
OS::get_singleton()->print(" --rendering-method <renderer> Renderer name. Requires driver support.\n");
OS::get_singleton()->print(" --rendering-driver <driver> Rendering driver (depends on display driver).\n");
OS::get_singleton()->print(" --gpu-index <device_index> Use a specific GPU (run with --verbose to get available device list).\n");
OS::get_singleton()->print(" --text-driver <driver> Text driver (Fonts, BiDi, shaping).\n");
OS::get_singleton()->print(" --tablet-driver <driver> Pen tablet input driver.\n");
OS::get_singleton()->print(" --headless Enable headless mode (--display-driver headless --audio-driver Dummy). Useful for servers and with --script.\n");
OS::get_singleton()->print(" --write-movie <file> Writes a video to the specified path (usually with .avi or .png extension).\n");
OS::get_singleton()->print(" --fixed-fps is forced when enabled, but it can be used to change movie FPS.\n");
OS::get_singleton()->print(" --disable-vsync can speed up movie writing but makes interaction more difficult.\n");
OS::get_singleton()->print("\n");
OS::get_singleton()->print("Display options:\n");
OS::get_singleton()->print(" -f, --fullscreen Request fullscreen mode.\n");
OS::get_singleton()->print(" -m, --maximized Request a maximized window.\n");
OS::get_singleton()->print(" -w, --windowed Request windowed mode.\n");
OS::get_singleton()->print(" -t, --always-on-top Request an always-on-top window.\n");
OS::get_singleton()->print(" --resolution <W>x<H> Request window resolution.\n");
OS::get_singleton()->print(" --position <X>,<Y> Request window position (if set, screen argument is ignored).\n");
OS::get_singleton()->print(" --screen <N> Request window screen.\n");
OS::get_singleton()->print(" --single-window Use a single window (no separate subwindows).\n");
OS::get_singleton()->print(" --xr-mode <mode> Select XR (Extended Reality) mode ['default', 'off', 'on'].\n");
OS::get_singleton()->print("\n");
OS::get_singleton()->print("Debug options:\n");
OS::get_singleton()->print(" -d, --debug Debug (local stdout debugger).\n");
OS::get_singleton()->print(" -b, --breakpoints Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n");
OS::get_singleton()->print(" --profiling Enable profiling in the script debugger.\n");
OS::get_singleton()->print(" --gpu-profile Show a GPU profile of the tasks that took the most time during frame rendering.\n");
OS::get_singleton()->print(" --gpu-validation Enable graphics API validation layers for debugging.\n");
#if DEBUG_ENABLED
OS::get_singleton()->print(" --gpu-abort Abort on graphics API usage errors (usually validation layer errors). May help see the problem if your system freezes.\n");
#endif
OS::get_singleton()->print(" --remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n");
#if defined(DEBUG_ENABLED)
OS::get_singleton()->print(" --debug-collisions Show collision shapes when running the scene.\n");
OS::get_singleton()->print(" --debug-paths Show path lines when running the scene.\n");
OS::get_singleton()->print(" --debug-navigation Show navigation polygons when running the scene.\n");
OS::get_singleton()->print(" --debug-stringnames Print all StringName allocations to stdout when the engine quits.\n");
#endif
OS::get_singleton()->print(" --frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds).\n");
OS::get_singleton()->print(" --time-scale <scale> Force time scale (higher values are faster, 1.0 is normal speed).\n");
OS::get_singleton()->print(" --disable-vsync Forces disabling of vertical synchronization, even if enabled in the project settings. Does not override driver-level V-Sync enforcement.\n");
OS::get_singleton()->print(" --disable-render-loop Disable render loop so rendering only occurs when called explicitly from script.\n");
OS::get_singleton()->print(" --disable-crash-handler Disable crash handler when supported by the platform code.\n");
OS::get_singleton()->print(" --fixed-fps <fps> Force a fixed number of frames per second. This setting disables real-time synchronization.\n");
OS::get_singleton()->print(" --print-fps Print the frames per second to the stdout.\n");
OS::get_singleton()->print("\n");
OS::get_singleton()->print("Standalone tools:\n");
OS::get_singleton()->print(" -s, --script <script> Run a script.\n");
OS::get_singleton()->print(" --check-only Only parse for errors and quit (use with --script).\n");
#ifdef TOOLS_ENABLED
OS::get_singleton()->print(" --export-release <preset> <path> Export the project in release mode using the given preset and output path. The preset name should match one defined in export_presets.cfg.\n");
OS::get_singleton()->print(" <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe').\n");
OS::get_singleton()->print(" The target directory must exist.\n");
OS::get_singleton()->print(" --export-debug <preset> <path> Export the project in debug mode using the given preset and output path. See --export-release description for other considerations.\n");
OS::get_singleton()->print(" --export-pack <preset> <path> Export the project data only using the given preset and output path. The <path> extension determines whether it will be in PCK or ZIP format.\n");
#ifndef DISABLE_DEPRECATED
OS::get_singleton()->print(" --convert-3to4 [<max_file_kb>] [<max_line_size>]\n");
OS::get_singleton()->print(" Converts project from Godot 3.x to Godot 4.x.\n");
OS::get_singleton()->print(" --validate-conversion-3to4 [<max_file_kb>] [<max_line_size>]\n");
OS::get_singleton()->print(" Shows what elements will be renamed when converting project from Godot 3.x to Godot 4.x.\n");
#endif // DISABLE_DEPRECATED
OS::get_singleton()->print(" --doctool [<path>] Dump the engine API reference to the given <path> (defaults to current dir) in XML format, merging if existing files are found.\n");
OS::get_singleton()->print(" --no-docbase Disallow dumping the base types (used with --doctool).\n");
OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n");
OS::get_singleton()->print(" --dump-gdextension-interface Generate GDExtension header file 'gdextension_interface.h' in the current folder. This file is the base file required to implement a GDExtension.\n");
OS::get_singleton()->print(" --dump-extension-api Generate JSON dump of the Godot API for GDExtension bindings named 'extension_api.json' in the current folder.\n");
OS::get_singleton()->print(" --startup-benchmark Benchmark the startup time and print it to console.\n");
OS::get_singleton()->print(" --startup-benchmark-file <path> Benchmark the startup time and save it to a given file in JSON format.\n");
#ifdef TESTS_ENABLED
OS::get_singleton()->print(" --test [--help] Run unit tests. Use --test --help for more information.\n");
#endif
#endif
OS::get_singleton()->print("\n");
}
Enfin, diverses informations sur les paramètres seront affichées dans la fenêtre DOS
Usage: D:\Godot Engine\bin\godot.windows.editor.x86_32.exe [options] [path to scene or 'project.godot' file]
General options:
-h, --help Display this help message.
--version Display the version string.
-v, --verbose Use verbose stdout mode.
-q, --quiet Quiet mode, silences stdout messages. Errors are still displayed.
Run options:
--, ++ Separator for user-provided arguments. Following arguments are not used by the engine, but can be read from `OS.get_cmdline_user_args()`.
-e, --editor Start the editor instead of running the scene.
-p, --project-manager Start the project manager, even if a project is auto-detected.
--debug-server <uri> Start the editor debug server (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007)
--quit Quit after the first iteration.
-l, --language <locale> Use a specific locale (<locale> being a two-letter code).
--path <directory> Path to a project (<directory> must contain a 'project.godot' file).
-u, --upwards Scan folders upwards for project.godot file.
--main-pack <file> Path to a pack (.pck) file to load.
--render-thread <mode> Render thread mode ['unsafe', 'safe', 'separate'].
--remote-fs <address> Remote filesystem (<host/IP>[:<port>] address).
--remote-fs-password <password> Password for remote filesystem.
--audio-driver <driver> Audio driver ['WASAPI', 'Dummy'].
--display-driver <driver> Display driver (and rendering driver) ['windows' ('vulkan', 'opengl3'), 'headless' ('dummy')].
--rendering-method <renderer> Renderer name. Requires driver support.
--rendering-driver <driver> Rendering driver (depends on display driver).
--gpu-index <device_index> Use a specific GPU (run with --verbose to get available device list).
--text-driver <driver> Text driver (Fonts, BiDi, shaping).
--tablet-driver <driver> Pen tablet input driver.
--headless Enable headless mode (--display-driver headless --audio-driver Dummy). Useful for servers and with --script.
--write-movie <file> Writes a video to the specified path (usually with .avi or .png extension).
--fixed-fps is forced when enabled, but it can be used to change movie FPS.
--disable-vsync can speed up movie writing but makes interaction more difficult.
Display options:
-f, --fullscreen Request fullscreen mode.
-m, --maximized Request a maximized window.
-w, --windowed Request windowed mode.
-t, --always-on-top Request an always-on-top window.
--resolution <W>x<H> Request window resolution.
--position <X>,<Y> Request window position (if set, screen argument is ignored).
--screen <N> Request window screen.
--single-window Use a single window (no separate subwindows).
--xr-mode <mode> Select XR (Extended Reality) mode ['default', 'off', 'on'].
Debug options:
-d, --debug Debug (local stdout debugger).
-b, --breakpoints Breakpoint list as source::line comma-separated pairs, no spaces (use %20 instead).
--profiling Enable profiling in the script debugger.
--gpu-profile Show a GPU profile of the tasks that took the most time during frame rendering.
--gpu-validation Enable graphics API validation layers for debugging.
--gpu-abort Abort on graphics API usage errors (usually validation layer errors). May help see the problem if your system freezes.
--remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).
--debug-collisions Show collision shapes when running the scene.
--debug-paths Show path lines when running the scene.
--debug-navigation Show navigation polygons when running the scene.
--debug-stringnames Print all StringName allocations to stdout when the engine quits.
--frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds).
--time-scale <scale> Force time scale (higher values are faster, 1.0 is normal speed).
--disable-vsync Forces disabling of vertical synchronization, even if enabled in the project settings. Does not override driver-level V-Sync enforcement.
--disable-render-loop Disable render loop so rendering only occurs when called explicitly from script.
--disable-crash-handler Disable crash handler when supported by the platform code.
--fixed-fps <fps> Force a fixed number of frames per second. This setting disables real-time synchronization.
--print-fps Print the frames per second to the stdout.
Standalone tools:
-s, --script <script> Run a script.
--check-only Only parse for errors and quit (use with --script).
--export-release <preset> <path> Export the project in release mode using the given preset and output path. The preset name should match one defined in export_presets.cfg.
<path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe').
The target directory must exist.
--export-debug <preset> <path> Export the project in debug mode using the given preset and output path. See --export-release description for other considerations.
--export-pack <preset> <path> Export the project data only using the given preset and output path. The <path> extension determines whether it will be in PCK or ZIP format.
--convert-3to4 [<max_file_kb>] [<max_line_size>]
Converts project from Godot 3.x to Godot 4.x.
--validate-conversion-3to4 [<max_file_kb>] [<max_line_size>]
Shows what elements will be renamed when converting project from Godot 3.x to Godot 4.x.
--doctool [<path>] Dump the engine API reference to the given <path> (defaults to current dir) in XML format, merging if existing files are found.
--no-docbase Disallow dumping the base types (used with --doctool).
--build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.
--dump-gdextension-interface Generate GDExtension header file 'gdextension_interface.h' in the current folder. This file is the base file required to implement a GDExtension.
--dump-extension-api Generate JSON dump of the Godot API for GDExtension bindings named 'extension_api.json' in the current folder.
--startup-benchmark Benchmark the startup time and print it to console.
--startup-benchmark-file <path> Benchmark the startup time and save it to a given file in JSON format.
Options générales - Afficher la chaîne de version
|
Affiche la chaîne de version. |
else if (I->get() == "--version") {
print_line(get_full_version_string());
exit_code = ERR_HELP; // Hack to force an early exit in `main()` with a success code.
goto error;
}
À peu près ainsi.
résumé
Options générales
Commande |
décrire |
|
Affiche une liste d'options de ligne de commande. |
|
Affiche la chaîne de version. |
|
Utilisez le mode de sortie détaillé. |
|
Mode silencieux, informations de sortie silencieuses. Mais les erreurs seront toujours affichées. |
option d'exécution
Commande |
décrire |
|
Démarre l'éditeur sans exécuter la scène ( les outils doivent être activés ). |
|
Lancer le gestionnaire de projet, même si un projet a été détecté automatiquement ( les outils doivent être activés). |
|
Quitter après la première itération. |
|
Utilisez les paramètres régionaux spécifiés (<locale> est un code à deux lettres). Voir Paramètres régionaux pour plus de détails . |
|
Le chemin d'accès au projet (le répertoire <répertoire> doit contenir un fichier "project.godot"). |
|
Scannez vers le haut pour le fichier "project.godot" dans le dossier. |
|
Chemin d'accès au fichier de package (.pck) à charger. |
|
Rendu en mode thread ('unsafe', 'safe', 'separate'). Lisez Mode thread pour plus de détails. |
|
Système de fichiers distant ( |
|
Pilotes audio. Utilisez d'abord |
|
Pilotes vidéo Utilisez d'abord |
option d'affichage
Commande |
décrire |
|
Demande d'utilisation du mode plein écran. |
|
Demandez une fenêtre maximisée. |
|
Nécessite le mode fenêtré. |
|
Demande une fenêtre toujours visible. |
|
Demander la résolution de la fenêtre. |
|
Spécifie la position de l'écran. |
|
Forcer le mode basse résolution (uniquement disponible sur macOS et Windows). |
|
|
options de débogage
Remarque
Le mode débogage ne fonctionne que dans l'éditeur et les modèles de sortie de débogage (cela nécessite d'utiliser debug
ou release_debug
de créer la cible, lisez Cibles pour plus d'informations).
Commande |
décrire |
|
debug (débogueur stdout local). |
|
Listes de points d'arrêt sous forme de paires source::line séparées par des virgules sans espaces (utilisez %%20 à la place). |
|
Activez le profilage dans le débogueur de script. |
|
remotedebug ( |
|
Affiche la forme de la zone de collision lors de l'exécution de la scène. |
|
Afficher la navigation du polygone lors de l'exécution de la scène. |
|
Simulez une charge CPU élevée (délai <ms> millisecondes par image). |
|
Forcer la mise à l'échelle du temps (plus la valeur est grande, plus la vitesse est rapide, 1,0 est la vitesse normale). |
|
Désactive la boucle de rendu afin que le rendu ne se produise que lorsqu'il est explicitement appelé à partir du script. |
|
Désactivez le gestionnaire de crash lorsque le code de la plate-forme le prend en charge. |
|
Force un nombre fixe d'images par seconde. Ce paramètre désactive la synchronisation en temps réel. |
|
Imprimer le nombre d'images par seconde sur la sortie standard. |
outil séparé
Commande |
décrire |
|
Exécutez le script. |
|
Analyser uniquement les erreurs et quitter ( |
|
Exportez le projet à l'aide de la plate-forme d'exportation indiquée. Le package principal n'est exporté que si le chemin se termine par .pck ou .zip ( les outils doivent être activés ). |
|
Comme , mais en utilisant le modèle de débogage ( les outils |
|
将引擎 API 参考以 XML 格式转储到给定的 <路径> 中,如果发现现有文件则合并(必须已启用 tools)。 |
|
禁止转储基本类型(和 |
|
构建脚本解决方案(例如用于构建C#项目, 必须启用 tools). |
|
为GDNative绑定生成Godot API的JSON输出(必须启用 tools). |
|
运行单元测试. 可以先用 |
|
像 |
其实,也不用太过于纠结钻研各命令行参数的含义,用的多了,就清楚了。
Godot运行方式
在调试过程中,发现Godot运行后打开工程管理器(Project Manager),选择目标工程后,进入编辑器,结果调试过程结束了。
经过几次折腾,大致明白Godot运行方式,包括工程管理器、编辑器、场景运行三种。这三种方式可以通过命令行参数来决定。
缺省情况下,为工程管理器模式
在VS中配置调试命令参数为-p,即进入工程管理器模式
如果要直接运行或调试编辑器,可配置命令参数为--path C:\Users\Administrator\Downloads\dodge_assets\dodge_assets -e ,将直接打开指定目录下的Godot工程,进行编辑
直接运行工程,就直接指定--path路径,不带-p/-e参数即可
Mode de fonctionnement Godot avec console
Godot supporte le mode console, le code source console_wrapper_windows.cpp, après avoir étudié le code source, je ne l'ai pas très bien compris, principalement parce que plusieurs des fonctions principales n'ont jamais été utilisées. Cependant, que cette fonction soit apprise ou non n'aura aucun effet sur le suivi, car j'ai l'impression que l'ajout d'une console signifie augmenter la sortie du journal. Dans l'article précédent, la sortie du fichier journal a été réalisée, il est donc normal de ne pas utiliser la console.
int main(int argc, char *argv[]) {
// Get executable name.
WCHAR exe_name[MAX_PATH] = {};
if (!GetModuleFileNameW(nullptr, exe_name, MAX_PATH)) {
wprintf(L"GetModuleFileName failed, error %d\n", GetLastError());
return -1;
}
// Get product name from the resources and set console title.
DWORD ver_info_handle = 0;
DWORD ver_info_size = GetFileVersionInfoSizeW(exe_name, &ver_info_handle);
if (ver_info_size > 0) {
LPBYTE ver_info = (LPBYTE)malloc(ver_info_size);
if (ver_info) {
if (GetFileVersionInfoW(exe_name, ver_info_handle, ver_info_size, ver_info)) {
LPCWSTR text_ptr = nullptr;
UINT text_size = 0;
if (VerQueryValueW(ver_info, L"\\StringFileInfo\\040904b0\\ProductName", (void **)&text_ptr, &text_size) && (text_size > 0)) {
SetConsoleTitleW(text_ptr);
}
}
free(ver_info);
}
}
// Enable virtual terminal sequences processing.
HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD out_mode = ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(stdout_handle, out_mode);
// Find main executable name and check if it exist.
static PCWSTR exe_renames[] = {
L".console.exe",
L"_console.exe",
L" console.exe",
L"console.exe",
nullptr,
};
bool rename_found = false;
for (int i = 0; exe_renames[i]; i++) {
PWSTR c = StrRStrIW(exe_name, nullptr, exe_renames[i]);
if (c) {
CopyMemory(c, L".exe", sizeof(WCHAR) * 5);
rename_found = true;
break;
}
}
if (!rename_found) {
wprintf(L"Invalid wrapper executable name.\n");
return -1;
}
DWORD file_attrib = GetFileAttributesW(exe_name);
if (file_attrib == INVALID_FILE_ATTRIBUTES || (file_attrib & FILE_ATTRIBUTE_DIRECTORY)) {
wprintf(L"Main executable %ls not found.\n", exe_name);
return -1;
}
// Create job to monitor process tree.
HANDLE job_handle = CreateJobObjectW(nullptr, nullptr);
if (!job_handle) {
wprintf(L"CreateJobObject failed, error %d\n", GetLastError());
return -1;
}
HANDLE io_port_handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1);
if (!io_port_handle) {
wprintf(L"CreateIoCompletionPort failed, error %d\n", GetLastError());
return -1;
}
JOBOBJECT_ASSOCIATE_COMPLETION_PORT compl_port;
ZeroMemory(&compl_port, sizeof(compl_port));
compl_port.CompletionKey = job_handle;
compl_port.CompletionPort = io_port_handle;
if (!SetInformationJobObject(job_handle, JobObjectAssociateCompletionPortInformation, &compl_port, sizeof(compl_port))) {
wprintf(L"SetInformationJobObject(AssociateCompletionPortInformation) failed, error %d\n", GetLastError());
return -1;
}
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
ZeroMemory(&jeli, sizeof(jeli));
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if (!SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) {
wprintf(L"SetInformationJobObject(ExtendedLimitInformation) failed, error %d\n", GetLastError());
return -1;
}
// Start the main process.
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
STARTUPINFOW si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
WCHAR new_command_line[32767];
_snwprintf_s(new_command_line, 32767, _TRUNCATE, L"%ls %ls", exe_name, PathGetArgsW(GetCommandLineW()));
if (!CreateProcessW(nullptr, new_command_line, nullptr, nullptr, true, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi)) {
wprintf(L"CreateProcess failed, error %d\n", GetLastError());
return -1;
}
if (!AssignProcessToJobObject(job_handle, pi.hProcess)) {
wprintf(L"AssignProcessToJobObject failed, error %d\n", GetLastError());
return -1;
}
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
// Wait until main process and all of its children are finished.
DWORD completion_code = 0;
ULONG_PTR completion_key = 0;
LPOVERLAPPED overlapped = nullptr;
while (GetQueuedCompletionStatus(io_port_handle, &completion_code, &completion_key, &overlapped, INFINITE)) {
if ((HANDLE)completion_key == job_handle && completion_code == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) {
break;
}
}
CloseHandle(job_handle);
CloseHandle(io_port_handle);
// Get exit code of the main process.
DWORD exit_code = 0;
GetExitCodeProcess(pi.hProcess, &exit_code);
CloseHandle(pi.hProcess);
return exit_code;
}