Services.cpp (6803B)
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 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) 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 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) 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) 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 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 */ 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 */ 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 }