Try to build PDB files even for releases.
[nssm.git] / gui.cpp
diff --git a/gui.cpp b/gui.cpp
index 692fb9b..5aaa932 100644 (file)
--- a/gui.cpp
+++ b/gui.cpp
@@ -1,6 +1,9 @@
 #include "nssm.h"\r
 \r
-static enum { NSSM_TAB_APPLICATION, NSSM_TAB_DETAILS, NSSM_TAB_LOGON, NSSM_TAB_DEPENDENCIES, NSSM_TAB_PROCESS, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS };\r
+extern const TCHAR *hook_event_strings[];\r
+extern const TCHAR *hook_action_strings[];\r
+\r
+static enum { NSSM_TAB_APPLICATION, NSSM_TAB_DETAILS, NSSM_TAB_LOGON, NSSM_TAB_DEPENDENCIES, NSSM_TAB_PROCESS, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_TAB_HOOKS, NSSM_NUM_TABS } nssm_tabs;\r
 static HWND tablist[NSSM_NUM_TABS];\r
 static int selected_tab;\r
 \r
@@ -23,6 +26,13 @@ static HWND dialog(const TCHAR *templ, HWND parent, DLGPROC function) {
   return dialog(templ, parent, function, 0);\r
 }\r
 \r
+static inline void set_logon_enabled(unsigned char interact_enabled, unsigned char credentials_enabled) {\r
+  EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_INTERACT), interact_enabled);\r
+  EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), credentials_enabled);\r
+  EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), credentials_enabled);\r
+  EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), credentials_enabled);\r
+}\r
+\r
 int nssm_gui(int resource, nssm_service_t *service) {\r
   /* Create window */\r
   HWND dlg = dialog(MAKEINTRESOURCE(resource), 0, nssm_dlg, (LPARAM) service);\r
@@ -83,15 +93,18 @@ int nssm_gui(int resource, nssm_service_t *service) {
 \r
     /* Log on tab. */\r
     if (service->username) {\r
-      CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_ACCOUNT);\r
-      SetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username);\r
-      EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_INTERACT), 0);\r
-      EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), 1);\r
-      EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), 1);\r
-      EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), 1);\r
+      if (is_virtual_account(service->name, service->username)) {\r
+        CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_VIRTUAL_SERVICE, IDC_VIRTUAL_SERVICE);\r
+        set_logon_enabled(0, 0);\r
+      }\r
+      else {\r
+        CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_VIRTUAL_SERVICE, IDC_ACCOUNT);\r
+        SetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username);\r
+        set_logon_enabled(0, 1);\r
+      }\r
     }\r
     else {\r
-      CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
+      CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_VIRTUAL_SERVICE, IDC_LOCALSYSTEM);\r
       if (service->type & SERVICE_INTERACTIVE_PROCESS) SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_INTERACT, BM_SETCHECK, BST_CHECKED, 0);\r
     }\r
 \r
@@ -153,6 +166,9 @@ int nssm_gui(int resource, nssm_service_t *service) {
     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
@@ -164,6 +180,7 @@ int nssm_gui(int resource, nssm_service_t *service) {
     SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDIN, service->stdin_path);\r
     SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDOUT, service->stdout_path);\r
     SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDERR, service->stderr_path);\r
+    if (service->timestamp_log) SendDlgItemMessage(tablist[NSSM_TAB_IO], IDC_TIMESTAMP, BM_SETCHECK, BST_CHECKED, 0);\r
 \r
     /* Rotation tab. */\r
     if (service->stdout_disposition == CREATE_ALWAYS) SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_TRUNCATE, BM_SETCHECK, BST_CHECKED, 0);\r
@@ -177,6 +194,9 @@ int nssm_gui(int resource, nssm_service_t *service) {
     SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, service->rotate_seconds, 0);\r
     if (! service->rotate_bytes_high) SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, service->rotate_bytes_low, 0);\r
 \r
