other-licenses/nsis/Contrib/ServicesHelper/Services.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     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/. */
     5 #include <windows.h>
     6 #include "../../../../toolkit/mozapps/update/common/pathhash.h"
     8 #pragma comment(lib, "advapi32.lib") 
    10 typedef struct _stack_t {
    11   struct _stack_t *next;
    12   TCHAR text[MAX_PATH];
    13 } stack_t;
    15 int popstring(stack_t **stacktop, LPTSTR str, int len);
    16 void pushstring(stack_t **stacktop, LPCTSTR str, int len);
    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;
    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   }
    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   }
    45   if (serviceHandle) {
    46     CloseServiceHandle(serviceHandle);
    47     exists = TRUE;
    48   } 
    50   CloseServiceHandle(serviceManager);
    51   return TRUE;
    52 }
    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);
    71 #if !defined(UNICODE)
    72     MultiByteToWideChar(CP_ACP, 0, tmp, -1, serviceName, MAX_PATH);
    73 #else
    74     wcscpy(serviceName, tmp);
    75 #endif
    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 }
    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   }
   101   SC_HANDLE serviceHandle = OpenServiceW(serviceManager, 
   102                                          serviceName, 
   103                                          SERVICE_STOP);
   104   if (!serviceHandle) {
   105     CloseServiceHandle(serviceManager);
   106     return FALSE;
   107   }
   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   }
   129   CloseServiceHandle(serviceHandle);
   130   CloseServiceHandle(serviceManager);
   131   return stopped;
   132 }
   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' };
   148   popstring(stacktop, tmp, MAX_PATH);
   150 #if !defined(UNICODE)
   151     MultiByteToWideChar(CP_ACP, 0, tmp, -1, serviceName, MAX_PATH);
   152 #else
   153     wcscpy(serviceName, tmp);
   154 #endif
   156   if (StopService(serviceName)) {
   157     pushstring(stacktop, TEXT("1"), 2);
   158   } else {
   159     pushstring(stacktop, TEXT("0"), 2);
   160   }
   161 }
   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);
   179 #if !defined(UNICODE)
   180     MultiByteToWideChar(CP_ACP, 0, tmp, -1, installBasePath, MAX_PATH);
   181 #else
   182     wcscpy(installBasePath, tmp);
   183 #endif
   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 }
   193 BOOL WINAPI 
   194 DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
   195 {
   196   return TRUE;
   197 }
   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   }
   215   th = (*stacktop);
   216   lstrcpyn(str,th->text, len);
   217   *stacktop = th->next;
   218   GlobalFree((HGLOBAL)th);
   219   return 0;
   220 }
   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   }
   237   th = (stack_t*)GlobalAlloc(GPTR, sizeof(stack_t) + len);
   238   lstrcpyn(th->text, str, len);
   239   th->next = *stacktop;
   240   *stacktop = th;
   241 }

mercurial