Fixed loading localised resources.
[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_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS };\r
4 static HWND tablist[NSSM_NUM_TABS];\r
5 static int selected_tab;\r
6 \r
7 static HWND dialog(const TCHAR *templ, HWND parent, DLGPROC function, LPARAM l) {\r
8   /* The caller will deal with GetLastError()... */\r
9   HRSRC resource = FindResourceEx(0, RT_DIALOG, templ, GetUserDefaultLangID());\r
10   if (! resource) {\r
11     if (GetLastError() != ERROR_RESOURCE_LANG_NOT_FOUND) return 0;\r
12     resource = FindResourceEx(0, RT_DIALOG, templ, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));\r
13     if (! resource) return 0;\r
14   }\r
15 \r
16   HGLOBAL ret = LoadResource(0, resource);\r
17   if (! ret) return 0;\r
18 \r
19   return CreateDialogIndirectParam(0, (DLGTEMPLATE *) ret, parent, function, l);\r
20 }\r
21 \r
22 static HWND dialog(const TCHAR *templ, HWND parent, DLGPROC function) {\r
23   return dialog(templ, parent, function, 0);\r
24 }\r
25 \r
26 int nssm_gui(int resource, nssm_service_t *service) {\r
27   /* Create window */\r
28   HWND dlg = dialog(MAKEINTRESOURCE(resource), 0, nssm_dlg, (LPARAM) service);\r
29   if (! dlg) {\r
30     popup_message(MB_OK, NSSM_GUI_CREATEDIALOG_FAILED, error_string(GetLastError()));\r
31     return 1;\r
32   }\r
33 \r
34   /* Remember what the window is for. */\r
35   SetWindowLongPtr(dlg, GWLP_USERDATA, (LONG_PTR) resource);\r
36 \r
37   /* Display the window */\r
38   centre_window(dlg);\r
39   ShowWindow(dlg, SW_SHOW);\r
40 \r
41   /* Set service name if given */\r
42   if (service->name[0]) {\r
43     SetDlgItemText(dlg, IDC_NAME, service->name);\r
44     /* No point making user click remove if the name is already entered */\r
45     if (resource == IDD_REMOVE) {\r
46       HWND button = GetDlgItem(dlg, IDC_REMOVE);\r
47       if (button) {\r
48         SendMessage(button, WM_LBUTTONDOWN, 0, 0);\r
49         SendMessage(button, WM_LBUTTONUP, 0, 0);\r
50       }\r
51     }\r
52   }\r
53 \r
54   if (resource == IDD_EDIT) {\r
55     /* We'll need the service handle later. */\r
56     SetWindowLongPtr(dlg, DWLP_USER, (LONG_PTR) service);\r
57 \r
58     /* Service name can't be edited. */\r
59     EnableWindow(GetDlgItem(dlg, IDC_NAME), 0);\r
60     SetFocus(GetDlgItem(dlg, IDOK));\r
61 \r
62     /* Set existing details. */\r
63     HWND combo;\r
64 \r
65     /* Application tab. */\r
66     if (service->native) SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_PATH, service->image);\r
67     else SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_PATH, service->exe);\r
68     SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_DIR, service->dir);\r
69     SetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_FLAGS, service->flags);\r
70 \r
71     /* Details tab. */\r
72     SetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME, service->displayname);\r
73     SetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION, service->description);\r
74     combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP);\r
75     SendMessage(combo, CB_SETCURSEL, service->startup, 0);\r
76 \r
77     /* Log on tab. */\r
78     if (service->username) {\r
79       CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_ACCOUNT);\r
80       SetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username);\r
81       EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_INTERACT), 0);\r
82       EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), 1);\r
83       EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), 1);\r
84       EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), 1);\r
85     }\r
86     else {\r
87       CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
88       if (service->type & SERVICE_INTERACTIVE_PROCESS) SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_INTERACT, BM_SETCHECK, BST_CHECKED, 0);\r
89     }\r
90 \r
91     /* Shutdown tab. */\r
92     if (! (service->stop_method & NSSM_STOP_METHOD_CONSOLE)) {\r
93       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_CONSOLE, BM_SETCHECK, BST_UNCHECKED, 0);\r
94       EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE), 0);\r
95     }\r
96     SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE, service->kill_console_delay, 0);\r
97     if (! (service->stop_method & NSSM_STOP_METHOD_WINDOW)) {\r
98       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_WINDOW, BM_SETCHECK, BST_UNCHECKED, 0);\r
99       EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW), 0);\r
100     }\r
101     SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, service->kill_window_delay, 0);\r
102     if (! (service->stop_method & NSSM_STOP_METHOD_THREADS)) {\r
103       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_THREADS, BM_SETCHECK, BST_UNCHECKED, 0);\r
104       EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS), 0);\r
105     }\r
106     SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, service->kill_threads_delay, 0);\r
107     if (! (service->stop_method & NSSM_STOP_METHOD_TERMINATE)) {\r
108       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_TERMINATE, BM_SETCHECK, BST_UNCHECKED, 0);\r
109     }\r
110 \r
111     /* Restart tab. */\r
112     SetDlgItemInt(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, service->throttle_delay, 0);\r
113     combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT);\r
114     SendMessage(combo, CB_SETCURSEL, service->default_exit_action, 0);\r
115 \r
116     /* I/O tab. */\r
117     SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDIN, service->stdin_path);\r
118     SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDOUT, service->stdout_path);\r
119     SetDlgItemText(tablist[NSSM_TAB_IO], IDC_STDERR, service->stderr_path);\r
120 \r
121     /* Rotation tab. */\r
122     if (service->stdout_disposition == CREATE_ALWAYS) SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_TRUNCATE, BM_SETCHECK, BST_CHECKED, 0);\r
123     if (service->rotate_files) {\r
124       SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_SETCHECK, BST_CHECKED, 0);\r
125       EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS), 1);\r
126       EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW), 1);\r
127     }\r
128     SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, service->rotate_seconds, 0);\r
129     if (! service->rotate_bytes_high) SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, service->rotate_bytes_low, 0);\r
130 \r
131     /* Check if advanced settings are in use. */\r
132     if (service->stdout_disposition ^ service->stderr_disposition || service->stdout_disposition & ~CREATE_ALWAYS || service->stderr_disposition & ~CREATE_ALWAYS) popup_message(MB_OK | MB_ICONWARNING, NSSM_GUI_WARN_STDIO);\r
133     if (service->rotate_bytes_high) popup_message(MB_OK | MB_ICONWARNING, NSSM_GUI_WARN_ROTATE_BYTES);\r
134 \r
135     /* Environment tab. */\r
136     TCHAR *env;\r
137     unsigned long envlen;\r
138     if (service->env_extralen) {\r
139       SendDlgItemMessage(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT_REPLACE, BM_SETCHECK, BST_CHECKED, 0);\r
140       env = service->env_extra;\r
141       envlen = service->env_extralen;\r
142     }\r
143     else {\r
144       env = service->env;\r
145       envlen = service->envlen;\r
146     }\r
147 \r
148     if (envlen) {\r
149       /* Replace NULL with CRLF. Leave NULL NULL as the end marker. */\r
150       unsigned long i, j;\r
151       unsigned long newlen = envlen;\r
152       for (i = 0; i < envlen; i++) if (! env[i] && env[i + 1]) newlen++;\r
153 \r
154       TCHAR *formatted = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newlen * sizeof(TCHAR));\r
155       if (formatted) {\r
156         for (i = 0, j = 0; i < envlen; i++) {\r
157           formatted[j] = env[i];\r
158           if (! env[i]) {\r
159             if (env[i + 1]) {\r
160               formatted[j] = _T('\r');\r
161               formatted[++j] = _T('\n');\r
162             }\r
163           }\r
164           j++;\r
165         }\r
166         SetDlgItemText(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT, formatted);\r
167         HeapFree(GetProcessHeap(), 0, formatted);\r
168       }\r
169       else popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("nssm_dlg()"));\r
170     }\r
171     if (service->envlen && service->env_extralen) popup_message(MB_OK | MB_ICONWARNING, NSSM_GUI_WARN_ENVIRONMENT);\r
172   }\r
173 \r
174   /* Go! */\r
175   MSG message;\r
176   while (GetMessage(&message, 0, 0, 0)) {\r
177     if (IsDialogMessage(dlg, &message)) continue;\r
178     TranslateMessage(&message);\r
179     DispatchMessage(&message);\r
180   }\r
181 \r
182   return (int) message.wParam;\r
183 }\r
184 \r
185 void centre_window(HWND window) {\r
186   HWND desktop;\r
187   RECT size, desktop_size;\r
188   unsigned long x, y;\r
189 \r
190   if (! window) return;\r
191 \r
192   /* Find window size */\r
193   if (! GetWindowRect(window, &size)) return;\r
194 \r
195   /* Find desktop window */\r
196   desktop = GetDesktopWindow();\r
197   if (! desktop) return;\r
198 \r
199   /* Find desktop window size */\r
200   if (! GetWindowRect(desktop, &desktop_size)) return;\r
201 \r
202   /* Centre window */\r
203   x = (desktop_size.right - size.right) / 2;\r
204   y = (desktop_size.bottom - size.bottom) / 2;\r
205   MoveWindow(window, x, y, size.right - size.left, size.bottom - size.top, 0);\r
206 }\r
207 \r
208 static inline void check_stop_method(nssm_service_t *service, unsigned long method, unsigned long control) {\r
209   if (SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], control, BM_GETCHECK, 0, 0) & BST_CHECKED) return;\r
210   service->stop_method &= ~method;\r
211 }\r
212 \r
213 static inline void check_number(HWND tab, unsigned long control, unsigned long *timeout) {\r
214   BOOL translated;\r
215   unsigned long configured = GetDlgItemInt(tab, control, &translated, 0);\r
216   if (translated) *timeout = configured;\r
217 }\r
218 \r
219 static inline void set_timeout_enabled(unsigned long control, unsigned long dependent) {\r
220   unsigned char enabled = 0;\r
221   if (SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], control, BM_GETCHECK, 0, 0) & BST_CHECKED) enabled = 1;\r
222   EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], dependent), enabled);\r
223 }\r
224 \r
225 static inline void set_logon_enabled(unsigned char enabled) {\r
226   EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_INTERACT), ! enabled);\r
227   EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), enabled);\r
228   EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), enabled);\r
229   EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), enabled);\r
230 }\r
231 \r
232 static inline void set_rotation_enabled(unsigned char enabled) {\r
233   EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS), enabled);\r
234   EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW), enabled);\r
235 }\r
236 \r
237 static inline void check_io(TCHAR *name, TCHAR *buffer, unsigned long len, unsigned long control) {\r
238   if (! SendMessage(GetDlgItem(tablist[NSSM_TAB_IO], control), WM_GETTEXTLENGTH, 0, 0)) return;\r
239   if (GetDlgItemText(tablist[NSSM_TAB_IO], control, buffer, (int) len)) return;\r
240   popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_PATH_TOO_LONG, name);\r
241   ZeroMemory(buffer, len * sizeof(TCHAR));\r
242 }\r
243 \r
244 /* Set service parameters. */\r
245 int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service) {\r
246   if (! service) return 1;\r
247 \r
248   set_nssm_service_defaults(service);\r
249 \r
250   if (orig_service) {\r
251     service->native = orig_service->native;\r
252     service->handle = orig_service->handle;\r
253   }\r
254 \r
255   /* Get service name. */\r
256   if (! GetDlgItemText(window, IDC_NAME, service->name, _countof(service->name))) {\r
257     popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_SERVICE_NAME);\r
258     cleanup_nssm_service(service);\r
259     return 2;\r
260   }\r
261 \r
262   /* Get executable name */\r
263   if (! service->native) {\r
264     if (! GetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_PATH, service->exe, _countof(service->exe))) {\r
265       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PATH);\r
266       return 3;\r
267     }\r
268 \r
269     /* Get startup directory. */\r
270     if (! GetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_DIR, service->dir, _countof(service->dir))) {\r
271       _sntprintf_s(service->dir, _countof(service->dir), _TRUNCATE, _T("%s"), service->exe);\r
272       strip_basename(service->dir);\r
273     }\r
274 \r
275     /* Get flags. */\r
276     if (SendMessage(GetDlgItem(tablist[NSSM_TAB_APPLICATION], IDC_FLAGS), WM_GETTEXTLENGTH, 0, 0)) {\r
277       if (! GetDlgItemText(tablist[NSSM_TAB_APPLICATION], IDC_FLAGS, service->flags, _countof(service->flags))) {\r
278         popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_OPTIONS);\r
279         return 4;\r
280       }\r
281     }\r
282   }\r
283 \r
284   /* Get details. */\r
285   if (SendMessage(GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME), WM_GETTEXTLENGTH, 0, 0)) {\r
286     if (! GetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DISPLAYNAME, service->displayname, _countof(service->displayname))) {\r
287       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DISPLAYNAME);\r
288       return 5;\r
289     }\r
290   }\r
291 \r
292   if (SendMessage(GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION), WM_GETTEXTLENGTH, 0, 0)) {\r
293     if (! GetDlgItemText(tablist[NSSM_TAB_DETAILS], IDC_DESCRIPTION, service->description, _countof(service->description))) {\r
294       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_DESCRIPTION);\r
295       return 5;\r
296     }\r
297   }\r
298 \r
299   HWND combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP);\r
300   service->startup = (unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0);\r
301   if (service->startup == CB_ERR) service->startup = 0;\r
302 \r
303   /* Get logon stuff. */\r
304   if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
305     if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_INTERACT, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
306       service->type |= SERVICE_INTERACTIVE_PROCESS;\r
307     }\r
308     if (service->username) HeapFree(GetProcessHeap(), 0, service->username);\r
309     service->username = 0;\r
310     service->usernamelen = 0;\r
311     if (service->password) {\r
312       SecureZeroMemory(service->password, service->passwordlen);\r
313       HeapFree(GetProcessHeap(), 0, service->password);\r
314     }\r
315     service->password = 0;\r
316     service->passwordlen = 0;\r
317   }\r
318   else {\r
319     /* Username. */\r
320     service->usernamelen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), WM_GETTEXTLENGTH, 0, 0);\r
321     if (! service->usernamelen) {\r
322       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_USERNAME);\r
323       return 6;\r
324     }\r
325     service->usernamelen++;\r
326 \r
327     service->username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->usernamelen * sizeof(TCHAR));\r
328     if (! service->username) {\r
329       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("account name"), _T("install()"));\r
330       return 6;\r
331     }\r
332     if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username, (int) service->usernamelen)) {\r
333       HeapFree(GetProcessHeap(), 0, service->username);\r
334       service->username = 0;\r
335       service->usernamelen = 0;\r
336       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_USERNAME);\r
337       return 6;\r
338     }\r
339 \r
340     /*\r
341       Special case LOCALSYSTEM.\r
342       Ignore the password if we're editing and the username hasn't changed.\r
343     */\r
344     if (str_equiv(service->username, NSSM_LOCALSYSTEM_ACCOUNT)) {\r
345       HeapFree(GetProcessHeap(), 0, service->username);\r
346       service->username = 0;\r
347       service->usernamelen = 0;\r
348     }\r
349     else {\r
350       /* Password. */\r
351       service->passwordlen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), WM_GETTEXTLENGTH, 0, 0);\r
352       size_t passwordlen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), WM_GETTEXTLENGTH, 0, 0);\r
353 \r
354       if (! orig_service || ! orig_service->username || ! str_equiv(service->username, orig_service->username) || service->passwordlen || passwordlen) {\r
355         if (! service->passwordlen) {\r
356           popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PASSWORD);\r
357           return 6;\r
358         }\r
359         if (passwordlen != service->passwordlen) {\r
360           popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PASSWORD);\r
361           return 6;\r
362         }\r
363         service->passwordlen++;\r
364 \r
365         /* Temporary buffer for password validation. */\r
366         TCHAR *password = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->passwordlen * sizeof(TCHAR));\r
367         if (! password) {\r
368           HeapFree(GetProcessHeap(), 0, service->username);\r
369           service->username = 0;\r
370           service->usernamelen = 0;\r
371           popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("password confirmation"), _T("install()"));\r
372           return 6;\r
373         }\r
374 \r
375         /* Actual password buffer. */\r
376         service->password = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->passwordlen * sizeof(TCHAR));\r
377         if (! service->password) {\r
378           HeapFree(GetProcessHeap(), 0, password);\r
379           HeapFree(GetProcessHeap(), 0, service->username);\r
380           service->username = 0;\r
381           service->usernamelen = 0;\r
382           popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("password"), _T("install()"));\r
383           return 6;\r
384         }\r
385 \r
386         /* Get first password. */\r
387         if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1, service->password, (int) service->passwordlen)) {\r
388           HeapFree(GetProcessHeap(), 0, password);\r
389           SecureZeroMemory(service->password, service->passwordlen);\r
390           HeapFree(GetProcessHeap(), 0, service->password);\r
391           service->password = 0;\r
392           service->passwordlen = 0;\r
393           HeapFree(GetProcessHeap(), 0, service->username);\r
394           service->username = 0;\r
395           service->usernamelen = 0;\r
396           popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_PASSWORD);\r
397           return 6;\r
398         }\r
399 \r
400         /* Get confirmation. */\r
401         if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2, password, (int) service->passwordlen)) {\r
402           SecureZeroMemory(password, service->passwordlen);\r
403           HeapFree(GetProcessHeap(), 0, password);\r
404           SecureZeroMemory(service->password, service->passwordlen);\r
405           HeapFree(GetProcessHeap(), 0, service->password);\r
406           service->password = 0;\r
407           service->passwordlen = 0;\r
408           HeapFree(GetProcessHeap(), 0, service->username);\r
409           service->username = 0;\r
410           service->usernamelen = 0;\r
411           popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_PASSWORD);\r
412           return 6;\r
413         }\r
414 \r
415         /* Compare. */\r
416         if (_tcsncmp(password, service->password, service->passwordlen)) {\r
417           popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PASSWORD);\r
418           SecureZeroMemory(password, service->passwordlen);\r
419           HeapFree(GetProcessHeap(), 0, password);\r
420           SecureZeroMemory(service->password, service->passwordlen);\r
421           HeapFree(GetProcessHeap(), 0, service->password);\r
422           service->password = 0;\r
423           service->passwordlen = 0;\r
424           HeapFree(GetProcessHeap(), 0, service->username);\r
425           service->username = 0;\r
426           service->usernamelen = 0;\r
427           return 6;\r
428         }\r
429       }\r
430     }\r
431   }\r
432 \r
433   /* Remaining tabs are only for services we manage. */\r
434   if (service->native) return 0;\r
435 \r
436   /* Get stop method stuff. */\r
437   check_stop_method(service, NSSM_STOP_METHOD_CONSOLE, IDC_METHOD_CONSOLE);\r
438   check_stop_method(service, NSSM_STOP_METHOD_WINDOW, IDC_METHOD_WINDOW);\r
439   check_stop_method(service, NSSM_STOP_METHOD_THREADS, IDC_METHOD_THREADS);\r
440   check_stop_method(service, NSSM_STOP_METHOD_TERMINATE, IDC_METHOD_TERMINATE);\r
441   check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE, &service->kill_console_delay);\r
442   check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, &service->kill_window_delay);\r
443   check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, &service->kill_threads_delay);\r
444 \r
445   /* Get exit action stuff. */\r
446   check_number(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, &service->throttle_delay);\r
447   combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT);\r
448   service->default_exit_action = (unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0);\r
449   if (service->default_exit_action == CB_ERR) service->default_exit_action = 0;\r
450 \r
451   /* Get I/O stuff. */\r
452   check_io(_T("stdin"), service->stdin_path, _countof(service->stdin_path), IDC_STDIN);\r
453   check_io(_T("stdout"), service->stdout_path, _countof(service->stdout_path), IDC_STDOUT);\r
454   check_io(_T("stderr"), service->stderr_path, _countof(service->stderr_path), IDC_STDERR);\r
455 \r
456   /* Override stdout and/or stderr. */\r
457   if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_TRUNCATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
458     if (service->stdout_path[0]) service->stdout_disposition = CREATE_ALWAYS;\r
459     if (service->stderr_path[0]) service->stderr_disposition = CREATE_ALWAYS;\r
460   }\r
461 \r
462   /* Get rotation stuff. */\r
463   if (SendDlgItemMessage(tablist[NSSM_TAB_ROTATION], IDC_ROTATE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
464     service->rotate_files = true;\r
465     check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, &service->rotate_seconds);\r
466     check_number(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, &service->rotate_bytes_low);\r
467   }\r
468 \r
469   /* Get environment. */\r
470   unsigned long envlen = (unsigned long) SendMessage(GetDlgItem(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT), WM_GETTEXTLENGTH, 0, 0);\r
471   if (envlen) {\r
472     TCHAR *env = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (envlen + 2) * sizeof(TCHAR));\r
473     if (! env) {\r
474       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("install()"));\r
475       cleanup_nssm_service(service);\r
476       return 5;\r
477     }\r
478 \r
479     if (! GetDlgItemText(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT, env, envlen + 1)) {\r
480       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_ENVIRONMENT);\r
481       HeapFree(GetProcessHeap(), 0, env);\r
482       cleanup_nssm_service(service);\r
483       return 5;\r
484     }\r
485 \r
486     /* Strip CR and replace LF with NULL. */\r
487     unsigned long newlen = 0;\r
488     unsigned long i, j;\r
489     for (i = 0; i < envlen; i++) if (env[i] != _T('\r')) newlen++;\r
490     /* Must end with two NULLs. */\r
491     newlen += 2;\r
492 \r
493     TCHAR *newenv = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newlen * sizeof(TCHAR));\r
494     if (! newenv) {\r
495       HeapFree(GetProcessHeap(), 0, env);\r
496       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("install()"));\r
497       cleanup_nssm_service(service);\r
498       return 5;\r
499     }\r
500 \r
501     for (i = 0, j = 0; i < envlen; i++) {\r
502       if (env[i] == _T('\r')) continue;\r
503       if (env[i] == _T('\n')) newenv[j] = _T('\0');\r
504       else newenv[j] = env[i];\r
505       j++;\r
506     }\r
507 \r
508     HeapFree(GetProcessHeap(), 0, env);\r
509     env = newenv;\r
510     envlen = newlen;\r
511 \r
512     /* Test the environment is valid. */\r
513     if (test_environment(env)) {\r
514       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_ENVIRONMENT);\r
515       HeapFree(GetProcessHeap(), 0, env);\r
516       cleanup_nssm_service(service);\r
517       return 5;\r
518     }\r
519 \r
520     if (SendDlgItemMessage(tablist[NSSM_TAB_ENVIRONMENT], IDC_ENVIRONMENT_REPLACE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
521       service->env = env;\r
522       service->envlen = envlen;\r
523     }\r
524     else {\r
525       service->env_extra = env;\r
526       service->env_extralen = envlen;\r
527     }\r
528   }\r
529 \r
530   return 0;\r
531 }\r
532 \r
533 /* Install the service. */\r
534 int install(HWND window) {\r
535   if (! window) return 1;\r
536 \r
537   nssm_service_t *service = alloc_nssm_service();\r
538   if (service) {\r
539     int ret = configure(window, service, 0);\r
540     if (ret) return ret;\r
541   }\r
542 \r
543   /* See if it works. */\r
544   switch (install_service(service)) {\r
545     case 1:\r
546       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("service"), _T("install()"));\r
547       cleanup_nssm_service(service);\r
548       return 1;\r
549 \r
550     case 2:\r
551       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
552       cleanup_nssm_service(service);\r
553       return 2;\r
554 \r
555     case 3:\r
556       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_PATH_TOO_LONG, NSSM);\r
557       cleanup_nssm_service(service);\r
558       return 3;\r
559 \r
560     case 4:\r
561       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_OUT_OF_MEMORY_FOR_IMAGEPATH);\r
562       cleanup_nssm_service(service);\r
563       return 4;\r
564 \r
565     case 5:\r
566       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INSTALL_SERVICE_FAILED);\r
567       cleanup_nssm_service(service);\r
568       return 5;\r
569 \r
570     case 6:\r
571       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_CREATE_PARAMETERS_FAILED);\r
572       cleanup_nssm_service(service);\r
573       return 6;\r
574   }\r
575 \r
576   popup_message(MB_OK, NSSM_MESSAGE_SERVICE_INSTALLED, service->name);\r
577   cleanup_nssm_service(service);\r
578   return 0;\r
579 }\r
580 \r
581 /* Remove the service */\r
582 int remove(HWND window) {\r
583   if (! window) return 1;\r
584 \r
585   /* See if it works */\r
586   nssm_service_t *service = alloc_nssm_service();\r
587   if (service) {\r
588     /* Get service name */\r
589     if (! GetDlgItemText(window, IDC_NAME, service->name, _countof(service->name))) {\r
590       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_SERVICE_NAME);\r
591       cleanup_nssm_service(service);\r
592       return 2;\r
593     }\r
594 \r
595     /* Confirm */\r
596     if (popup_message(MB_YESNO, NSSM_GUI_ASK_REMOVE_SERVICE, service->name) != IDYES) {\r
597       cleanup_nssm_service(service);\r
598       return 0;\r
599     }\r
600   }\r
601 \r
602   switch (remove_service(service)) {\r
603     case 1:\r
604       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("service"), _T("remove()"));\r
605       cleanup_nssm_service(service);\r
606       return 1;\r
607 \r
608     case 2:\r
609       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
610       cleanup_nssm_service(service);\r
611       return 2;\r
612 \r
613     case 3:\r
614       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_SERVICE_NOT_INSTALLED);\r
615       return 3;\r
616       cleanup_nssm_service(service);\r
617 \r
618     case 4:\r
619       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_REMOVE_SERVICE_FAILED);\r
620       cleanup_nssm_service(service);\r
621       return 4;\r
622   }\r
623 \r
624   popup_message(MB_OK, NSSM_MESSAGE_SERVICE_REMOVED, service->name);\r
625   cleanup_nssm_service(service);\r
626   return 0;\r
627 }\r
628 \r
629 int edit(HWND window, nssm_service_t *orig_service) {\r
630   if (! window) return 1;\r
631 \r
632   nssm_service_t *service = alloc_nssm_service();\r
633   if (service) {\r
634     int ret = configure(window, service, orig_service);\r
635     if (ret) return ret;\r
636   }\r
637 \r
638   switch (edit_service(service, true)) {\r
639     case 1:\r
640       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("service"), _T("edit()"));\r
641       cleanup_nssm_service(service);\r
642       return 1;\r
643 \r
644     case 3:\r
645       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_PATH_TOO_LONG, NSSM);\r
646       cleanup_nssm_service(service);\r
647       return 3;\r
648 \r
649     case 4:\r
650       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_OUT_OF_MEMORY_FOR_IMAGEPATH);\r
651       cleanup_nssm_service(service);\r
652       return 4;\r
653 \r
654     case 5:\r
655     case 6:\r
656       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_EDIT_PARAMETERS_FAILED);\r
657       cleanup_nssm_service(service);\r
658       return 6;\r
659   }\r
660 \r
661   popup_message(MB_OK, NSSM_MESSAGE_SERVICE_EDITED, service->name);\r
662   cleanup_nssm_service(service);\r
663   return 0;\r
664 }\r
665 \r
666 static TCHAR *browse_filter(int message) {\r
667   switch (message) {\r
668     case NSSM_GUI_BROWSE_FILTER_APPLICATIONS: return _T("*.exe;*.bat;*.cmd");\r
669     case NSSM_GUI_BROWSE_FILTER_DIRECTORIES: return _T(".");\r
670     case NSSM_GUI_BROWSE_FILTER_ALL_FILES: /* Fall through. */\r
671     default: return _T("*.*");\r
672   }\r
673 }\r
674 \r
675 UINT_PTR CALLBACK browse_hook(HWND dlg, UINT message, WPARAM w, LPARAM l) {\r
676   switch (message) {\r
677     case WM_INITDIALOG:\r
678       return 1;\r
679   }\r
680 \r
681   return 0;\r
682 }\r
683 \r
684 /* Browse for application */\r
685 void browse(HWND window, TCHAR *current, unsigned long flags, ...) {\r
686   if (! window) return;\r
687 \r
688   va_list arg;\r
689   size_t bufsize = 256;\r
690   size_t len = bufsize;\r
691   int i;\r
692 \r
693   OPENFILENAME ofn;\r
694   ZeroMemory(&ofn, sizeof(ofn));\r
695   ofn.lStructSize = sizeof(ofn);\r
696   ofn.lpstrFilter = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, bufsize * sizeof(TCHAR));\r
697   /* XXX: Escaping nulls with FormatMessage is tricky */\r
698   if (ofn.lpstrFilter) {\r
699     ZeroMemory((void *) ofn.lpstrFilter, bufsize);\r
700     len = 0;\r
701     /* "Applications" + NULL + "*.exe" + NULL */\r
702     va_start(arg, flags);\r
703     while (i = va_arg(arg, int)) {\r
704       TCHAR *localised = message_string(i);\r
705       _sntprintf_s((TCHAR *) ofn.lpstrFilter + len, bufsize, _TRUNCATE, localised);\r
706       len += _tcslen(localised) + 1;\r
707       LocalFree(localised);\r
708       TCHAR *filter = browse_filter(i);\r
709       _sntprintf_s((TCHAR *) ofn.lpstrFilter + len, bufsize - len, _TRUNCATE, _T("%s"), filter);\r
710       len += _tcslen(filter) + 1;\r
711     }\r
712     va_end(arg);\r
713     /* Remainder of the buffer is already zeroed */\r
714   }\r
715   ofn.lpstrFile = new TCHAR[MAX_PATH];\r
716   if (flags & OFN_NOVALIDATE) {\r
717     /* Directory hack. */\r
718     _sntprintf_s(ofn.lpstrFile, MAX_PATH, _TRUNCATE, _T(":%s:"), message_string(NSSM_GUI_BROWSE_FILTER_DIRECTORIES));\r
719   }\r
720   else _sntprintf_s(ofn.lpstrFile, MAX_PATH, _TRUNCATE, _T("%s"), current);\r
721   ofn.lpstrTitle = message_string(NSSM_GUI_BROWSE_TITLE);\r
722   ofn.nMaxFile = MAX_PATH;\r
723   ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | flags;\r
724 \r
725   if (GetOpenFileName(&ofn)) {\r
726     /* Directory hack. */\r
727     if (flags & OFN_NOVALIDATE) strip_basename(ofn.lpstrFile);\r
728     SendMessage(window, WM_SETTEXT, 0, (LPARAM) ofn.lpstrFile);\r
729   }\r
730   if (ofn.lpstrFilter) HeapFree(GetProcessHeap(), 0, (void *) ofn.lpstrFilter);\r
731 \r
732   delete[] ofn.lpstrFile;\r
733 }\r
734 \r
735 INT_PTR CALLBACK tab_dlg(HWND tab, UINT message, WPARAM w, LPARAM l) {\r
736   switch (message) {\r
737     case WM_INITDIALOG:\r
738       return 1;\r
739 \r
740     /* Button was pressed or control was controlled. */\r
741     case WM_COMMAND:\r
742       HWND dlg;\r
743       TCHAR buffer[MAX_PATH];\r
744       unsigned char enabled;\r
745 \r
746       switch (LOWORD(w)) {\r
747         /* Browse for application. */\r
748         case IDC_BROWSE:\r
749           dlg = GetDlgItem(tab, IDC_PATH);\r
750           GetDlgItemText(tab, IDC_PATH, buffer, _countof(buffer));\r
751           browse(dlg, buffer, OFN_FILEMUSTEXIST, NSSM_GUI_BROWSE_FILTER_APPLICATIONS, NSSM_GUI_BROWSE_FILTER_ALL_FILES, 0);\r
752           /* Fill in startup directory if it wasn't already specified. */\r
753           GetDlgItemText(tab, IDC_DIR, buffer, _countof(buffer));\r
754           if (! buffer[0]) {\r
755             GetDlgItemText(tab, IDC_PATH, buffer, _countof(buffer));\r
756             strip_basename(buffer);\r
757             SetDlgItemText(tab, IDC_DIR, buffer);\r
758           }\r
759           break;\r
760 \r
761         /* Browse for startup directory. */\r
762         case IDC_BROWSE_DIR:\r
763           dlg = GetDlgItem(tab, IDC_DIR);\r
764           GetDlgItemText(tab, IDC_DIR, buffer, _countof(buffer));\r
765           browse(dlg, buffer, OFN_NOVALIDATE, NSSM_GUI_BROWSE_FILTER_DIRECTORIES, 0);\r
766           break;\r
767 \r
768         /* Log on. */\r
769         case IDC_LOCALSYSTEM:\r
770           set_logon_enabled(0);\r
771           break;\r
772 \r
773         case IDC_ACCOUNT:\r
774           set_logon_enabled(1);\r
775           break;\r
776 \r
777         /* Shutdown methods. */\r
778         case IDC_METHOD_CONSOLE:\r
779           set_timeout_enabled(LOWORD(w), IDC_KILL_CONSOLE);\r
780           break;\r
781 \r
782         case IDC_METHOD_WINDOW:\r
783           set_timeout_enabled(LOWORD(w), IDC_KILL_WINDOW);\r
784           break;\r
785 \r
786         case IDC_METHOD_THREADS:\r
787           set_timeout_enabled(LOWORD(w), IDC_KILL_THREADS);\r
788           break;\r
789 \r
790         /* Browse for stdin. */\r
791         case IDC_BROWSE_STDIN:\r
792           dlg = GetDlgItem(tab, IDC_STDIN);\r
793           GetDlgItemText(tab, IDC_STDIN, buffer, _countof(buffer));\r
794           browse(dlg, buffer, 0, NSSM_GUI_BROWSE_FILTER_ALL_FILES, 0);\r
795           break;\r
796 \r
797         /* Browse for stdout. */\r
798         case IDC_BROWSE_STDOUT:\r
799           dlg = GetDlgItem(tab, IDC_STDOUT);\r
800           GetDlgItemText(tab, IDC_STDOUT, buffer, _countof(buffer));\r
801           browse(dlg, buffer, 0, NSSM_GUI_BROWSE_FILTER_ALL_FILES, 0);\r
802           /* Fill in stderr if it wasn't already specified. */\r
803           GetDlgItemText(tab, IDC_STDERR, buffer, _countof(buffer));\r
804           if (! buffer[0]) {\r
805             GetDlgItemText(tab, IDC_STDOUT, buffer, _countof(buffer));\r
806             SetDlgItemText(tab, IDC_STDERR, buffer);\r
807           }\r
808           break;\r
809 \r
810         /* Browse for stderr. */\r
811         case IDC_BROWSE_STDERR:\r
812           dlg = GetDlgItem(tab, IDC_STDERR);\r
813           GetDlgItemText(tab, IDC_STDERR, buffer, _countof(buffer));\r
814           browse(dlg, buffer, 0, NSSM_GUI_BROWSE_FILTER_ALL_FILES, 0);\r
815           break;\r
816 \r
817         /* Rotation. */\r
818         case IDC_ROTATE:\r
819           if (SendDlgItemMessage(tab, LOWORD(w), BM_GETCHECK, 0, 0) & BST_CHECKED) enabled = 1;\r
820           else enabled = 0;\r
821           set_rotation_enabled(enabled);\r
822           break;\r
823       }\r
824       return 1;\r
825   }\r
826 \r
827   return 0;\r
828 }\r
829 \r
830 /* Install/remove dialogue callback */\r
831 INT_PTR CALLBACK nssm_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {\r
832   nssm_service_t *service;\r
833 \r
834   switch (message) {\r
835     /* Creating the dialogue */\r
836     case WM_INITDIALOG:\r
837       service = (nssm_service_t *) l;\r
838 \r
839       SetFocus(GetDlgItem(window, IDC_NAME));\r
840 \r
841       HWND tabs;\r
842       HWND combo;\r
843       tabs = GetDlgItem(window, IDC_TAB1);\r
844       if (! tabs) return 0;\r
845 \r
846       /* Set up tabs. */\r
847       TCITEM tab;\r
848       ZeroMemory(&tab, sizeof(tab));\r
849       tab.mask = TCIF_TEXT;\r
850 \r
851       selected_tab = 0;\r
852 \r
853       /* Application tab. */\r
854       if (service->native) tab.pszText = message_string(NSSM_GUI_TAB_NATIVE);\r
855       else tab.pszText = message_string(NSSM_GUI_TAB_APPLICATION);\r
856       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
857       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_APPLICATION, (LPARAM) &tab);\r
858       if (service->native) {\r
859         tablist[NSSM_TAB_APPLICATION] = dialog(MAKEINTRESOURCE(IDD_NATIVE), window, tab_dlg);\r
860         EnableWindow(tablist[NSSM_TAB_APPLICATION], 0);\r
861         EnableWindow(GetDlgItem(tablist[NSSM_TAB_APPLICATION], IDC_PATH), 0);\r
862       }\r
863       else tablist[NSSM_TAB_APPLICATION] = dialog(MAKEINTRESOURCE(IDD_APPLICATION), window, tab_dlg);\r
864       ShowWindow(tablist[NSSM_TAB_APPLICATION], SW_SHOW);\r
865 \r
866       /* Details tab. */\r
867       tab.pszText = message_string(NSSM_GUI_TAB_DETAILS);\r
868       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
869       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_DETAILS, (LPARAM) &tab);\r
870       tablist[NSSM_TAB_DETAILS] = dialog(MAKEINTRESOURCE(IDD_DETAILS), window, tab_dlg);\r
871       ShowWindow(tablist[NSSM_TAB_DETAILS], SW_HIDE);\r
872 \r
873       /* Set defaults. */\r
874       combo = GetDlgItem(tablist[NSSM_TAB_DETAILS], IDC_STARTUP);\r
875       SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_AUTOMATIC, (LPARAM) message_string(NSSM_GUI_STARTUP_AUTOMATIC));\r
876       SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_DELAYED, (LPARAM) message_string(NSSM_GUI_STARTUP_DELAYED));\r
877       SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_MANUAL, (LPARAM) message_string(NSSM_GUI_STARTUP_MANUAL));\r
878       SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_DISABLED, (LPARAM) message_string(NSSM_GUI_STARTUP_DISABLED));\r
879       SendMessage(combo, CB_SETCURSEL, NSSM_STARTUP_AUTOMATIC, 0);\r
880 \r
881       /* Logon tab. */\r
882       tab.pszText = message_string(NSSM_GUI_TAB_LOGON);\r
883       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
884       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_LOGON, (LPARAM) &tab);\r
885       tablist[NSSM_TAB_LOGON] = dialog(MAKEINTRESOURCE(IDD_LOGON), window, tab_dlg);\r
886       ShowWindow(tablist[NSSM_TAB_LOGON], SW_HIDE);\r
887 \r
888       /* Set defaults. */\r
889       CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
890       set_logon_enabled(0);\r
891 \r
892       /* Remaining tabs are only for services we manage. */\r
893       if (service->native) return 1;\r
894 \r
895       /* Shutdown tab. */\r
896       tab.pszText = message_string(NSSM_GUI_TAB_SHUTDOWN);\r
897       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
898       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_SHUTDOWN, (LPARAM) &tab);\r
899       tablist[NSSM_TAB_SHUTDOWN] = dialog(MAKEINTRESOURCE(IDD_SHUTDOWN), window, tab_dlg);\r
900       ShowWindow(tablist[NSSM_TAB_SHUTDOWN], SW_HIDE);\r
901 \r
902       /* Set defaults. */\r
903       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_CONSOLE, BM_SETCHECK, BST_CHECKED, 0);\r
904       SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE, NSSM_KILL_CONSOLE_GRACE_PERIOD, 0);\r
905       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_WINDOW, BM_SETCHECK, BST_CHECKED, 0);\r
906       SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, NSSM_KILL_WINDOW_GRACE_PERIOD, 0);\r
907       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_THREADS, BM_SETCHECK, BST_CHECKED, 0);\r
908       SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, NSSM_KILL_THREADS_GRACE_PERIOD, 0);\r
909       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_TERMINATE, BM_SETCHECK, BST_CHECKED, 0);\r
910 \r
911       /* Restart tab. */\r
912       tab.pszText = message_string(NSSM_GUI_TAB_EXIT);\r
913       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
914       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_EXIT, (LPARAM) &tab);\r
915       tablist[NSSM_TAB_EXIT] = dialog(MAKEINTRESOURCE(IDD_APPEXIT), window, tab_dlg);\r
916       ShowWindow(tablist[NSSM_TAB_EXIT], SW_HIDE);\r
917 \r
918       /* Set defaults. */\r
919       SetDlgItemInt(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, NSSM_RESET_THROTTLE_RESTART, 0);\r
920       combo = GetDlgItem(tablist[NSSM_TAB_EXIT], IDC_APPEXIT);\r
921       SendMessage(combo, CB_INSERTSTRING, NSSM_EXIT_RESTART, (LPARAM) message_string(NSSM_GUI_EXIT_RESTART));\r
922       SendMessage(combo, CB_INSERTSTRING, NSSM_EXIT_IGNORE, (LPARAM) message_string(NSSM_GUI_EXIT_IGNORE));\r
923       SendMessage(combo, CB_INSERTSTRING, NSSM_EXIT_REALLY, (LPARAM) message_string(NSSM_GUI_EXIT_REALLY));\r
924       SendMessage(combo, CB_INSERTSTRING, NSSM_EXIT_UNCLEAN, (LPARAM) message_string(NSSM_GUI_EXIT_UNCLEAN));\r
925       SendMessage(combo, CB_SETCURSEL, NSSM_EXIT_RESTART, 0);\r
926 \r
927       /* I/O tab. */\r
928       tab.pszText = message_string(NSSM_GUI_TAB_IO);\r
929       tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;\r
930       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_IO, (LPARAM) &tab);\r
931       tablist[NSSM_TAB_IO] = dialog(MAKEINTRESOURCE(IDD_IO), window, tab_dlg);\r
932       ShowWindow(tablist[NSSM_TAB_IO], SW_HIDE);\r
933 \r
934       /* Rotation tab. */\r
935       tab.pszText = message_string(NSSM_GUI_TAB_ROTATION);\r
936       tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;\r
937       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_ROTATION, (LPARAM) &tab);\r
938       tablist[NSSM_TAB_ROTATION] = dialog(MAKEINTRESOURCE(IDD_ROTATION), window, tab_dlg);\r
939       ShowWindow(tablist[NSSM_TAB_ROTATION], SW_HIDE);\r
940 \r
941       /* Set defaults. */\r
942       SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS, 0, 0);\r
943       SetDlgItemInt(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW, 0, 0);\r
944       set_rotation_enabled(0);\r
945 \r
946       /* Environment tab. */\r
947       tab.pszText = message_string(NSSM_GUI_TAB_ENVIRONMENT);\r
948       tab.cchTextMax = (int) _tcslen(tab.pszText) + 1;\r
949       SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_ENVIRONMENT, (LPARAM) &tab);\r
950       tablist[NSSM_TAB_ENVIRONMENT] = dialog(MAKEINTRESOURCE(IDD_ENVIRONMENT), window, tab_dlg);\r
951       ShowWindow(tablist[NSSM_TAB_ENVIRONMENT], SW_HIDE);\r
952 \r
953       return 1;\r
954 \r
955     /* Tab change. */\r
956     case WM_NOTIFY:\r
957       NMHDR *notification;\r
958 \r
959       notification = (NMHDR *) l;\r
960       switch (notification->code) {\r
961         case TCN_SELCHANGE:\r
962           HWND tabs;\r
963           int selection;\r
964 \r
965           tabs = GetDlgItem(window, IDC_TAB1);\r
966           if (! tabs) return 0;\r
967 \r
968           selection = (int) SendMessage(tabs, TCM_GETCURSEL, 0, 0);\r
969           if (selection != selected_tab) {\r
970             ShowWindow(tablist[selected_tab], SW_HIDE);\r
971             ShowWindow(tablist[selection], SW_SHOWDEFAULT);\r
972             SetFocus(GetDlgItem(window, IDOK));\r
973             selected_tab = selection;\r
974           }\r
975           return 1;\r
976       }\r
977 \r
978       return 0;\r
979 \r
980     /* Button was pressed or control was controlled */\r
981     case WM_COMMAND:\r
982       switch (LOWORD(w)) {\r
983         /* OK button */\r
984         case IDOK:\r
985           if ((int) GetWindowLongPtr(window, GWLP_USERDATA) == IDD_EDIT) {\r
986             if (! edit(window, (nssm_service_t *) GetWindowLongPtr(window, DWLP_USER))) PostQuitMessage(0);\r
987           }\r
988           else if (! install(window)) PostQuitMessage(0);\r
989           break;\r
990 \r
991         /* Cancel button */\r
992         case IDCANCEL:\r
993           DestroyWindow(window);\r
994           break;\r
995 \r
996         /* Remove button */\r
997         case IDC_REMOVE:\r
998           if (! remove(window)) PostQuitMessage(0);\r
999           break;\r
1000       }\r
1001       return 1;\r
1002 \r
1003     /* Window closing */\r
1004     case WM_CLOSE:\r
1005       DestroyWindow(window);\r
1006       return 0;\r
1007     case WM_DESTROY:\r
1008       PostQuitMessage(0);\r
1009   }\r
1010   return 0;\r
1011 }\r