1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include <windows.h>
6 #include "../../../../toolkit/mozapps/update/common/pathhash.h"
7
8 #pragma comment(lib, "advapi32.lib")
9
10 typedef struct _stack_t {
11 struct _stack_t *next;
12 TCHAR text[MAX_PATH];
13 } stack_t;
14
15 int popstring(stack_t **stacktop, LPTSTR str, int len);
16 void pushstring(stack_t **stacktop, LPCTSTR str, int len);
17
18 /**
19 * Determines if the specified service exists or not
20 *
21 * @param serviceName The name of the service to check
22 * @param exists Whether or not the service exists
23 * @return TRUE if there were no errors
24 */
25 static BOOL
IsServiceInstalled(LPCWSTR serviceName,BOOL & exists)26 IsServiceInstalled(LPCWSTR serviceName, BOOL &exists)
27 {
28 exists = FALSE;
29
30 // Get a handle to the local computer SCM database with full access rights.
31 SC_HANDLE serviceManager = OpenSCManager(NULL, NULL,
32 SC_MANAGER_ENUMERATE_SERVICE);
33 if (!serviceManager) {
34 return FALSE;
35 }
36
37 SC_HANDLE serviceHandle = OpenServiceW(serviceManager,
38 serviceName,
39 SERVICE_QUERY_CONFIG);
40 if (!serviceHandle && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) {
41 CloseServiceHandle(serviceManager);
42 return FALSE;
43 }
44
45 if (serviceHandle) {
46 CloseServiceHandle(serviceHandle);
47 exists = TRUE;
48 }
49
50 CloseServiceHandle(serviceManager);
51 return TRUE;
52 }
53
54 /**
55 * Determines if the specified service is installed or not
56 *
57 * @param stacktop A pointer to the top of the stack
58 * @param variables A pointer to the NSIS variables
59 * @return 0 if the service does not exist
60 * 1 if the service does exist
61 * -1 if there was an error.
62 */
63 extern "C" void __declspec(dllexport)
IsInstalled(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop,void * extra)64 IsInstalled(HWND hwndParent, int string_size,
65 TCHAR *variables, stack_t **stacktop, void *extra)
66 {
67 TCHAR tmp[MAX_PATH] = { L'\0' };
68 WCHAR serviceName[MAX_PATH] = { '\0' };
69 popstring(stacktop, tmp, MAX_PATH);
70
71 #if !defined(UNICODE)
72 MultiByteToWideChar(CP_ACP, 0, tmp, -1, serviceName, MAX_PATH);
73 #else
74 wcscpy(serviceName, tmp);
75 #endif
76
77 BOOL serviceInstalled;
78 if (!IsServiceInstalled(serviceName, serviceInstalled)) {
79 pushstring(stacktop, TEXT("-1"), 3);
80 } else {
81 pushstring(stacktop, serviceInstalled ? TEXT("1") : TEXT("0"), 2);
82 }
83 }
84
85 /**
86 * Stops the specified service.
87 *
88 * @param serviceName The name of the service to stop
89 * @return TRUE if the operation was successful
90 */
91 static BOOL
StopService(LPCWSTR serviceName)92 StopService(LPCWSTR serviceName)
93 {
94 // Get a handle to the local computer SCM database with full access rights.
95 SC_HANDLE serviceManager = OpenSCManager(NULL, NULL,
96 SC_MANAGER_ENUMERATE_SERVICE);
97 if (!serviceManager) {
98 return FALSE;
99 }
100
101 SC_HANDLE serviceHandle = OpenServiceW(serviceManager,
102 serviceName,
103 SERVICE_STOP);
104 if (!serviceHandle) {
105 CloseServiceHandle(serviceManager);
106 return FALSE;
107 }
108
109 //Stop the service so it deletes faster and so the uninstaller
110 // can actually delete its EXE.
111 DWORD totalWaitTime = 0;
112 SERVICE_STATUS status;
113 static const int maxWaitTime = 1000 * 60; // Never wait more than a minute
114 BOOL stopped = FALSE;
115 if (ControlService(serviceHandle, SERVICE_CONTROL_STOP, &status)) {
116 do {
117 Sleep(status.dwWaitHint);
118 // + 10 milliseconds to make sure we always approach maxWaitTime
119 totalWaitTime += (status.dwWaitHint + 10);
120 if (status.dwCurrentState == SERVICE_STOPPED) {
121 stopped = true;
122 break;
123 } else if (totalWaitTime > maxWaitTime) {
124 break;
125 }
126 } while (QueryServiceStatus(serviceHandle, &status));
127 }
128
129 CloseServiceHandle(serviceHandle);
130 CloseServiceHandle(serviceManager);
131 return stopped;
132 }
133
134 /**
135 * Stops the specified service
136 *
137 * @param stacktop A pointer to the top of the stack
138 * @param variables A pointer to the NSIS variables
139 * @return 1 if the service was stopped, 0 on error
140 */
141 extern "C" void __declspec(dllexport)
Stop(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop,void * extra)142 Stop(HWND hwndParent, int string_size,
143 TCHAR *variables, stack_t **stacktop, void *extra)
144 {
145 TCHAR tmp[MAX_PATH] = { L'\0' };
146 WCHAR serviceName[MAX_PATH] = { '\0' };
147
148 popstring(stacktop, tmp, MAX_PATH);
149
150 #if !defined(UNICODE)
151 MultiByteToWideChar(CP_ACP, 0, tmp, -1, serviceName, MAX_PATH);
152 #else
153 wcscpy(serviceName, tmp);
154 #endif
155
156 if (StopService(serviceName)) {
157 pushstring(stacktop, TEXT("1"), 2);
158 } else {
159 pushstring(stacktop, TEXT("0"), 2);
160 }
161 }
162
163 /**
164 * Determines a unique registry path from a file or directory path
165 *
166 * @param stacktop A pointer to the top of the stack
167 * @param variables A pointer to the NSIS variables
168 * @return The unique registry path or an empty string on error
169 */
170 extern "C" void __declspec(dllexport)
PathToUniqueRegistryPath(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop,void * extra)171 PathToUniqueRegistryPath(HWND hwndParent, int string_size,
172 TCHAR *variables, stack_t **stacktop,
173 void *extra)
174 {
175 TCHAR tmp[MAX_PATH] = { L'\0' };
176 WCHAR installBasePath[MAX_PATH] = { '\0' };
177 popstring(stacktop, tmp, MAX_PATH);
178
179 #if !defined(UNICODE)
180 MultiByteToWideChar(CP_ACP, 0, tmp, -1, installBasePath, MAX_PATH);
181 #else
182 wcscpy(installBasePath, tmp);
183 #endif
184
185 WCHAR registryPath[MAX_PATH + 1] = { '\0' };
186 if (CalculateRegistryPathFromFilePath(installBasePath, registryPath)) {
187 pushstring(stacktop, registryPath, wcslen(registryPath) + 1);
188 } else {
189 pushstring(stacktop, TEXT(""), 1);
190 }
191 }
192
193 BOOL WINAPI
DllMain(HANDLE hInst,ULONG ul_reason_for_call,LPVOID lpReserved)194 DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
195 {
196 return TRUE;
197 }
198
199 /**
200 * Removes an element from the top of the NSIS stack
201 *
202 * @param stacktop A pointer to the top of the stack
203 * @param str The string to pop to
204 * @param len The max length
205 * @return 0 on success
206 */
popstring(stack_t ** stacktop,TCHAR * str,int len)207 int popstring(stack_t **stacktop, TCHAR *str, int len)
208 {
209 // Removes the element from the top of the stack and puts it in the buffer
210 stack_t *th;
211 if (!stacktop || !*stacktop) {
212 return 1;
213 }
214
215 th = (*stacktop);
216 lstrcpyn(str,th->text, len);
217 *stacktop = th->next;
218 GlobalFree((HGLOBAL)th);
219 return 0;
220 }
221
222 /**
223 * Adds an element to the top of the NSIS stack
224 *
225 * @param stacktop A pointer to the top of the stack
226 * @param str The string to push on the stack
227 * @param len The length of the string to push on the stack
228 * @return 0 on success
229 */
pushstring(stack_t ** stacktop,const TCHAR * str,int len)230 void pushstring(stack_t **stacktop, const TCHAR *str, int len)
231 {
232 stack_t *th;
233 if (!stacktop) {
234 return;
235 }
236
237 th = (stack_t*)GlobalAlloc(GPTR, sizeof(stack_t) + len);
238 lstrcpyn(th->text, str, len);
239 th->next = *stacktop;
240 *stacktop = th;
241 }
242