Pass parameters around in a data structure.
[nssm.git] / gui.cpp
1 #include "nssm.h"\r
2 \r
3 static void strip_basename(char *buffer) {\r
4   size_t len = strlen(buffer);\r
5   size_t i;\r
6   for (i = len; i && buffer[i] != '\\' && buffer[i] != '/'; i--);\r
7   /* X:\ is OK. */\r
8   if (i && buffer[i-1] == ':') i++;\r
9   buffer[i] = '\0';\r
10 }\r
11 \r
12 int nssm_gui(int resource, char *name) {\r
13   /* Create window */\r
14   HWND dlg = CreateDialog(0, MAKEINTRESOURCE(resource), 0, install_dlg);\r
15   if (! dlg) {\r
16     popup_message(MB_OK, NSSM_GUI_CREATEDIALOG_FAILED, error_string(GetLastError()));\r
17     return 1;\r
18   }\r
19 \r
20   /* Display the window */\r
21   centre_window(dlg);\r
22   ShowWindow(dlg, SW_SHOW);\r
23 \r
24   /* Set service name if given */\r
25   if (name) {\r
26     SetDlgItemText(dlg, IDC_NAME, name);\r
27     /* No point making user click remove if the name is already entered */\r
28     if (resource == IDD_REMOVE) {\r
29       HWND button = GetDlgItem(dlg, IDC_REMOVE);\r
30       if (button) {\r
31         SendMessage(button, WM_LBUTTONDOWN, 0, 0);\r
32         SendMessage(button, WM_LBUTTONUP, 0, 0);\r
33       }\r
34     }\r
35   }\r
36 \r
37   /* Go! */\r
38   MSG message;\r
39   while (GetMessage(&message, 0, 0, 0)) {\r
40     if (IsDialogMessage(dlg, &message)) continue;\r
41     TranslateMessage(&message);\r
42     DispatchMessage(&message);\r
43   }\r
44 \r
45   return (int) message.wParam;\r
46 }\r
47 \r
48 void centre_window(HWND window) {\r
49   HWND desktop;\r
50   RECT size, desktop_size;\r
51   unsigned long x, y;\r
52 \r
53   if (! window) return;\r
54 \r
55   /* Find window size */\r
56   if (! GetWindowRect(window, &size)) return;\r
57   \r
58   /* Find desktop window */\r
59   desktop = GetDesktopWindow();\r
60   if (! desktop) return;\r
61 \r
62   /* Find desktop window size */\r
63   if (! GetWindowRect(desktop, &desktop_size)) return;\r
64 \r
65   /* Centre window */\r
66   x = (desktop_size.right - size.right) / 2;\r
67   y = (desktop_size.bottom - size.bottom) / 2;\r
68   MoveWindow(window, x, y, size.right - size.left, size.bottom - size.top, 0);\r
69 }\r
70 \r
71 /* Install the service */\r
72 int install(HWND window) {\r
73   if (! window) return 1;\r
74 \r
75   nssm_service_t *service = alloc_nssm_service();\r
76   if (service) {\r
77     /* Get service name. */\r
78     if (! GetDlgItemText(window, IDC_NAME, service->name, sizeof(service->name))) {\r
79       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_SERVICE_NAME);\r
80       cleanup_nssm_service(service);\r
81       return 2;\r
82     }\r
83 \r
84     /* Get executable name */\r
85     if (! GetDlgItemText(window, IDC_PATH, service->exe, sizeof(service->exe))) {\r
86       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PATH);\r
87       return 3;\r
88     }\r
89   \r
90     /* Get flags */\r
91     if (SendMessage(GetDlgItem(window, IDC_FLAGS), WM_GETTEXTLENGTH, 0, 0)) {\r
92       if (! GetDlgItemText(window, IDC_FLAGS, service->flags, sizeof(service->flags))) {\r
93         popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_OPTIONS);\r
94         return 4;\r
95       }
96     }\r
97 \r
98     memmove(service->dir, service->exe, strlen(service->exe));\r
99     strip_basename(service->dir);\r
100   }\r
101 \r
102   /* See if it works. */\r
103   switch (install_service(service)) {\r
104     case 1:\r
105       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, "service", "install()");\r
106       cleanup_nssm_service(service);\r
107       return 1;\r
108 \r
109     case 2:\r
110       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
111       cleanup_nssm_service(service);\r
112       return 2;\r
113 \r
114     case 3:\r
115       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_PATH_TOO_LONG, NSSM);\r
116       cleanup_nssm_service(service);\r
117       return 3;\r
118 \r
119     case 4:\r
120       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_OUT_OF_MEMORY_FOR_IMAGEPATH);\r
121       cleanup_nssm_service(service);\r
122       return 4;\r
123 \r
124     case 5:\r
125       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INSTALL_SERVICE_FAILED);\r
126       cleanup_nssm_service(service);\r
127       return 5;\r
128 \r
129     case 6:\r
130       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_CREATE_PARAMETERS_FAILED);\r
131       cleanup_nssm_service(service);\r
132       return 6;\r
133   }\r
134 \r
135   popup_message(MB_OK, NSSM_MESSAGE_SERVICE_INSTALLED, service->name);\r
136   cleanup_nssm_service(service);\r
137   return 0;\r
138 }\r
139 \r
140 /* Remove the service */\r
141 int remove(HWND window) {\r
142   if (! window) return 1;\r
143 \r
144   /* See if it works */\r
145   nssm_service_t *service = alloc_nssm_service();\r
146   if (service) {\r
147     /* Get service name */\r
148     if (! GetDlgItemText(window, IDC_NAME, service->name, sizeof(service->name))) {\r
149       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_SERVICE_NAME);\r
150       cleanup_nssm_service(service);\r
151       return 2;\r
152     }\r
153 \r
154     /* Confirm */\r
155     if (popup_message(MB_YESNO, NSSM_GUI_ASK_REMOVE_SERVICE, service->name) != IDYES) {\r
156       cleanup_nssm_service(service);\r
157       return 0;\r
158     }\r
159   }\r
160 \r
161   switch (remove_service(service)) {\r
162     case 1:\r
163       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, "service", "remove()");\r
164       cleanup_nssm_service(service);\r
165       return 1;\r
166 \r
167     case 2:\r
168       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
169       cleanup_nssm_service(service);\r
170       return 2;\r
171 \r
172     case 3:\r
173       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_SERVICE_NOT_INSTALLED);\r
174       return 3;\r
175       cleanup_nssm_service(service);\r
176 \r
177     case 4:\r
178       popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_REMOVE_SERVICE_FAILED);\r
179       cleanup_nssm_service(service);\r
180       return 4;\r
181   }\r
182 \r
183   popup_message(MB_OK, NSSM_MESSAGE_SERVICE_REMOVED, service->name);\r
184   cleanup_nssm_service(service);\r
185   return 0;\r
186 }\r
187 \r
188 /* Browse for application */\r
189 void browse(HWND window) {\r
190   if (! window) return;\r
191 \r
192   size_t bufsize = 256;\r
193   size_t len = bufsize;\r
194   OPENFILENAME ofn;\r
195   ZeroMemory(&ofn, sizeof(ofn));\r
196   ofn.lStructSize = sizeof(ofn);\r
197   ofn.lpstrFilter = (char *) HeapAlloc(GetProcessHeap(), 0, bufsize);\r
198   /* XXX: Escaping nulls with FormatMessage is tricky */\r
199   if (ofn.lpstrFilter) {\r
200     ZeroMemory((void *) ofn.lpstrFilter, bufsize);\r
201     char *localised = message_string(NSSM_GUI_BROWSE_FILTER_APPLICATIONS);\r
202     _snprintf_s((char *) ofn.lpstrFilter, bufsize, _TRUNCATE, localised);\r
203     /* "Applications" + NULL + "*.exe" + NULL */\r
204     len = strlen(localised) + 1;\r
205     LocalFree(localised);\r
206     _snprintf_s((char *) ofn.lpstrFilter + len, bufsize - len, _TRUNCATE, "*.exe");\r
207     /* "All files" + NULL + "*.*" + NULL */\r
208     len += 6;\r
209     localised = message_string(NSSM_GUI_BROWSE_FILTER_ALL_FILES);\r
210     _snprintf_s((char *) ofn.lpstrFilter + len, bufsize - len, _TRUNCATE, localised);\r
211     len += strlen(localised) + 1;\r
212     LocalFree(localised);\r
213     _snprintf_s((char *) ofn.lpstrFilter + len, bufsize - len, _TRUNCATE, "*.*");\r
214     /* Remainder of the buffer is already zeroed */\r
215   }\r
216   ofn.lpstrFile = new char[MAX_PATH];\r
217   ofn.lpstrFile[0] = '\0';\r
218   ofn.lpstrTitle = message_string(NSSM_GUI_BROWSE_TITLE);\r
219   ofn.nMaxFile = MAX_PATH;\r
220   ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;\r
221 \r
222   if (GetOpenFileName(&ofn)) {\r
223     SendMessage(window, WM_SETTEXT, 0, (LPARAM) ofn.lpstrFile);\r
224   }\r
225   if (ofn.lpstrFilter) HeapFree(GetProcessHeap(), 0, (void *) ofn.lpstrFilter);\r
226 \r
227   delete[] ofn.lpstrFile;\r
228 }\r
229 \r
230 /* Install/remove dialogue callback */\r
231 INT_PTR CALLBACK install_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {\r
232   switch (message) {\r
233     /* Creating the dialogue */\r
234     case WM_INITDIALOG:\r
235       return 1;\r
236 \r
237     /* Button was pressed or control was controlled */\r
238     case WM_COMMAND:\r
239       switch (LOWORD(w)) {\r
240         /* OK button */\r
241         case IDC_OK:\r
242           if (! install(window)) PostQuitMessage(0);\r
243           break;\r
244 \r
245         /* Cancel button */\r
246         case IDCANCEL:\r
247           DestroyWindow(window);\r
248           break;\r
249 \r
250         /* Browse button */\r
251         case IDC_BROWSE:\r
252           browse(GetDlgItem(window, IDC_PATH));\r
253           break;\r
254 \r
255         /* Remove button */\r
256         case IDC_REMOVE:\r
257           if (! remove(window)) PostQuitMessage(0);\r
258           break;\r
259       }\r
260       return 1;\r
261 \r
262     /* Window closing */\r
263     case WM_CLOSE:\r
264       DestroyWindow(window);\r
265       return 0;\r
266     case WM_DESTROY:\r
267       PostQuitMessage(0);\r
268   }\r
269   return 0;\r
270 }\r