+    /* Hooks tab. */\r
+    if (service->hook_share_output_handles) SendDlgItemMessage(tablist[NSSM_TAB_HOOKS], IDC_REDIRECT_HOOK, BM_SETCHECK, BST_CHECKED, 0);\r
+\r
     /* Check if advanced settings are in use. */\r
     if (service->stdout_disposition != service->stderr_disposition || (service->stdout_disposition && service->stdout_disposition != NSSM_STDOUT_DISPOSITION && service->stdout_disposition != CREATE_ALWAYS) || (service->stderr_disposition && service->stderr_disposition != NSSM_STDERR_DISPOSITION && service->stderr_disposition != CREATE_ALWAYS)) popup_message(dlg, MB_OK | MB_ICONWARNING, NSSM_GUI_WARN_STDIO);\r
     if (service->rotate_bytes_high) popup_message(dlg, MB_OK | MB_ICONWARNING, NSSM_GUI_WARN_ROTATE_BYTES);\r
@@ -259,13 +279,6 @@ static inline void set_timeout_enabled(unsigned long control, unsigned long depe
   EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], dependent), enabled);\r
 }\r
 \r
-static inline void set_logon_enabled(unsigned char enabled) {\r
-  EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_INTERACT), ! enabled);\r
-  EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), enabled);\r
-  EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), enabled);\r
-  EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), enabled);\r
-}\r
-\r
 static inline void set_affinity_enabled(unsigned char enabled) {\r
   EnableWindow(GetDlgItem(tablist[NSSM_TAB_PROCESS], IDC_AFFINITY), enabled);\r
 }\r
@@ -276,6 +289,100 @@ static inline void set_rotation_enabled(unsigned char enabled) {
   EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW), enabled);\r
 }\r
 \r
+static inline int hook_env(const TCHAR *hook_event, const TCHAR *hook_action, TCHAR *buffer, unsigned long buflen) {\r
+  return _sntprintf_s(buffer, buflen, _TRUNCATE, _T("NSSM_HOOK_%s_%s"), hook_event, hook_action);\r
+}\r
+\r
+static inline void set_hook_tab(int event_index, int action_index, bool changed) {\r
+  int first_event = NSSM_GUI_HOOK_EVENT_START;\r
+  HWND combo;\r
+  combo = GetDlgItem(tablist[NSSM_TAB_HOOKS], IDC_HOOK_EVENT);\r
+  SendMessage(combo, CB_SETCURSEL, event_index, 0);\r
+  combo = GetDlgItem(tablist[NSSM_TAB_HOOKS], IDC_HOOK_ACTION);\r
+  SendMessage(combo, CB_RESETCONTENT, 0, 0);\r
+\r
+  const TCHAR *hook_event = hook_event_strings[event_index];\r
+  TCHAR *hook_action;\r
+  int i;\r
+  switch (event_index + first_event) {\r
+    case NSSM_GUI_HOOK_EVENT_ROTATE:\r
+      i = 0;\r
+      SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_ROTATE_PRE));\r
+      if (action_index == i++) hook_action = NSSM_HOOK_ACTION_PRE;\r
+      SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_ROTATE_POST));\r
+      if (action_index == i++) hook_action = NSSM_HOOK_ACTION_POST;\r
+      break;\r
+\r
+    case NSSM_GUI_HOOK_EVENT_START:\r
+      i = 0;\r
+      SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_START_PRE));\r
+      if (action_index == i++) hook_action = NSSM_HOOK_ACTION_PRE;\r
+      SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_START_POST));\r
+      if (action_index == i++) hook_action = NSSM_HOOK_ACTION_POST;\r
+      break;\r
+\r
+    case NSSM_GUI_HOOK_EVENT_STOP:\r
+      i = 0;\r
+      SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_STOP_PRE));\r
+      if (action_index == i++) hook_action = NSSM_HOOK_ACTION_PRE;\r
+      break;\r
+\r
+    case NSSM_GUI_HOOK_EVENT_EXIT:\r
+      i = 0;\r
+      SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_EXIT_POST));\r
+      if (action_index == i++) hook_action = NSSM_HOOK_ACTION_POST;\r
+      break;\r
+\r
+    case NSSM_GUI_HOOK_EVENT_POWER:\r
+      i = 0;\r
+      SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_POWER_CHANGE));\r
+      if (action_index == i++) hook_action = NSSM_HOOK_ACTION_CHANGE;\r
+      SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_POWER_RESUME));\r
+      if (action_index == i++) hook_action = NSSM_HOOK_ACTION_RESUME;\r
+      break;\r
+  }\r
+\r
+  SendMessage(combo, CB_SETCURSEL, action_index, 0);\r
+\r
+  TCHAR hook_name[HOOK_NAME_LENGTH];\r
+  hook_env(hook_event, hook_action, hook_name, _countof(hook_name));\r
+\r
+  if (! *hook_name) return;\r
+\r
+  TCHAR cmd[CMD_LENGTH];\r
+  if (changed) {\r
+    GetDlgItemText(tablist[NSSM_TAB_HOOKS], IDC_HOOK, cmd, _countof(cmd));\r
+    SetEnvironmentVariable(hook_name, cmd);\r
+  }\r
+  else {\r
+    if (! GetEnvironmentVariable(hook_name, cmd, _countof(cmd))) cmd[0] = _T('\0');\r
+    SetDlgItemText(tablist[NSSM_TAB_HOOKS], IDC_HOOK, cmd);\r
+  }\r
+}\r
+\r
+static inline int update_hook(TCHAR *service_name, const TCHAR *hook_event, const TCHAR *hook_action) {\r
+  TCHAR hook_name[HOOK_NAME_LENGTH];\r
+  if (hook_env(hook_event, hook_action, hook_name, _countof(hook_name)) < 0) return 1;\r
+  TCHAR cmd[CMD_LENGTH];\r
+  ZeroMemory(cmd, sizeof(cmd));\r
+  GetEnvironmentVariable(hook_name, cmd, _countof(cmd));\r
+  if (set_hook(service_name, hook_event, hook_action, cmd)) return 2;\r
+  return 0;\r
+}\r
+\r
+static inline int update_hooks(TCHAR *service_name) {\r
+  int ret = 0;\r
+  ret += update_hook(service_name, NSSM_HOOK_EVENT_START, NSSM_HOOK_ACTION_PRE);\r
+  ret += update_hook(service_name, NSSM_HOOK_EVENT_START, NSSM_HOOK_ACTION_POST);\r
+  ret += update_hook(service_name, NSSM_HOOK_EVENT_STOP, NSSM_HOOK_ACTION_PRE);\r
+  ret += update_hook(service_name, NSSM_HOOK_EVENT_EXIT, NSSM_HOOK_ACTION_POST);\r
+  ret += update_hook(service_name, NSSM_HOOK_EVENT_POWER, NSSM_HOOK_ACTION_CHANGE);\r
+  ret += update_hook(service_name, NSSM_HOOK_EVENT_POWER, NSSM_HOOK_ACTION_RESUME);\r
+  ret += update_hook(service_name, NSSM_HOOK_EVENT_ROTATE, NSSM_HOOK_ACTION_PRE);\r
+  ret += update_hook(service_name, NSSM_HOOK_EVENT_ROTATE, NSSM_HOOK_ACTION_POST);\r
+  return ret;\r
+}\r
+\r
 static inline void check_io(HWND owner, TCHAR *name, TCHAR *buffer, unsigned long len, unsigned long control) {\r
   if (! SendMessage(GetDlgItem(tablist[NSSM_TAB_IO], control), WM_GETTEXTLENGTH, 0, 0)) return;\r
   if (GetDlgItemText(tablist[NSSM_TAB_IO], control, buffer, (int) len)) return;\r
@@ -351,12 +458,23 @@ int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service
     service->username = 0;\r
     service->usernamelen = 0;\r
     if (service->password) {\r
-      SecureZeroMemory(service->password, service->passwordlen);\r
+      SecureZeroMemory(service->password, service->passwordlen * sizeof(TCHAR));\r
       HeapFree(GetProcessHeap(), 0, service->password);\r
     }\r
     service->password = 0;\r
     service->passwordlen = 0;\r
   }\r
