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