Command to dump service configuration.
[nssm.git] / gui.cpp
1 #include "nssm.h"\r
2 \r
3 extern const TCHAR *hook_event_strings[];\r
4 extern const TCHAR *hook_action_strings[];\r
5 \r
6 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
7 static HWND tablist[NSSM_NUM_TABS];\r
8 static int selected_tab;\r
9 \r
10 static HWND dialog(const TCHAR *templ, HWND parent, DLGPROC function, LPARAM l) {\r
11   /* The caller will deal with GetLastError()... */\r
12   HRSRC resource = FindResourceEx(0, RT_DIALOG, templ, GetUserDefaultLangID());\r
13   if (! resource) {\r
14     if (GetLastError() != ERROR_RESOURCE_LANG_NOT_FOUND) return 0;\r
15     resource = FindResourceEx(0, RT_DIALOG, templ, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));\r
16     if (! resource) return 0;\r
17   }\r
18 \r
19   HGLOBAL ret = LoadResource(0, resource);\r
20   if (! ret) return 0;\r
21 \r
22   return CreateDialogIndirectParam(0, (DLGTEMPLATE *) ret, parent, function, l);\r
23 }\r
24 \r
25 static HWND dialog(const TCHAR *templ, HWND parent, DLGPROC function) {\r
26   return dialog(templ, parent, function, 0);\r
27 }\r
28 \r
29 int nssm_gui(int resource, nssm_service_t *service) {\r
30   /* Create window */\r
31   HWND dlg = dialog(MAKEINTRESOURCE(resource), 0, nssm_dlg, (LPARAM) service);\r
32   if (! dlg) {\r
33     popup_message(0, MB_OK, NSSM_GUI_CREATEDIALOG_FAILED, error_string(GetLastError()));\r
34     return 1;\r
35   }\r
36 \r
37   /* Load the icon. */\r
38   HANDLE icon = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDI_NSSM), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);\r
39   if (icon) SendMessage(dlg, WM_SETICON, ICON_SMALL, (LPARAM) icon);\r
40   icon = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDI_NSSM), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0);\r
41   if (icon) SendMessage(dlg, WM_SETICON, ICON_BIG, (LPARAM) icon);\r
42 \r
43   /* Remember what the window is for. */\r
44   SetWindowLongPtr(dlg, GWLP_USERDATA, (LONG_PTR) resource);\r
45 \r
46   /* Display the window */\r
47   centre_window(dlg);\r
48   ShowWindow(dlg, SW_SHOW);\r
49 \r
50   /* Set service name if given */\r
51   if (service->name[0]) {\r
52     SetDlgItemText(dlg, IDC_NAME, service->name);\r
53     /* No point making user click remove if the name is already entered */\r
54     if (resource == IDD_REMOVE) {\r
55       HWND button = GetDlgItem(dlg, IDC_REMOVE);\r
56       if (button) {\r
57         SendMessage(button, WM_LBUTTONDOWN, 0, 0);\r
58         SendMessage(button, WM_LBUTTONUP, 0, 0);\r
59       }\r
60     }\r
61   }\r
62 \r
63   if (resource == IDD_EDIT) {\r
64     /* We'll need the service handle later. */\r
65     SetWindowLongPtr(dlg, DWLP_USER, (LONG_PTR) service);\r
66 \r
67     /* Service name can't be edited. */\r
68     EnableWindow(GetDlgItem(dlg, IDC_NAME), 0);\r
69     SetFocus(GetDlgItem(dlg, IDOK));\r
70 \r
71     /* Set existing details. */\r
72     HWND combo;\r
73     HWND list;\r
74 \r
75     /* Application tab. */\r
76     if (service->native) SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_PATH, service->image);\r
77     else SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_PATH, service->exe);\r
78     SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_DIR, service->dir);\r
79     SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_FLAGS, service->flags);\r
80 \r
81     /* Details tab. */\r
82     SetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME, service->displayname);\r
83     SetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION, service->description);\r
84     combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP);\r
85     SendMessage(combo, CB_SETCURSEL, service->startup, 0);\r
86 \r
87     /* Log on tab. */\r
88     if (service->username) {\r
89       CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_ACCOUNT);\r
90       SetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username);\r
91       EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_INTERACT), 0);\r
92       EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), 1);\r
93       EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), 1);\r
94       EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), 1);\r
95     }\r
96     else {\r
97       CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
98       if (service->type & SERVICE_INTERACTIVE_PROCESS) SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_INTERACT, BM_SETCHECK, BST_CHECKED, 0);\r
99     }\r
100 \r
101     /* Dependencies tab. */\r
102     if (service->dependencieslen) {\r
103       TCHAR *formatted;\r
104       unsigned long newlen;\r
105       if (format_double_null(service->dependencies, service->dependencieslen, &formatted, &newlen)) {\r
106         popup_message(dlg, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("dependencies"), _T("nssm_dlg()"));\r
107       }\r
108       else {\r
109         SetDlgItemText(tablist[NSSM_TAB_DEPENDENCIES], IDC_DEPENDENCIES, formatted);\r
110         HeapFree(GetProcessHeap(), 0, formatted);\r
111       }\r
112     }\r
113 \r
114     /* Process tab. */\r
115     if (service->priority) {\r
116       int priority = priority_constant_to_index(service->priority);\r
117       combo = GetDlgItem(tablist[NSSM_TAB_PROCESS], IDC_PRIORITY);\r
118       SendMessage(combo, CB_SETCURSEL, priority, 0);\r
119     }\r
120 \r
121     if (service->affinity) {\r
122       list = GetDlgItem(tablist[NSSM_TAB_PROCESS], IDC_AFFINITY);\r
123       SendDlgItemMessage(tablist[NSSM_TAB_PROCESS], IDC_AFFINITY_ALL, BM_SETCHECK, BST_UNCHECKED, 0);\r
124       EnableWindow(GetDlgItem(tablist[NSSM_TAB_PROCESS], IDC_AFFINITY), 1);\r
125 \r
126       DWORD_PTR affinity, system_affinity;\r
127       if (GetProcessAffinityMask(GetCurrentProcess(), &affinity, &system_affinity)) {\r
128         if ((service->affinity & (__int64) system_affinity) != service->affinity) popup_message(dlg, MB_OK | MB_ICONWARNING, NSSM_GUI_WARN_AFFINITY);\r
129       }\r
130 \r
131       for (int i = 0; i < num_cpus(); i++) {\r
132         if (! (service->affinity & (1LL << (__int64) i))) SendMessage(list, LB_SETSEL, 0, i);\r
133       }\r
134     }\r
135 \r
136     if (service->no_console) {\r
137       SendDlgItemMessage(tablist[NSSM_TAB_PROCESS], IDC_CONSOLE, BM_SETCHECK, BST_UNCHECKED, 0);\r
138     }\r
139 \r
140     /* Shutdown tab. */\r
141     if (! (service->stop_method & NSSM_STOP_METHOD_CONSOLE)) {\r
142       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_CONSOLE, BM_SETCHECK, BST_UNCHECKED, 0);\r
143       EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE), 0);\r
144     }\r
145     SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE, service->kill_console_delay, 0);\r
146     if (! (service->stop_method & NSSM_STOP_METHOD_WINDOW)) {\r
147       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_WINDOW, BM_SETCHECK, BST_UNCHECKED, 0);\r
148       EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW), 0);\r
149     }\r
150     SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, service->kill_window_delay, 0);\r
151     if (! (service->stop_method & NSSM_STOP_METHOD_THREADS)) {\r
152       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_THREADS, BM_SETCHECK, BST_UNCHECKED, 0);\r
153       EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS), 0);\r
154     }\r
155     SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, service->kill_threads_delay, 0);\r
156     if (! (service->stop_method & NSSM_STOP_METHOD_TERMINATE)) {\r
157       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_TERMINATE, BM_SETCHECK, BST_UNCHECKED, 0);\r
158     }\r
159     if (! service->kill_process_tree) {\r
160       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_SETCHECK, BST_UNCHECKED, 0);\r
161     }\r
162 \r
163     /* Restart tab. */\r
164     SetDlgItemInt(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, service->throttle_delay, 0);\r
165     combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT);\r
166     SendMessage(combo, CB_SETCURSEL, service->default_exit_action, 0);\r
167     SetDlgItemInt(tablist[NSSM_TAB_EXIT], IDC_RESTART_DELAY, service->restart_delay, 0);\r
168 \r
169     /* I/O tab. */\r
170     SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDIN, service->stdin_path);\r
171     SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDOUT, service->stdout_path);\r
172     SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDERR, service->stderr_path);\r
173 \r
174     /* Rotation tab. */\r
175     if (service->stdout_disposition == CREATE_ALWAYS) SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_TRUNCATE, BM_SETCHECK, BST_CHECKED, 0);\r
176     if (service->rotate_files) {\r
177       SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_SETCHECK, BST_CHECKED, 0);\r
178       EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_ONLINE), 1);\r
179       EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS), 1);\r
180       EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW), 1);\r
181     }\r
182     if (service->rotate_stdout_online || service->rotate_stderr_online) SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_ONLINE, BM_SETCHECK, BST_CHECKED, 0);\r
183     SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, service->rotate_seconds, 0);\r
184     if (! service->rotate_bytes_high) SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, service->rotate_bytes_low, 0);\r
185 \r
186     /* Hooks tab. */\r
187     if (service->hook_share_output_handles) SendDlgItemMessage(tablist[NSSM_TAB_HOOKS], IDC_REDIRECT_HOOK, BM_SETCHECK, BST_CHECKED, 0);\r
188 \r
189     /* Check if advanced settings are in use. */\r
190     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
191     if (service->rotate_bytes_high) popup_message(dlg, MB_OK | MB_ICONWARNING, NSSM_GUI_WARN_ROTATE_BYTES);\r
192 \r
193     /* Environment tab. */\r
194     TCHAR *env;\r
195     unsigned long envlen;\r
196     if (service->env_extralen) {\r
197       env = service->env_extra;\r
198       envlen = service->env_extralen;\r
199     }\r
200     else {\r
201       env = service->env;\r
202       envlen = service->envlen;\r
203       if (envlen) SendDlgItemMessage(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT_REPLACE, BM_SETCHECK, BST_CHECKED, 0);\r
204     }\r
205 \r
206     if (envlen) {\r
207       TCHAR *formatted;\r
208       unsigned long newlen;\r
209       if (format_double_null(env, envlen, &formatted, &newlen)) {\r
210         popup_message(dlg, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("nssm_dlg()"));\r
211       }\r
212       else {\r
213         SetDlgItemText(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT, formatted);\r
214         HeapFree(GetProcessHeap(), 0, formatted);\r
215       }\r
216     }\r
217     if (service->envlen && service->env_extralen) popup_message(dlg, MB_OK | MB_ICONWARNING, NSSM_GUI_WARN_ENVIRONMENT);\r
218   }\r
219 \r
220   /* Go! */\r
221   MSG message;\r
222   while (GetMessage(&message, 0, 0, 0)) {\r
223     if (IsDialogMessage(dlg, &message)) continue;\r
224     TranslateMessage(&message);\r
225     DispatchMessage(&message);\r
226   }\r
227 \r
228   return (int) message.wParam;\r
229 }\r
230 \r
231 void centre_window(HWND window) {\r
232   HWND desktop;\r
233   RECT size, desktop_size;\r
234   unsigned long x, y;\r
235 \r
236   if (! window) return;\r
237 \r
238   /* Find window size */\r
239   if (! GetWindowRect(window, &size)) return;\r
240 \r
241   /* Find desktop window */\r
242   desktop = GetDesktopWindow();\r
243   if (! desktop) return;\r
244 \r
245   /* Find desktop window size */\r
246   if (! GetWindowRect(desktop, &desktop_size)) return;\r
247 \r
248   /* Centre window */\r
249   x = (desktop_size.right - size.right) / 2;\r
250   y = (desktop_size.bottom - size.bottom) / 2;\r
251   MoveWindow(window, x, y, size.right - size.left, size.bottom - size.top, 0);\r
252 }\r
253 \r
254 static inline void check_stop_method(nssm_service_t *service, unsigned long method, unsigned long control) {\r
255   if (SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], control, BM_GETCHECK, 0, 0) & BST_CHECKED) return;\r
256   service->stop_method &= ~method;\r
257 }\r
258 \r
259 static inline void check_number(HWND tab, unsigned long control, unsigned long *timeout) {\r
260   BOOL translated;\r
261   unsigned long configured = GetDlgItemInt(tab, control, &translated, 0);\r
262   if (translated) *timeout = configured;\r
263 }\r
264 \r
265 static inline void set_timeout_enabled(unsigned long control, unsigned long dependent) {\r
266   unsigned char enabled = 0;\r
267   if (SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], control, BM_GETCHECK, 0, 0) & BST_CHECKED) enabled = 1;\r
268   EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], dependent), enabled);\r
269 }\r
270 \r
271 static inline void set_logon_enabled(unsigned char enabled) {\r
272   EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_INTERACT), ! enabled);\r
273   EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), enabled);\r
274   EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), enabled);\r
275   EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), enabled);\r
276 }\r
277 \r
278 static inline void set_affinity_enabled(unsigned char enabled) {\r
279   EnableWindow(GetDlgItem(tablist[NSSM_TAB_PROCESS], IDC_AFFINITY), enabled);\r
280 }\r
281 \r
282 static inline void set_rotation_enabled(unsigned char enabled) {\r
283   EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_ONLINE), enabled);\r
284   EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS), enabled);\r
285   EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW), enabled);\r
286 }\r
287 \r
288 static inline int hook_env(const TCHAR *hook_event, const TCHAR *hook_action, TCHAR *buffer, unsigned long buflen) {\r
289   return _sntprintf_s(buffer, buflen, _TRUNCATE, _T("NSSM_HOOK_%s_%s"), hook_event, hook_action);\r
290 }\r
291 \r
292 static inline void set_hook_tab(int event_index, int action_index, bool changed) {\r
293   int first_event = NSSM_GUI_HOOK_EVENT_START;\r
294   HWND combo;\r
295   combo = GetDlgItem(tablist[NSSM_TAB_HOOKS], IDC_HOOK_EVENT);\r
296   SendMessage(combo, CB_SETCURSEL, event_index, 0);\r
297   combo = GetDlgItem(tablist[NSSM_TAB_HOOKS], IDC_HOOK_ACTION);\r
298   SendMessage(combo, CB_RESETCONTENT, 0, 0);\r
299 \r
300   const TCHAR *hook_event = hook_event_strings[event_index];\r
301   TCHAR *hook_action;\r
302   int i;\r
303   switch (event_index + first_event) {\r
304     case NSSM_GUI_HOOK_EVENT_ROTATE:\r
305       i = 0;\r
306       SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_ROTATE_PRE));\r
307       if (action_index == i++) hook_action = NSSM_HOOK_ACTION_PRE;\r
308       SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_ROTATE_POST));\r
309       if (action_index == i++) hook_action = NSSM_HOOK_ACTION_POST;\r
310       break;\r
311 \r
312     case NSSM_GUI_HOOK_EVENT_START:\r
313       i = 0;\r
314       SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_START_PRE));\r
315       if (action_index == i++) hook_action = NSSM_HOOK_ACTION_PRE;\r
316       SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_START_POST));\r
317       if (action_index == i++) hook_action = NSSM_HOOK_ACTION_POST;\r
318       break;\r
319 \r
320     case NSSM_GUI_HOOK_EVENT_STOP:\r
321       i = 0;\r
322       SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_STOP_PRE));\r
323       if (action_index == i++) hook_action = NSSM_HOOK_ACTION_PRE;\r
324       break;\r
325 \r
326     case NSSM_GUI_HOOK_EVENT_EXIT:\r
327       i = 0;\r
328       SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_EXIT_POST));\r
329       if (action_index == i++) hook_action = NSSM_HOOK_ACTION_POST;\r
330       break;\r
331 \r
332     case NSSM_GUI_HOOK_EVENT_POWER:\r
333       i = 0;\r
334       SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_POWER_CHANGE));\r
335       if (action_index == i++) hook_action = NSSM_HOOK_ACTION_CHANGE;\r
336       SendMessage(combo, CB_INSERTSTRING, i, (LPARAM) message_string(NSSM_GUI_HOOK_ACTION_POWER_RESUME));\r
337       if (action_index == i++) hook_action = NSSM_HOOK_ACTION_RESUME;\r
338       break;\r
339   }\r
340 \r
341   SendMessage(combo, CB_SETCURSEL, action_index, 0);\r
342 \r
343   TCHAR hook_name[HOOK_NAME_LENGTH];\r
344   hook_env(hook_event, hook_action, hook_name, _countof(hook_name));\r
345 \r
346   if (! *hook_name) return;\r
347 \r
348   TCHAR cmd[CMD_LENGTH];\r
349   if (changed) {\r
350     GetDlgItemText(tablist[NSSM_TAB_HOOKS], IDC_HOOK, cmd, _countof(cmd));\r
351     SetEnvironmentVariable(hook_name, cmd);\r
352   }\r
353   else {\r
354     GetEnvironmentVariable(hook_name, cmd, _countof(cmd));\r
355     SetDlgItemText(tablist[NSSM_TAB_HOOKS], IDC_HOOK, cmd);\r
356   }\r
357 }\r
358 \r
359 static inline int update_hook(TCHAR *service_name, const TCHAR *hook_event, const TCHAR *hook_action) {\r
360   TCHAR hook_name[HOOK_NAME_LENGTH];\r
361   if (hook_env(hook_event, hook_action, hook_name, _countof(hook_name)) < 0) return 1;\r
362   TCHAR cmd[CMD_LENGTH];\r
363   ZeroMemory(cmd, sizeof(cmd));\r
364   GetEnvironmentVariable(hook_name, cmd, _countof(cmd));\r
365   if (set_hook(service_name, hook_event, hook_action, cmd)) return 2;\r
366   return 0;\r
367 }\r
368 \r
369 static inline int update_hooks(TCHAR *service_name) {\r
370   int ret = 0;\r
371   ret += update_hook(service_name, NSSM_HOOK_EVENT_START, NSSM_HOOK_ACTION_PRE);\r
372   ret += update_hook(service_name, NSSM_HOOK_EVENT_START, NSSM_HOOK_ACTION_POST);\r
373   ret += update_hook(service_name, NSSM_HOOK_EVENT_STOP, NSSM_HOOK_ACTION_PRE);\r
374   ret += update_hook(service_name, NSSM_HOOK_EVENT_EXIT, NSSM_HOOK_ACTION_POST);\r
375   ret += update_hook(service_name, NSSM_HOOK_EVENT_POWER, NSSM_HOOK_ACTION_CHANGE);\r
376   ret += update_hook(service_name, NSSM_HOOK_EVENT_POWER, NSSM_HOOK_ACTION_RESUME);\r
377   ret += update_hook(service_name, NSSM_HOOK_EVENT_ROTATE, NSSM_HOOK_ACTION_PRE);\r
378   ret += update_hook(service_name, NSSM_HOOK_EVENT_ROTATE, NSSM_HOOK_ACTION_POST);\r
379   return ret;\r
380 }\r
381 \r
382 static inline void check_io(HWND owner, TCHAR *name, TCHAR *buffer, unsigned long len, unsigned long control) {\r
383   if (! SendMessage(GetDlgItem(tablist[NSSM_TAB_IO], control), WM_GETTEXTLENGTH, 0, 0)) return;\r
384   if (GetDlgItemText(tablist[NSSM_TAB_IO], control, buffer, (int) len)) return;\r
385   popup_message(owner, MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_PATH_TOO_LONG, name);\r
386   ZeroMemory(buffer, len * sizeof(TCHAR));\r
387 }\r
388 \r
389 /* Set service parameters. */\r
390 int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service) {\r
391   if (! service) return 1;\r
392 \r
393   set_nssm_service_defaults(service);\r
394 \r
395   if (orig_service) {\r
396     service->native = orig_service->native;\r
397     service->handle = orig_service->handle;\r
398   }\r
399 \r
400   /* Get service name. */\r
401   if (! GetDlgItemText(window, IDC_NAME, service->name, _countof(service->name))) {\r
402     popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_SERVICE_NAME);\r
403     cleanup_nssm_service(service);\r
404     return 2;\r
405   }\r
406 \r
407   /* Get executable name */\r
408   if (! service->native) {\r
409     if (! GetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_PATH, service->exe, _countof(service->exe))) {\r
410       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PATH);\r
411       return 3;\r
412     }\r
413 \r
414     /* Get startup directory. */\r
415     if (! GetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_DIR, service->dir, _countof(service->dir))) {\r
416       _sntprintf_s(service->dir, _countof(service->dir), _TRUNCATE, _T("%s"), service->exe);\r
417       strip_basename(service->dir);\r
418     }\r
419 \r
420     /* Get flags. */\r
421     if (SendMessage(GetDlgItem(tablist[NSSM_TAB_APPLICATION], IDC_FLAGS), WM_GETTEXTLENGTH, 0, 0)) {\r
422       if (! GetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_FLAGS, service->flags, _countof(service->flags))) {\r
423         popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_OPTIONS);\r
424         return 4;\r
425       }\r
426     }\r
427   }\r
428 \r
429   /* Get details. */\r
430   if (SendMessage(GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME), WM_GETTEXTLENGTH, 0, 0)) {\r
431     if (! GetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME, service->displayname, _countof(service->displayname))) {\r
432       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DISPLAYNAME);\r
433       return 5;\r
434     }\r
435   }\r
436 \r
437   if (SendMessage(GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION), WM_GETTEXTLENGTH, 0, 0)) {\r
438     if (! GetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION, service->description, _countof(service->description))) {\r
439       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DESCRIPTION);\r
440       return 5;\r
441     }\r
442   }\r
443 \r
444   HWND combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP);\r
445   service->startup = (unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0);\r
446   if (service->startup == CB_ERR) service->startup = 0;\r
447 \r
448   /* Get logon stuff. */\r
449   if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
450     if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_INTERACT, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
451       service->type |= SERVICE_INTERACTIVE_PROCESS;\r
452     }\r
453     if (service->username) HeapFree(GetProcessHeap(), 0, service->username);\r
454     service->username = 0;\r
455     service->usernamelen = 0;\r
456     if (service->password) {\r
457       SecureZeroMemory(service->password, service->passwordlen * sizeof(TCHAR));\r
458       HeapFree(GetProcessHeap(), 0, service->password);\r
459     }\r
460     service->password = 0;\r
461     service->passwordlen = 0;\r
462   }\r
463   else {\r
464     /* Username. */\r
465     service->usernamelen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), WM_GETTEXTLENGTH, 0, 0);\r
466     if (! service->usernamelen) {\r
467       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_USERNAME);\r
468       return 6;\r
469     }\r
470     service->usernamelen++;\r
471 \r
472     service->username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->usernamelen * sizeof(TCHAR));\r
473     if (! service->username) {\r
474       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("account name"), _T("install()"));\r
475       return 6;\r
476     }\r
477     if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username, (int) service->usernamelen)) {\r
478       HeapFree(GetProcessHeap(), 0, service->username);\r
479       service->username = 0;\r
480       service->usernamelen = 0;\r
481       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_USERNAME);\r
482       return 6;\r
483     }\r
484 \r
485     /*\r
486       Special case for well-known accounts.\r
487       Ignore the password if we're editing and the username hasn't changed.\r
488     */\r
489     const TCHAR *well_known = well_known_username(service->username);\r
490     if (well_known) {\r
491       if (str_equiv(well_known, NSSM_LOCALSYSTEM_ACCOUNT)) {\r
492         HeapFree(GetProcessHeap(), 0, service->username);\r
493         service->username = 0;\r
494         service->usernamelen = 0;\r
495       }\r
496       else {\r
497         service->usernamelen = _tcslen(well_known) + 1;\r
498         service->username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->usernamelen * sizeof(TCHAR));\r
499         if (! service->username) {\r
500           print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("canon"), _T("install()"));\r
501           return 6;\r
502         }\r
503         memmove(service->username, well_known, service->usernamelen * sizeof(TCHAR));\r
504       }\r
505     }\r
506     else {\r
507       /* Password. */\r
508       service->passwordlen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), WM_GETTEXTLENGTH, 0, 0);\r
509       size_t passwordlen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), WM_GETTEXTLENGTH, 0, 0);\r
510 \r
511       if (! orig_service || ! orig_service->username || ! str_equiv(service->username, orig_service->username) || service->passwordlen || passwordlen) {\r
512         if (! service->passwordlen) {\r
513           popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PASSWORD);\r
514           return 6;\r
515         }\r
516         if (passwordlen != service->passwordlen) {\r
517           popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PASSWORD);\r
518           return 6;\r
519         }\r
520         service->passwordlen++;\r
521 \r
522         /* Temporary buffer for password validation. */\r
523         TCHAR *password = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->passwordlen * sizeof(TCHAR));\r
524         if (! password) {\r
525           HeapFree(GetProcessHeap(), 0, service->username);\r
526           service->username = 0;\r
527           service->usernamelen = 0;\r
528           popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("password confirmation"), _T("install()"));\r
529           return 6;\r
530         }\r
531 \r
532         /* Actual password buffer. */\r
533         service->password = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->passwordlen * sizeof(TCHAR));\r
534         if (! service->password) {\r
535           HeapFree(GetProcessHeap(), 0, password);\r
536           HeapFree(GetProcessHeap(), 0, service->username);\r
537           service->username = 0;\r
538           service->usernamelen = 0;\r
539           popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("password"), _T("install()"));\r
540           return 6;\r
541         }\r
542 \r
543         /* Get first password. */\r
544         if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1, service->password, (int) service->passwordlen)) {\r
545           HeapFree(GetProcessHeap(), 0, password);\r
546           SecureZeroMemory(service->password, service->passwordlen * sizeof(TCHAR));\r
547           HeapFree(GetProcessHeap(), 0, service->password);\r
548           service->password = 0;\r
549           service->passwordlen = 0;\r
550           HeapFree(GetProcessHeap(), 0, service->username);\r
551           service->username = 0;\r
552           service->usernamelen = 0;\r
553           popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_PASSWORD);\r
554           return 6;\r
555         }\r
556 \r
557         /* Get confirmation. */\r
558         if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2, password, (int) service->passwordlen)) {\r
559           SecureZeroMemory(password, service->passwordlen * sizeof(TCHAR));\r
560           HeapFree(GetProcessHeap(), 0, password);\r
561           SecureZeroMemory(service->password, service->passwordlen * sizeof(TCHAR));\r
562           HeapFree(GetProcessHeap(), 0, service->password);\r
563           service->password = 0;\r
564           service->passwordlen = 0;\r
565           HeapFree(GetProcessHeap(), 0, service->username);\r
566           service->username = 0;\r
567           service->usernamelen = 0;\r
568           popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_PASSWORD);\r
569           return 6;\r
570         }\r
571 \r
572         /* Compare. */\r
573         if (_tcsncmp(password, service->password, service->passwordlen)) {\r
574           popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PASSWORD);\r
575           SecureZeroMemory(password, service->passwordlen * sizeof(TCHAR));\r
576           HeapFree(GetProcessHeap(), 0, password);\r
577           SecureZeroMemory(service->password, service->passwordlen * sizeof(TCHAR));\r
578           HeapFree(GetProcessHeap(), 0, service->password);\r
579           service->password = 0;\r
580           service->passwordlen = 0;\r
581           HeapFree(GetProcessHeap(), 0, service->username);\r
582           service->username = 0;\r
583           service->usernamelen = 0;\r
584           return 6;\r
585         }\r
586       }\r
587     }\r
588   }\r
589 \r
590   /* Get dependencies. */\r
591   unsigned long dependencieslen = (unsigned long) SendMessage(GetDlgItem(tablist[NSSM_TAB_DEPENDENCIES], IDC_DEPENDENCIES), WM_GETTEXTLENGTH, 0, 0);\r
592   if (dependencieslen) {\r
593     TCHAR *dependencies = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (dependencieslen + 2) * sizeof(TCHAR));\r
594     if (! dependencies) {\r
595       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("dependencies"), _T("install()"));\r
596       cleanup_nssm_service(service);\r
597       return 6;\r
598     }\r
599 \r
600     if (! GetDlgItemText(tablist[NSSM_TAB_DEPENDENCIES], IDC_DEPENDENCIES, dependencies, dependencieslen + 1)) {\r
601       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DEPENDENCIES);\r
602       HeapFree(GetProcessHeap(), 0, dependencies);\r
603       cleanup_nssm_service(service);\r
604       return 6;\r
605     }\r
606 \r
607     if (unformat_double_null(dependencies, dependencieslen, &service->dependencies, &service->dependencieslen)) {\r
608       HeapFree(GetProcessHeap(), 0, dependencies);\r
609       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("dependencies"), _T("install()"));\r
610       cleanup_nssm_service(service);\r
611       return 6;\r
612     }\r
613 \r
614     HeapFree(GetProcessHeap(), 0, dependencies);\r
615   }\r
616 \r
617   /* Remaining tabs are only for services we manage. */\r
618   if (service->native) return 0;\r
619 \r
620   /* Get process stuff. */\r
621   combo = GetDlgItem(tablist[NSSM_TAB_PROCESS], IDC_PRIORITY);\r
622   service->priority = priority_index_to_constant((unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0));\r
623 \r
624   service->affinity = 0LL;\r
625   if (! (SendDlgItemMessage(tablist[NSSM_TAB_PROCESS], IDC_AFFINITY_ALL, BM_GETCHECK, 0, 0) & BST_CHECKED)) {\r
626     HWND list = GetDlgItem(tablist[NSSM_TAB_PROCESS], IDC_AFFINITY);\r
627     int selected = (int) SendMessage(list, LB_GETSELCOUNT, 0, 0);\r
628     int count = (int) SendMessage(list, LB_GETCOUNT, 0, 0);\r
629     if (! selected) {\r
630       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_WARN_AFFINITY_NONE);\r
631       return 5;\r
632     }\r
633     else if (selected < count) {\r
634       for (int i = 0; i < count; i++) {\r
635         if (SendMessage(list, LB_GETSEL, i, 0)) service->affinity |= (1LL << (__int64) i);\r
636       }\r
637     }\r
638   }\r
639 \r
640   if (SendDlgItemMessage(tablist[NSSM_TAB_PROCESS], IDC_CONSOLE, BM_GETCHECK, 0, 0) & BST_CHECKED) service->no_console = 0;\r
641   else service->no_console = 1;\r
642 \r
643   /* Get stop method stuff. */\r
644   check_stop_method(service, NSSM_STOP_METHOD_CONSOLE, IDC_METHOD_CONSOLE);\r
645   check_stop_method(service, NSSM_STOP_METHOD_WINDOW, IDC_METHOD_WINDOW);\r
646   check_stop_method(service, NSSM_STOP_METHOD_THREADS, IDC_METHOD_THREADS);\r
647   check_stop_method(service, NSSM_STOP_METHOD_TERMINATE, IDC_METHOD_TERMINATE);\r
648   check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE, &service->kill_console_delay);\r
649   check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, &service->kill_window_delay);\r
650   check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, &service->kill_threads_delay);\r
651   if (SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_GETCHECK, 0, 0) & BST_CHECKED) service->kill_process_tree = 1;\r
652   else service->kill_process_tree = 0;\r
653 \r
654   /* Get exit action stuff. */\r
655   check_number(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, &service->throttle_delay);\r
656   combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT);\r
657   service->default_exit_action = (unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0);\r
658   if (service->default_exit_action == CB_ERR) service->default_exit_action = 0;\r
659   check_number(tablist[NSSM_TAB_EXIT], IDC_RESTART_DELAY, &service->restart_delay);\r
660 \r
661   /* Get I/O stuff. */\r
662   check_io(window, _T("stdin"), service->stdin_path, _countof(service->stdin_path), IDC_STDIN);\r
663   check_io(window, _T("stdout"), service->stdout_path, _countof(service->stdout_path), IDC_STDOUT);\r
664   check_io(window, _T("stderr"), service->stderr_path, _countof(service->stderr_path), IDC_STDERR);\r
665 \r
666   /* Override stdout and/or stderr. */\r
667   if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_TRUNCATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
668     if (service->stdout_path[0]) service->stdout_disposition = CREATE_ALWAYS;\r
669     if (service->stderr_path[0]) service->stderr_disposition = CREATE_ALWAYS;\r
670   }\r
671 \r
672   /* Get rotation stuff. */\r
673   if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
674     service->rotate_files = true;\r
675     if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_ONLINE, BM_GETCHECK, 0, 0) & BST_CHECKED) service->rotate_stdout_online = service->rotate_stderr_online = NSSM_ROTATE_ONLINE;\r
676     check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, &service->rotate_seconds);\r
677     check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, &service->rotate_bytes_low);\r
678   }\r
679 \r
680   /* Get hook stuff. */\r
681   if (SendDlgItemMessage(tablist[NSSM_TAB_HOOKS], IDC_REDIRECT_HOOK, BM_GETCHECK, 0, 0) & BST_CHECKED) service->hook_share_output_handles = true;\r
682 \r
683   /* Get environment. */\r
684   unsigned long envlen = (unsigned long) SendMessage(GetDlgItem(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT), WM_GETTEXTLENGTH, 0, 0);\r
685   if (envlen) {\r
686     TCHAR *env = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (envlen + 2) * sizeof(TCHAR));\r
687     if (! env) {\r
688       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("install()"));\r
689       cleanup_nssm_service(service);\r
690       return 5;\r
691     }\r
692 \r
693     if (! GetDlgItemText(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT, env, envlen + 1)) {\r
694       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_ENVIRONMENT);\r
695       HeapFree(GetProcessHeap(), 0, env);\r
696       cleanup_nssm_service(service);\r
697       return 5;\r
698     }\r
699 \r
700     TCHAR *newenv;\r
701     unsigned long newlen;\r
702     if (unformat_double_null(env, envlen, &newenv, &newlen)) {\r
703       HeapFree(GetProcessHeap(), 0, env);\r
704       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("install()"));\r
705       cleanup_nssm_service(service);\r
706       return 5;\r
707     }\r
708 \r
709     HeapFree(GetProcessHeap(), 0, env);\r
710     env = newenv;\r
711     envlen = newlen;\r
712 \r
713     /* Test the environment is valid. */\r
714     if (test_environment(env)) {\r
715       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_ENVIRONMENT);\r
716       HeapFree(GetProcessHeap(), 0, env);\r
717       cleanup_nssm_service(service);\r
718       return 5;\r
719     }\r
720 \r
721     if (SendDlgItemMessage(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT_REPLACE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
722       service->env = env;\r
723       service->envlen = envlen;\r
724     }\r
725     else {\r
726       service->env_extra = env;\r
727       service->env_extralen = envlen;\r
728     }\r
729   }\r
730 \r
731   return 0;\r
732 }\r
733 \r
734 /* Install the service. */\r
735 int install(HWND window) {\r
736   if (! window) return 1;\r
737 \r
738   nssm_service_t *service = alloc_nssm_service();\r
739   if (service) {\r
740     int ret = configure(window, service, 0);\r
741     if (ret) return ret;\r
742   }\r
743 \r
744   /* See if it works. */\r
745   switch (install_service(service)) {\r
746     case 1:\r
747       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("service"), _T("install()"));\r
748       cleanup_nssm_service(service);\r
749       return 1;\r
750 \r
751     case 2:\r
752       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
753       cleanup_nssm_service(service);\r
754       return 2;\r
755 \r
756     case 3:\r
757       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_PATH_TOO_LONG, NSSM);\r
758       cleanup_nssm_service(service);\r
759       return 3;\r
760 \r
761     case 4:\r
762       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_OUT_OF_MEMORY_FOR_IMAGEPATH);\r
763       cleanup_nssm_service(service);\r
764       return 4;\r
765 \r
766     case 5:\r
767       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INSTALL_SERVICE_FAILED);\r
768       cleanup_nssm_service(service);\r
769       return 5;\r
770 \r
771     case 6:\r
772       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_CREATE_PARAMETERS_FAILED);\r
773       cleanup_nssm_service(service);\r
774       return 6;\r
775   }\r
776 \r
777   update_hooks(service->name);\r
778 \r
779   popup_message(window, MB_OK, NSSM_MESSAGE_SERVICE_INSTALLED, service->name);\r
780   cleanup_nssm_service(service);\r
781   return 0;\r
782 }\r
783 \r
784 /* Remove the service */\r
785 int remove(HWND window) {\r
786   if (! window) return 1;\r
787 \r
788   /* See if it works */\r
789   nssm_service_t *service = alloc_nssm_service();\r
790   if (service) {\r
791     /* Get service name */\r
792     if (! GetDlgItemText(window, IDC_NAME, service->name, _countof(service->name))) {\r
793       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_SERVICE_NAME);\r
794       cleanup_nssm_service(service);\r
795       return 2;\r
796     }\r
797 \r
798     /* Confirm */\r
799     if (popup_message(window, MB_YESNO, NSSM_GUI_ASK_REMOVE_SERVICE, service->name) != IDYES) {\r
800       cleanup_nssm_service(service);\r
801       return 0;\r
802     }\r
803   }\r
804 \r
805   switch (remove_service(service)) {\r
806     case 1:\r
807       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("service"), _T("remove()"));\r
808       cleanup_nssm_service(service);\r
809       return 1;\r
810 \r
811     case 2:\r
812       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
813       cleanup_nssm_service(service);\r
814       return 2;\r
815 \r
816     case 3:\r
817       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_SERVICE_NOT_INSTALLED);\r
818       cleanup_nssm_service(service);\r
819       return 3;\r
820 \r
821     case 4:\r
822       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_REMOVE_SERVICE_FAILED);\r
823       cleanup_nssm_service(service);\r
824       return 4;\r
825   }\r
826 \r
827   popup_message(window, MB_OK, NSSM_MESSAGE_SERVICE_REMOVED, service->name);\r
828   cleanup_nssm_service(service);\r
829   return 0;\r
830 }\r
831 \r
832 int edit(HWND window, nssm_service_t *orig_service) {\r
833   if (! window) return 1;\r
834 \r
835   nssm_service_t *service = alloc_nssm_service();\r
836   if (service) {\r
837     int ret = configure(window, service, orig_service);\r
838     if (ret) return ret;\r
839   }\r
840 \r
841   switch (edit_service(service, true)) {\r
842     case 1:\r
843       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("service"), _T("edit()"));\r
844       cleanup_nssm_service(service);\r
845       return 1;\r
846 \r
847     case 3:\r
848       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_PATH_TOO_LONG, NSSM);\r
849       cleanup_nssm_service(service);\r
850       return 3;\r
851 \r
852     case 4:\r
853       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_OUT_OF_MEMORY_FOR_IMAGEPATH);\r
854       cleanup_nssm_service(service);\r
855       return 4;\r
856 \r
857     case 5:\r
858     case 6:\r
859       popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_EDIT_PARAMETERS_FAILED);\r
860       cleanup_nssm_service(service);\r
861       return 6;\r
862   }\r
863 \r
864   update_hooks(service->name);\r
865 \r
866   popup_message(window, MB_OK, NSSM_MESSAGE_SERVICE_EDITED, service->name);\r
867   cleanup_nssm_service(service);\r
868   return 0;\r
869 }\r
870 \r
871 static TCHAR *browse_filter(int message) {\r
872   switch (message) {\r
873     case NSSM_GUI_BROWSE_FILTER_APPLICATIONS: return _T("*.exe;*.bat;*.cmd");\r
874     case NSSM_GUI_BROWSE_FILTER_DIRECTORIES: return _T(".");\r
875     case NSSM_GUI_BROWSE_FILTER_ALL_FILES: /* Fall through. */\r
876     default: return _T("*.*");\r
877   }\r
878 }\r
879 \r
880 UINT_PTR CALLBACK browse_hook(HWND dlg, UINT message, WPARAM w, LPARAM l) {\r
881   switch (message) {\r
882     case WM_INITDIALOG:\r
883       return 1;\r
884   }\r
885 \r
886   return 0;\r
887 }\r
888 \r
889 /* Browse for application */\r
890 void browse(HWND window, TCHAR *current, unsigned long flags, ...) {\r
891   if (! window) return;\r
892 \r
893   va_list arg;\r
894   size_t bufsize = 256;\r
895   size_t len = bufsize;\r
896   int i;\r
897 \r
898   OPENFILENAME ofn;\r
899   ZeroMemory(&ofn, sizeof(ofn));\r
900   ofn.lStructSize = sizeof(ofn);\r
901   ofn.lpstrFilter = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, bufsize * sizeof(TCHAR));\r
902   /* XXX: Escaping nulls with FormatMessage is tricky */\r
903   if (ofn.lpstrFilter) {\r
904     ZeroMemory((void *) ofn.lpstrFilter, bufsize);\r
905     len = 0;\r
906     /* "Applications" + NULL + "*.exe" + NULL */\r
907     va_start(arg, flags);\r
908     while (i = va_arg(arg, int)) {\r
909       TCHAR *localised = message_string(i);\r
910       _sntprintf_s((TCHAR *) ofn.lpstrFilter + len, bufsize, _TRUNCATE, localised);\r
911       len += _tcslen(localised) + 1;\r
912       LocalFree(localised);\r
913       TCHAR *filter = browse_filter(i);\r
914       _sntprintf_s((TCHAR *) ofn.lpstrFilter + len, bufsize - len, _TRUNCATE, _T("%s"), filter);\r
915       len += _tcslen(filter) + 1;\r
916     }\r
917     va_end(arg);\r
918     /* Remainder of the buffer is already zeroed */\r
919   }\r
920   ofn.lpstrFile = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, PATH_LENGTH * sizeof(TCHAR));\r
921   if (ofn.lpstrFile) {\r
922     if (flags & OFN_NOVALIDATE) {\r
923       /* Directory hack. */\r
924       _sntprintf_s(ofn.lpstrFile, PATH_LENGTH, _TRUNCATE, _T(":%s:"), message_string(NSSM_GUI_BROWSE_FILTER_DIRECTORIES));\r
925       ofn.nMaxFile = DIR_LENGTH;\r
926     }\r
927     else {\r
928       _sntprintf_s(ofn.lpstrFile, PATH_LENGTH, _TRUNCATE, _T("%s"), current);\r
929       ofn.nMaxFile = PATH_LENGTH;\r
930     }\r
931   }\r
932   ofn.lpstrTitle = message_string(NSSM_GUI_BROWSE_TITLE);\r
933   ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | flags;\r
934 \r
935   if (GetOpenFileName(&ofn)) {\r
936     /* Directory hack. */\r
937     if (flags & OFN_NOVALIDATE) strip_basename(ofn.lpstrFile);\r
938     SendMessage(window, WM_SETTEXT, 0, (LPARAM) ofn.lpstrFile);\r
939   }\r
940   if (ofn.lpstrFilter) HeapFree(GetProcessHeap(), 0, (void *) ofn.lpstrFilter);\r
941   if (ofn.lpstrFile) HeapFree(GetProcessHeap(), 0, ofn.lpstrFile);\r
942 }\r
943 \r
944 INT_PTR CALLBACK tab_dlg(HWND tab, UINT message, WPARAM w, LPARAM l) {\r
945   switch (message) {\r
946     case WM_INITDIALOG:\r
947       return 1;\r
948 \r
949     /* Button was pressed or control was controlled. */\r
950     case WM_COMMAND:\r
951       HWND dlg;\r
952       TCHAR buffer[PATH_LENGTH];\r
953       unsigned char enabled;\r
954 \r
955       switch (LOWORD(w)) {\r
956         /* Browse for application. */\r
957         case IDC_BROWSE:\r
958           dlg = GetDlgItem(tab, IDC_PATH);\r
959           GetDlgItemText(tab, IDC_PATH, buffer, _countof(buffer));\r
960           browse(dlg, buffer, OFN_FILEMUSTEXIST, NSSM_GUI_BROWSE_FILTER_APPLICATIONS, NSSM_GUI_BROWSE_FILTER_ALL_FILES, 0);\r
961           /* Fill in startup directory if it wasn't already specified. */\r
962           GetDlgItemText(tab, IDC_DIR, buffer, _countof(buffer));\r
963           if (! buffer[0]) {\r
964             GetDlgItemText(tab, IDC_PATH, buffer, _countof(buffer));\r
965             strip_basename(buffer);\r
966             SetDlgItemText(tab, IDC_DIR, buffer);\r
967           }\r
968           break;\r
969 \r
970         /* Browse for startup directory. */\r
971         case IDC_BROWSE_DIR:\r
972           dlg = GetDlgItem(tab, IDC_DIR);\r
973           GetDlgItemText(tab, IDC_DIR, buffer, _countof(buffer));\r
974           browse(dlg, buffer, OFN_NOVALIDATE, NSSM_GUI_BROWSE_FILTER_DIRECTORIES, 0);\r
975           break;\r
976 \r
977         /* Log on. */\r
978         case IDC_LOCALSYSTEM:\r
979           set_logon_enabled(0);\r
980           break;\r
981 \r
982         case IDC_ACCOUNT:\r
983           set_logon_enabled(1);\r
984           break;\r
985 \r
986         /* Affinity. */\r
987         case IDC_AFFINITY_ALL:\r
988           if (SendDlgItemMessage(tab, LOWORD(w), BM_GETCHECK, 0, 0) & BST_CHECKED) enabled = 0;\r
989           else enabled = 1;\r
990           set_affinity_enabled(enabled);\r
991           break;\r
992 \r
993         /* Shutdown methods. */\r
994         case IDC_METHOD_CONSOLE:\r
995           set_timeout_enabled(LOWORD(w), IDC_KILL_CONSOLE);\r
996           break;\r
997 \r
998         case IDC_METHOD_WINDOW:\r
999           set_timeout_enabled(LOWORD(w), IDC_KILL_WINDOW);\r
1000           break;\r
1001 \r
1002         case IDC_METHOD_THREADS:\r
1003           set_timeout_enabled(LOWORD(w), IDC_KILL_THREADS);\r
1004           break;\r
1005 \r
1006         /* Browse for stdin. */\r
1007         case IDC_BROWSE_STDIN:\r
1008           dlg = GetDlgItem(tab, IDC_STDIN);\r
1009           GetDlgItemText(tab, IDC_STDIN, buffer, _countof(buffer));\r
1010           browse(dlg, buffer, 0, NSSM_GUI_BROWSE_FILTER_ALL_FILES, 0);\r
1011           break;\r
1012 \r
1013         /* Browse for stdout. */\r
1014         case IDC_BROWSE_STDOUT:\r
1015           dlg = GetDlgItem(tab, IDC_STDOUT);\r
1016           GetDlgItemText(tab, IDC_STDOUT, buffer, _countof(buffer));\r
1017           browse(dlg, buffer, 0, NSSM_GUI_BROWSE_FILTER_ALL_FILES, 0);\r
1018           /* Fill in stderr if it wasn't already specified. */\r
1019           GetDlgItemText(tab, IDC_STDERR, buffer, _countof(buffer));\r
1020           if (! buffer[0]) {\r
1021             GetDlgItemText(tab, IDC_STDOUT, buffer, _countof(buffer));\r
1022             SetDlgItemText(tab, IDC_STDERR, buffer);\r
1023           }\r
1024           break;\r
1025 \r
1026         /* Browse for stderr. */\r
1027         case IDC_BROWSE_STDERR:\r
1028           dlg = GetDlgItem(tab, IDC_STDERR);\r
1029           GetDlgItemText(tab, IDC_STDERR, buffer, _countof(buffer));\r
1030           browse(dlg, buffer, 0, NSSM_GUI_BROWSE_FILTER_ALL_FILES, 0);\r
1031           break;\r
1032 \r
1033         /* Rotation. */\r
1034         case IDC_ROTATE:\r
1035           if (SendDlgItemMessage(tab, LOWORD(w), BM_GETCHECK, 0, 0) & BST_CHECKED) enabled = 1;\r
1036           else enabled = 0;\r
1037           set_rotation_enabled(enabled);\r
1038           break;\r
1039 \r
1040         /* Hook event. */\r
1041         case IDC_HOOK_EVENT:\r
1042           if (HIWORD(w) == CBN_SELCHANGE) set_hook_tab((int) SendMessage(GetDlgItem(tab, IDC_HOOK_EVENT), CB_GETCURSEL, 0, 0), 0, false);\r
1043           break;\r
1044 \r
1045         /* Hook action. */\r
1046         case IDC_HOOK_ACTION:\r
1047           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
1048           break;\r
1049 \r
1050         /* Browse for hook. */\r
1051         case IDC_BROWSE_HOOK:\r
1052           dlg = GetDlgItem(tab, IDC_HOOK);\r
1053           GetDlgItemText(tab, IDC_HOOK, buffer, _countof(buffer));\r
1054           browse(dlg, _T(""), OFN_FILEMUSTEXIST, NSSM_GUI_BROWSE_FILTER_ALL_FILES, 0);\r
1055           break;\r
1056 \r
1057         /* Hook. */\r
1058         case IDC_HOOK:\r
1059           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
1060           break;\r
1061       }\r
1062       return 1;\r
1063   }\r
1064 \r
1065   return 0;\r
1066 }\r
1067 \r
1068 /* Install/remove dialogue callback */\r
1069 INT_PTR CALLBACK nssm_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {\r
1070   nssm_service_t *service;\r
1071 \r
1072   switch (message) {\r
1073     /* Creating the dialogue */\r
1074     case WM_INITDIALOG:\r
1075       service = (nssm_service_t *) l;\r
1076 \r
1077       SetFocus(GetDlgItem(window, IDC_NAME));\r
1078 \r
1079       HWND tabs;\r
1080       HWND combo;\r
1081       HWND list;\r
1082       int i, n;\r
1083       tabs = GetDlgItem(window, IDC_TAB1);\r
1084       if (! tabs) return 0;\r
1085 \r
1086       /* Set up tabs. */\r
1087       TCITEM tab;\r
1088       ZeroMemory(&tab, sizeof(tab));\r
1089       tab.mask = TCIF_TEXT;\r
1090 \r
1091       selected_tab = 0;\r
1092 \r
1093       /* Application tab. */\r
1094       if (service->native) tab.pszText = message_string(NSSM_GUI_TAB_NATIVE);\r
1095       else tab.pszText = message_string(NSSM_GUI_TAB_APPLICATION);\r
1096       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
1097       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_APPLICATION, (LPARAM) &tab);\r
1098       if (service->native) {\r
1099         tablist[NSSM_TAB_APPLICATION] = dialog(MAKEINTRESOURCE(IDD_NATIVE), window, tab_dlg);\r
1100         EnableWindow(tablist[NSSM_TAB_APPLICATION], 0);\r
1101         EnableWindow(GetDlgItem(tablist[NSSM_TAB_APPLICATION], IDC_PATH), 0);\r
1102       }\r
1103       else tablist[NSSM_TAB_APPLICATION] = dialog(MAKEINTRESOURCE(IDD_APPLICATION), window, tab_dlg);\r
1104       ShowWindow(tablist[NSSM_TAB_APPLICATION], SW_SHOW);\r
1105 \r
1106       /* Details tab. */\r
1107       tab.pszText = message_string(NSSM_GUI_TAB_DETAILS);\r
1108       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
1109       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_DETAILS, (LPARAM) &tab);\r
1110       tablist[NSSM_TAB_DETAILS] = dialog(MAKEINTRESOURCE(IDD_DETAILS), window, tab_dlg);\r
1111       ShowWindow(tablist[NSSM_TAB_DETAILS], SW_HIDE);\r
1112 \r
1113       /* Set defaults. */\r
1114       combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP);\r
1115       SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_AUTOMATIC, (LPARAM) message_string(NSSM_GUI_STARTUP_AUTOMATIC));\r
1116       SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_DELAYED, (LPARAM) message_string(NSSM_GUI_STARTUP_DELAYED));\r
1117       SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_MANUAL, (LPARAM) message_string(NSSM_GUI_STARTUP_MANUAL));\r
1118       SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_DISABLED, (LPARAM) message_string(NSSM_GUI_STARTUP_DISABLED));\r
1119       SendMessage(combo, CB_SETCURSEL, NSSM_STARTUP_AUTOMATIC, 0);\r
1120 \r
1121       /* Logon tab. */\r
1122       tab.pszText = message_string(NSSM_GUI_TAB_LOGON);\r
1123       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
1124       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_LOGON, (LPARAM) &tab);\r
1125       tablist[NSSM_TAB_LOGON] = dialog(MAKEINTRESOURCE(IDD_LOGON), window, tab_dlg);\r
1126       ShowWindow(tablist[NSSM_TAB_LOGON], SW_HIDE);\r
1127 \r
1128       /* Set defaults. */\r
1129       CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
1130       set_logon_enabled(0);\r
1131 \r
1132       /* Dependencies tab. */\r
1133       tab.pszText = message_string(NSSM_GUI_TAB_DEPENDENCIES);\r
1134       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
1135       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_DEPENDENCIES, (LPARAM) &tab);\r
1136       tablist[NSSM_TAB_DEPENDENCIES] = dialog(MAKEINTRESOURCE(IDD_DEPENDENCIES), window, tab_dlg);\r
1137       ShowWindow(tablist[NSSM_TAB_DEPENDENCIES], SW_HIDE);\r
1138 \r
1139       /* Remaining tabs are only for services we manage. */\r
1140       if (service->native) return 1;\r
1141 \r
1142       /* Process tab. */\r
1143       tab.pszText = message_string(NSSM_GUI_TAB_PROCESS);\r
1144       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
1145       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_PROCESS, (LPARAM) &tab);\r
1146       tablist[NSSM_TAB_PROCESS] = dialog(MAKEINTRESOURCE(IDD_PROCESS), window, tab_dlg);\r
1147       ShowWindow(tablist[NSSM_TAB_PROCESS], SW_HIDE);\r
1148 \r
1149       /* Set defaults. */\r
1150       combo = GetDlgItem(tablist[NSSM_TAB_PROCESS], IDC_PRIORITY);\r
1151       SendMessage(combo, CB_INSERTSTRING, NSSM_REALTIME_PRIORITY, (LPARAM) message_string(NSSM_GUI_REALTIME_PRIORITY_CLASS));\r
1152       SendMessage(combo, CB_INSERTSTRING, NSSM_HIGH_PRIORITY, (LPARAM) message_string(NSSM_GUI_HIGH_PRIORITY_CLASS));\r
1153       SendMessage(combo, CB_INSERTSTRING, NSSM_ABOVE_NORMAL_PRIORITY, (LPARAM) message_string(NSSM_GUI_ABOVE_NORMAL_PRIORITY_CLASS));\r
1154       SendMessage(combo, CB_INSERTSTRING, NSSM_NORMAL_PRIORITY, (LPARAM) message_string(NSSM_GUI_NORMAL_PRIORITY_CLASS));\r
1155       SendMessage(combo, CB_INSERTSTRING, NSSM_BELOW_NORMAL_PRIORITY, (LPARAM) message_string(NSSM_GUI_BELOW_NORMAL_PRIORITY_CLASS));\r
1156       SendMessage(combo, CB_INSERTSTRING, NSSM_IDLE_PRIORITY, (LPARAM) message_string(NSSM_GUI_IDLE_PRIORITY_CLASS));\r
1157       SendMessage(combo, CB_SETCURSEL, NSSM_NORMAL_PRIORITY, 0);\r
1158 \r
1159       SendDlgItemMessage(tablist[NSSM_TAB_PROCESS], IDC_CONSOLE, BM_SETCHECK, BST_CHECKED, 0);\r
1160 \r
1161       list = GetDlgItem(tablist[NSSM_TAB_PROCESS], IDC_AFFINITY);\r
1162       n = num_cpus();\r
1163       SendMessage(list, LB_SETCOLUMNWIDTH, 16, 0);\r
1164       for (i = 0; i < n; i++) {\r
1165         TCHAR buffer[3];\r
1166         _sntprintf_s(buffer, _countof(buffer), _TRUNCATE, _T("%d"), i);\r
1167         SendMessage(list, LB_ADDSTRING, 0, (LPARAM) buffer);\r
1168       }\r
1169 \r
1170       /*\r
1171         Size to fit.\r
1172         The box is high enough for four rows.  It is wide enough for eight\r
1173         columns without scrolling.  With scrollbars it shrinks to two rows.\r
1174         Note that the above only holds if we set the column width BEFORE\r
1175         adding the strings.\r
1176       */\r
1177       if (n < 32) {\r
1178         int columns = (n - 1) / 4;\r
1179         RECT rect;\r
1180         GetWindowRect(list, &rect);\r
1181         int width = rect.right - rect.left;\r
1182         width -= (7 - columns) * 16;\r
1183         int height = rect.bottom - rect.top;\r
1184         if (n < 4) height -= (int) SendMessage(list, LB_GETITEMHEIGHT, 0, 0) * (4 - n);\r
1185         SetWindowPos(list, 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOOWNERZORDER);\r
1186       }\r
1187       SendMessage(list, LB_SELITEMRANGE, 1, MAKELPARAM(0, n));\r
1188 \r
1189       SendDlgItemMessage(tablist[NSSM_TAB_PROCESS], IDC_AFFINITY_ALL, BM_SETCHECK, BST_CHECKED, 0);\r
1190       set_affinity_enabled(0);\r
1191 \r
1192       /* Shutdown tab. */\r
1193       tab.pszText = message_string(NSSM_GUI_TAB_SHUTDOWN);\r
1194       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
1195       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_SHUTDOWN, (LPARAM) &tab);\r
1196       tablist[NSSM_TAB_SHUTDOWN] = dialog(MAKEINTRESOURCE(IDD_SHUTDOWN), window, tab_dlg);\r
1197       ShowWindow(tablist[NSSM_TAB_SHUTDOWN], SW_HIDE);\r
1198 \r
1199       /* Set defaults. */\r
1200       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_CONSOLE, BM_SETCHECK, BST_CHECKED, 0);\r
1201       SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE, NSSM_KILL_CONSOLE_GRACE_PERIOD, 0);\r
1202       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_WINDOW, BM_SETCHECK, BST_CHECKED, 0);\r
1203       SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, NSSM_KILL_WINDOW_GRACE_PERIOD, 0);\r
1204       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_THREADS, BM_SETCHECK, BST_CHECKED, 0);\r
1205       SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, NSSM_KILL_THREADS_GRACE_PERIOD, 0);\r
1206       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_TERMINATE, BM_SETCHECK, BST_CHECKED, 0);\r
1207       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_SETCHECK, BST_CHECKED, 1);\r
1208 \r
1209       /* Restart tab. */\r
1210       tab.pszText = message_string(NSSM_GUI_TAB_EXIT);\r
1211       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
1212       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_EXIT, (LPARAM) &tab);\r
1213       tablist[NSSM_TAB_EXIT] = dialog(MAKEINTRESOURCE(IDD_APPEXIT), window, tab_dlg);\r
1214       ShowWindow(tablist[NSSM_TAB_EXIT], SW_HIDE);\r
1215 \r
1216       /* Set defaults. */\r
1217       SetDlgItemInt(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, NSSM_RESET_THROTTLE_RESTART, 0);\r
1218       combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT);\r
1219       SendMessage(combo, CB_INSERTSTRING, NSSM_EXIT_RESTART, (LPARAM) message_string(NSSM_GUI_EXIT_RESTART));\r
1220       SendMessage(combo, CB_INSERTSTRING, NSSM_EXIT_IGNORE, (LPARAM) message_string(NSSM_GUI_EXIT_IGNORE));\r
1221       SendMessage(combo, CB_INSERTSTRING, NSSM_EXIT_REALLY, (LPARAM) message_string(NSSM_GUI_EXIT_REALLY));\r
1222       SendMessage(combo, CB_INSERTSTRING, NSSM_EXIT_UNCLEAN, (LPARAM) message_string(NSSM_GUI_EXIT_UNCLEAN));\r
1223       SendMessage(combo, CB_SETCURSEL, NSSM_EXIT_RESTART, 0);\r
1224       SetDlgItemInt(tablist[NSSM_TAB_EXIT], IDC_RESTART_DELAY, 0, 0);\r
1225 \r
1226       /* I/O tab. */\r
1227       tab.pszText = message_string(NSSM_GUI_TAB_IO);\r
1228       tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;\r
1229       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_IO, (LPARAM) &tab);\r
1230       tablist[NSSM_TAB_IO] = dialog(MAKEINTRESOURCE(IDD_IO), window, tab_dlg);\r
1231       ShowWindow(tablist[NSSM_TAB_IO], SW_HIDE);\r
1232 \r
1233       /* Rotation tab. */\r
1234       tab.pszText = message_string(NSSM_GUI_TAB_ROTATION);\r
1235       tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;\r
1236       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_ROTATION, (LPARAM) &tab);\r
1237       tablist[NSSM_TAB_ROTATION] = dialog(MAKEINTRESOURCE(IDD_ROTATION), window, tab_dlg);\r
1238       ShowWindow(tablist[NSSM_TAB_ROTATION], SW_HIDE);\r
1239 \r
1240       /* Set defaults. */\r
1241       SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_ONLINE, BM_SETCHECK, BST_UNCHECKED, 0);\r
1242       SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, 0, 0);\r
1243       SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, 0, 0);\r
1244       set_rotation_enabled(0);\r
1245 \r
1246       /* Environment tab. */\r
1247       tab.pszText = message_string(NSSM_GUI_TAB_ENVIRONMENT);\r
1248       tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;\r
1249       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_ENVIRONMENT, (LPARAM) &tab);\r
1250       tablist[NSSM_TAB_ENVIRONMENT] = dialog(MAKEINTRESOURCE(IDD_ENVIRONMENT), window, tab_dlg);\r
1251       ShowWindow(tablist[NSSM_TAB_ENVIRONMENT], SW_HIDE);\r
1252 \r
1253       /* Hooks tab. */\r
1254       tab.pszText = message_string(NSSM_GUI_TAB_HOOKS);\r
1255       tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;\r
1256       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_HOOKS, (LPARAM) &tab);\r
1257       tablist[NSSM_TAB_HOOKS] = dialog(MAKEINTRESOURCE(IDD_HOOKS), window, tab_dlg);\r
1258       ShowWindow(tablist[NSSM_TAB_HOOKS], SW_HIDE);\r
1259 \r
1260       /* Set defaults. */\r
1261       combo = GetDlgItem(tablist[NSSM_TAB_HOOKS], IDC_HOOK_EVENT);\r
1262       SendMessage(combo, CB_INSERTSTRING, -1, (LPARAM) message_string(NSSM_GUI_HOOK_EVENT_START));\r
1263       SendMessage(combo, CB_INSERTSTRING, -1, (LPARAM) message_string(NSSM_GUI_HOOK_EVENT_STOP));\r
1264       SendMessage(combo, CB_INSERTSTRING, -1, (LPARAM) message_string(NSSM_GUI_HOOK_EVENT_EXIT));\r
1265       SendMessage(combo, CB_INSERTSTRING, -1, (LPARAM) message_string(NSSM_GUI_HOOK_EVENT_POWER));\r
1266       SendMessage(combo, CB_INSERTSTRING, -1, (LPARAM) message_string(NSSM_GUI_HOOK_EVENT_ROTATE));\r
1267       SendDlgItemMessage(tablist[NSSM_TAB_HOOKS], IDC_REDIRECT_HOOK, BM_SETCHECK, BST_UNCHECKED, 0);\r
1268       if (_tcslen(service->name)) {\r
1269         TCHAR hook_name[HOOK_NAME_LENGTH];\r
1270         TCHAR cmd[CMD_LENGTH];\r
1271         for (i = 0; hook_event_strings[i]; i++) {\r
1272           const TCHAR *hook_event = hook_event_strings[i];\r
1273           int j;\r
1274           for (j = 0; hook_action_strings[j]; j++) {\r
1275             const TCHAR *hook_action = hook_action_strings[j];\r
1276             if (! valid_hook_name(hook_event, hook_action, true)) continue;\r
1277             if (get_hook(service->name, hook_event, hook_action, cmd, sizeof(cmd))) continue;\r
1278             if (hook_env(hook_event, hook_action, hook_name, _countof(hook_name)) < 0) continue;\r
1279             SetEnvironmentVariable(hook_name, cmd);\r
1280           }\r
1281         }\r
1282       }\r
1283       set_hook_tab(0, 0, false);\r
1284 \r
1285       return 1;\r
1286 \r
1287     /* Tab change. */\r
1288     case WM_NOTIFY:\r
1289       NMHDR *notification;\r
1290 \r
1291       notification = (NMHDR *) l;\r
1292       switch (notification->code) {\r
1293         case TCN_SELCHANGE:\r
1294           HWND tabs;\r
1295           int selection;\r
1296 \r
1297           tabs = GetDlgItem(window, IDC_TAB1);\r
1298           if (! tabs) return 0;\r
1299 \r
1300           selection = (int) SendMessage(tabs, TCM_GETCURSEL, 0, 0);\r
1301           if (selection != selected_tab) {\r
1302             ShowWindow(tablist[selected_tab], SW_HIDE);\r
1303             ShowWindow(tablist[selection], SW_SHOWDEFAULT);\r
1304             SetFocus(GetDlgItem(window, IDOK));\r
1305             selected_tab = selection;\r
1306           }\r
1307           return 1;\r
1308       }\r
1309 \r
1310       return 0;\r
1311 \r
1312     /* Button was pressed or control was controlled */\r
1313     case WM_COMMAND:\r
1314       switch (LOWORD(w)) {\r
1315         /* OK button */\r
1316         case IDOK:\r
1317           if ((int) GetWindowLongPtr(window, GWLP_USERDATA) == IDD_EDIT) {\r
1318             if (! edit(window, (nssm_service_t *) GetWindowLongPtr(window, DWLP_USER))) PostQuitMessage(0);\r
1319           }\r
1320           else if (! install(window)) PostQuitMessage(0);\r
1321           break;\r
1322 \r
1323         /* Cancel button */\r
1324         case IDCANCEL:\r
1325           DestroyWindow(window);\r
1326           break;\r
1327 \r
1328         /* Remove button */\r
1329         case IDC_REMOVE:\r
1330           if (! remove(window)) PostQuitMessage(0);\r
1331           break;\r
1332       }\r
1333       return 1;\r
1334 \r
1335     /* Window closing */\r
1336     case WM_CLOSE:\r
1337       DestroyWindow(window);\r
1338       return 0;\r
1339     case WM_DESTROY:\r
1340       PostQuitMessage(0);\r
1341   }\r
1342   return 0;\r
1343 }\r