+  else if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_VIRTUAL_SERVICE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+    if (service->username) HeapFree(GetProcessHeap(), 0, service->username);\r
+    service->username = virtual_account(service->name);\r
+    if (! service->username) {\r
+      popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("account name"), _T("install()"));\r
+      return 6;\r
+    }\r
+    service->usernamelen = _tcslen(service->username) + 1;\r
+    service->password = 0;\r
+    service->passwordlen = 0;\r
+  }\r
   else {\r
     /* Username. */\r
     service->usernamelen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), WM_GETTEXTLENGTH, 0, 0);\r
@@ -440,7 +558,7 @@ int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service
         /* Get first password. */\r
         if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1, service->password, (int) service->passwordlen)) {\r
           HeapFree(GetProcessHeap(), 0, password);\r
-          SecureZeroMemory(service->password, service->passwordlen);\r
+          SecureZeroMemory(service->password, service->passwordlen * sizeof(TCHAR));\r
           HeapFree(GetProcessHeap(), 0, service->password);\r
           service->password = 0;\r
           service->passwordlen = 0;\r
@@ -453,9 +571,9 @@ int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service
 \r
         /* Get confirmation. */\r
         if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2, password, (int) service->passwordlen)) {\r
-          SecureZeroMemory(password, service->passwordlen);\r
+          SecureZeroMemory(password, service->passwordlen * sizeof(TCHAR));\r
           HeapFree(GetProcessHeap(), 0, password);\r
-          SecureZeroMemory(service->password, service->passwordlen);\r
+          SecureZeroMemory(service->password, service->passwordlen * sizeof(TCHAR));\r
           HeapFree(GetProcessHeap(), 0, service->password);\r
           service->password = 0;\r
           service->passwordlen = 0;\r
@@ -469,9 +587,9 @@ int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service
         /* Compare. */\r
         if (_tcsncmp(password, service->password, service->passwordlen)) {\r
           popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PASSWORD);\r
-          SecureZeroMemory(password, service->passwordlen);\r
+          SecureZeroMemory(password, service->passwordlen * sizeof(TCHAR));\r
           HeapFree(GetProcessHeap(), 0, password);\r
-          SecureZeroMemory(service->password, service->passwordlen);\r
+          SecureZeroMemory(service->password, service->passwordlen * sizeof(TCHAR));\r
           HeapFree(GetProcessHeap(), 0, service->password);\r
           service->password = 0;\r
           service->passwordlen = 0;\r
@@ -545,6 +663,8 @@ int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service
   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
@@ -557,6 +677,8 @@ int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service
   check_io(window, _T("stdin"), service->stdin_path, _countof(service->stdin_path), IDC_STDIN);\r
   check_io(window, _T("stdout"), service->stdout_path, _countof(service->stdout_path), IDC_STDOUT);\r
   check_io(window, _T("stderr"), service->stderr_path, _countof(service->stderr_path), IDC_STDERR);\r
+  if (SendDlgItemMessage(tablist[NSSM_TAB_IO], IDC_TIMESTAMP, BM_GETCHECK, 0, 0) & BST_CHECKED) service->timestamp_log = true;\r
+  else service->timestamp_log = false;\r
 \r
   /* Override stdout and/or stderr. */\r
   if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_TRUNCATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
@@ -572,6 +694,9 @@ int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service
     check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, &service->rotate_bytes_low);\r
   }\r
 \r
+  /* Get hook stuff. */\r
+  if (SendDlgItemMessage(tablist[NSSM_TAB_HOOKS], IDC_REDIRECT_HOOK, BM_GETCHECK, 0, 0) & BST_CHECKED) service->hook_share_output_handles = true;\r
+\r
   /* Get environment. */\r
   unsigned long envlen = (unsigned long) SendMessage(GetDlgItem(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT), WM_GETTEXTLENGTH, 0, 0);\r
   if (envlen) {\r
@@ -666,6 +791,8 @@ int install(HWND window) {
       return 6;\r
   }\r
 \r
+  update_hooks(service->name);\r
+\r
   popup_message(window, MB_OK, NSSM_MESSAGE_SERVICE_INSTALLED, service->name);\r
   cleanup_nssm_service(service);\r
   return 0;\r
@@ -705,8 +832,8 @@ int remove(HWND window) {
 \r
     case 3:\r
       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_SERVICE_NOT_INSTALLED);\r
-      return 3;\r
       cleanup_nssm_service(service);\r
+      return 3;\r
 \r
     case 4:\r
       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_REMOVE_SERVICE_FAILED);\r
@@ -751,6 +878,8 @@ int edit(HWND window, nssm_service_t *orig_service) {
       return 6;\r
   }\r
 \r
+  update_hooks(service->name);\r
+\r
   popup_message(window, MB_OK, NSSM_MESSAGE_SERVICE_EDITED, service->name);\r
   cleanup_nssm_service(service);\r
   return 0;\r
@@ -795,7 +924,7 @@ void browse(HWND window, TCHAR *current, unsigned long flags, ...) {
     va_start(arg, flags);\r
     while (i = va_arg(arg, int)) {\r
       TCHAR *localised = message_string(i);\r
-      _sntprintf_s((TCHAR *) ofn.lpstrFilter + len, bufsize, _TRUNCATE, localised);\r
+      _sntprintf_s((TCHAR *) ofn.lpstrFilter + len, bufsize - len, _TRUNCATE, localised);\r
       len += _tcslen(localised) + 1;\r
       LocalFree(localised);\r
       TCHAR *filter = browse_filter(i);\r
@@ -864,11 +993,15 @@ INT_PTR CALLBACK tab_dlg(HWND tab, UINT message, WPARAM w, LPARAM l) {
 \r
         /* Log on. */\r
         case IDC_LOCALSYSTEM:\r
-          set_logon_enabled(0);\r
+          set_logon_enabled(1, 0);\r
+          break;\r
+\r
+        case IDC_VIRTUAL_SERVICE:\r
+          set_logon_enabled(0, 0);\r
           break;\r
 \r
         case IDC_ACCOUNT:\r
-          set_logon_enabled(1);\r
+          set_logon_enabled(0, 1);\r
           break;\r
 \r
         /* Affinity. */\r
@@ -924,6 +1057,28 @@ INT_PTR CALLBACK tab_dlg(HWND tab, UINT message, WPARAM w, LPARAM l) {
           else enabled = 0;\r
           set_rotation_enabled(enabled);\r
           break;\r
+\r
+        /* Hook event. */\r
+        case IDC_HOOK_EVENT:\r
+          if (HIWORD(w) == CBN_SELCHANGE) set_hook_tab((int) SendMessage(GetDlgItem(tab, IDC_HOOK_EVENT), CB_GETCURSEL, 0, 0), 0, false);\r
+          break;\r
+\r
+        /* Hook action. */\r
+        case IDC_HOOK_ACTION:\r
+          if (HIWORD(w) == CBN_SELCHANGE) set_hook_tab((int) SendMessage(GetDlgItem(tab, IDC_HOOK_EVENT), CB_GETCURSEL, 0, 0), (int) SendMessage(GetDlgItem(tab, IDC_HOOK_ACTION), CB_GETCURSEL, 0, 0), false);\r
+          break;\r
+\r
+        /* Browse for hook. */\r
+        case IDC_BROWSE_HOOK:\r
+          dlg = GetDlgItem(tab, IDC_HOOK);\r
+          GetDlgItemText(tab, IDC_HOOK, buffer, _countof(buffer));\r
+          browse(dlg, _T(""), OFN_FILEMUSTEXIST, NSSM_GUI_BROWSE_FILTER_ALL_FILES, 0);\r
+          break;\r
+\r
+        /* Hook. */\r
+        case IDC_HOOK:\r
+          set_hook_tab((int) SendMessage(GetDlgItem(tab, IDC_HOOK_EVENT), CB_GETCURSEL, 0, 0), (int) SendMessage(GetDlgItem(tab, IDC_HOOK_ACTION), CB_GETCURSEL, 0, 0), true);\r
+          break;\r
       }\r
       return 1;\r
   }\r
@@ -993,7 +1148,7 @@ INT_PTR CALLBACK nssm_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
 \r
       /* Set defaults. */\r
       CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
-      set_logon_enabled(0);\r
+      set_logon_enabled(1, 0);\r
 \r
       /* Dependencies tab. */\r
       tab.pszText = message_string(NSSM_GUI_TAB_DEPENDENCIES);\r
@@ -1070,6 +1225,7 @@ INT_PTR CALLBACK nssm_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
       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
@@ -1095,6 +1251,9 @@ INT_PTR CALLBACK nssm_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
       tablist[NSSM_TAB_IO] = dialog(MAKEINTRESOURCE(IDD_IO), window, tab_dlg);\r
       ShowWindow(tablist[NSSM_TAB_IO], SW_HIDE);\r
 \r
+      /* Set defaults. */\r
+      SendDlgItemMessage(tablist[NSSM_TAB_IO], IDC_TIMESTAMP, BM_SETCHECK, BST_UNCHECKED, 0);\r
+\r
       /* Rotation tab. */\r
       tab.pszText = message_string(NSSM_GUI_TAB_ROTATION);\r
       tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;\r
@@ -1115,6 +1274,38 @@ INT_PTR CALLBACK nssm_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
       tablist[NSSM_TAB_ENVIRONMENT] = dialog(MAKEINTRESOURCE(IDD_ENVIRONMENT), window, tab_dlg);\r
       ShowWindow(tablist[NSSM_TAB_ENVIRONMENT], SW_HIDE);\r
 \r
+      /* Hooks tab. */\r
+      tab.pszText = message_string(NSSM_GUI_TAB_HOOKS);\r
+      tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;\r
+      SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_HOOKS, (LPARAM) &tab);\r
+      tablist[NSSM_TAB_HOOKS] = dialog(MAKEINTRESOURCE(IDD_HOOKS), window, tab_dlg);\r
+      ShowWindow(tablist[NSSM_TAB_HOOKS], SW_HIDE);\r
+\r
+      /* Set defaults. */\r
+      combo = GetDlgItem(tablist[NSSM_TAB_HOOKS], IDC_HOOK_EVENT);\r
+      SendMessage(combo, CB_INSERTSTRING, -1, (LPARAM) message_string(NSSM_GUI_HOOK_EVENT_START));\r
+      SendMessage(combo, CB_INSERTSTRING, -1, (LPARAM) message_string(NSSM_GUI_HOOK_EVENT_STOP));\r
+      SendMessage(combo, CB_INSERTSTRING, -1, (LPARAM) message_string(NSSM_GUI_HOOK_EVENT_EXIT));\r
+      SendMessage(combo, CB_INSERTSTRING, -1, (LPARAM) message_string(NSSM_GUI_HOOK_EVENT_POWER));\r
+      SendMessage(combo, CB_INSERTSTRING, -1, (LPARAM) message_string(NSSM_GUI_HOOK_EVENT_ROTATE));\r
+      SendDlgItemMessage(tablist[NSSM_TAB_HOOKS], IDC_REDIRECT_HOOK, BM_SETCHECK, BST_UNCHECKED, 0);\r
+      if (_tcslen(service->name)) {\r
+        TCHAR hook_name[HOOK_NAME_LENGTH];\r
+        TCHAR cmd[CMD_LENGTH];\r
+        for (i = 0; hook_event_strings[i]; i++) {\r
+          const TCHAR *hook_event = hook_event_strings[i];\r
+          int j;\r
+          for (j = 0; hook_action_strings[j]; j++) {\r
+            const TCHAR *hook_action = hook_action_strings[j];\r
+            if (! valid_hook_name(hook_event, hook_action, true)) continue;\r
+            if (get_hook(service->name, hook_event, hook_action, cmd, sizeof(cmd))) continue;\r
+            if (hook_env(hook_event, hook_action, hook_name, _countof(hook_name)) < 0) continue;\r
+            SetEnvironmentVariable(hook_name, cmd);\r
+          }\r
+        }\r
+      }\r
+      set_hook_tab(0, 0, false);\r
+\r
       return 1;\r
 \r
     /* Tab change. */\r