+Changes since 2.24\r
+------------------\r
+ * Allow skipping kill_process_tree().\r
+\r
Changes since 2.23\r
------------------\r
* NSSM once again calls TerminateProcess() correctly.\r
so the actual time to shutdown may be longer than the sum of all configured\r
timeouts if the application spawns multiple subprocesses.\r
\r
+To skip applying the above stop methods to all processes in the application's\r
+process tree, applying them only to the original application process, set the\r
+HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters\AppKillProcessTree\r
+registry value, which should be of type REG_DWORD, to 0.\r
+\r
\r
Console window\r
--------------\r
Thanks to Allen Vailliencourt for noticing bugs with configuring the service to\r
run under a local user account.\r
Thanks to Sam Townsend for noticing a regression with TerminateProcess().\r
+Thanks to Barrett Lewis for suggesting the option to skip terminating the\r
+application's child processes.\r
\r
Licence\r
-------\r
if (! (service->stop_method & NSSM_STOP_METHOD_TERMINATE)) {\r
SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_TERMINATE, BM_SETCHECK, BST_UNCHECKED, 0);\r
}\r
+ if (! service->kill_process_tree) {\r
+ SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_SETCHECK, BST_UNCHECKED, 0);\r
+ }\r
\r
/* Restart tab. */\r
SetDlgItemInt(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, service->throttle_delay, 0);\r
check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE, &service->kill_console_delay);\r
check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, &service->kill_window_delay);\r
check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, &service->kill_threads_delay);\r
+ if (SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_GETCHECK, 0, 0) & BST_CHECKED) service->kill_process_tree = 1;\r
+ else service->kill_process_tree = 0;\r
\r
/* Get exit action stuff. */\r
check_number(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, &service->throttle_delay);\r
SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_THREADS, BM_SETCHECK, BST_CHECKED, 0);\r
SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, NSSM_KILL_THREADS_GRACE_PERIOD, 0);\r
SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_TERMINATE, BM_SETCHECK, BST_CHECKED, 0);\r
+ SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_SETCHECK, BST_CHECKED, 1);\r
\r
/* Restart tab. */\r
tab.pszText = message_string(NSSM_GUI_TAB_EXIT);\r
else if (editing) RegDeleteValue(key, NSSM_REG_KILL_WINDOW_GRACE_PERIOD);\r
if (service->kill_threads_delay != NSSM_KILL_THREADS_GRACE_PERIOD) set_number(key, NSSM_REG_KILL_THREADS_GRACE_PERIOD, service->kill_threads_delay);\r
else if (editing) RegDeleteValue(key, NSSM_REG_KILL_THREADS_GRACE_PERIOD);\r
+ if (! service->kill_process_tree) set_number(key, NSSM_REG_KILL_PROCESS_TREE, 0);\r
+ else if (editing) RegDeleteValue(key, NSSM_REG_KILL_PROCESS_TREE);\r
if (service->stdin_path[0] || editing) {\r
if (service->stdin_path[0]) set_expand_string(key, NSSM_REG_STDIN, service->stdin_path);\r
else if (editing) RegDeleteValue(key, NSSM_REG_STDIN);\r
override_milliseconds(service->name, key, NSSM_REG_KILL_WINDOW_GRACE_PERIOD, &service->kill_window_delay, NSSM_KILL_WINDOW_GRACE_PERIOD, NSSM_EVENT_BOGUS_KILL_WINDOW_GRACE_PERIOD);\r
override_milliseconds(service->name, key, NSSM_REG_KILL_THREADS_GRACE_PERIOD, &service->kill_threads_delay, NSSM_KILL_THREADS_GRACE_PERIOD, NSSM_EVENT_BOGUS_KILL_THREADS_GRACE_PERIOD);\r
\r
+ /* Try to get process tree settings - may fail. */\r
+ unsigned long kill_process_tree;\r
+ if (get_number(key, NSSM_REG_KILL_PROCESS_TREE, &kill_process_tree, false) == 1) {\r
+ if (kill_process_tree) service->kill_process_tree = true;\r
+ else service->kill_process_tree = false;\r
+ }\r
+ else service->kill_process_tree = true;\r
+\r
/* Try to get default exit action. */\r
bool default_action;\r
service->default_exit_action = NSSM_EXIT_RESTART;\r
#define NSSM_REG_KILL_CONSOLE_GRACE_PERIOD _T("AppStopMethodConsole")\r
#define NSSM_REG_KILL_WINDOW_GRACE_PERIOD _T("AppStopMethodWindow")\r
#define NSSM_REG_KILL_THREADS_GRACE_PERIOD _T("AppStopMethodThreads")\r
+#define NSSM_REG_KILL_PROCESS_TREE _T("AppKillProcessTree")\r
#define NSSM_REG_STDIN _T("AppStdin")\r
#define NSSM_REG_STDOUT _T("AppStdout")\r
#define NSSM_REG_STDERR _T("AppStderr")\r
#define IDC_AFFINITY 1044\r
#define IDC_CONSOLE 1045\r
#define IDC_DEPENDENCIES 1046\r
+#define IDC_KILL_PROCESS_TREE 1047\r
\r
// Next default values for new objects\r
// \r
#ifndef APSTUDIO_READONLY_SYMBOLS\r
#define _APS_NEXT_RESOURCE_VALUE 115\r
#define _APS_NEXT_COMMAND_VALUE 40001\r
-#define _APS_NEXT_CONTROL_VALUE 1047\r
+#define _APS_NEXT_CONTROL_VALUE 1048\r
#define _APS_NEXT_SYMED_VALUE 101\r
#endif\r
#endif\r
service->kill_console_delay = NSSM_KILL_CONSOLE_GRACE_PERIOD;\r
service->kill_window_delay = NSSM_KILL_WINDOW_GRACE_PERIOD;\r
service->kill_threads_delay = NSSM_KILL_THREADS_GRACE_PERIOD;\r
+ service->kill_process_tree = 1;\r
}\r
\r
/* Allocate and zero memory for a service. */\r
\r
/* Clean up. */\r
if (exitcode == STILL_ACTIVE) exitcode = 0;\r
- if (service->pid) kill_process_tree(service, service->pid, exitcode, service->pid);\r
+ if (service->pid && service->kill_process_tree) kill_process_tree(service, service->pid, exitcode, service->pid);\r
service->pid = 0;\r
\r
/*\r
unsigned long kill_console_delay;\r
unsigned long kill_window_delay;\r
unsigned long kill_threads_delay;\r
+ bool kill_process_tree;\r
SC_HANDLE handle;\r
SERVICE_STATUS status;\r
SERVICE_STATUS_HANDLE status_handle;\r
{ NSSM_REG_KILL_CONSOLE_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_CONSOLE_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
{ NSSM_REG_KILL_WINDOW_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_WINDOW_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
{ NSSM_REG_KILL_THREADS_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_THREADS_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
+ { NSSM_REG_KILL_PROCESS_TREE, REG_DWORD, (void *) 1, false, 0, setting_set_number, setting_get_number },
{ NSSM_REG_THROTTLE, REG_DWORD, (void *) NSSM_RESET_THROTTLE_RESTART, false, 0, setting_set_number, setting_get_number },
{ NSSM_REG_ROTATE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
{ NSSM_REG_ROTATE_ONLINE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },