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