diff options
Diffstat (limited to 'packaging/WiX/ca/CustomAction.cpp')
-rw-r--r-- | packaging/WiX/ca/CustomAction.cpp | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/packaging/WiX/ca/CustomAction.cpp b/packaging/WiX/ca/CustomAction.cpp new file mode 100644 index 00000000000..806535bc79a --- /dev/null +++ b/packaging/WiX/ca/CustomAction.cpp @@ -0,0 +1,188 @@ +/* Copyright 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef UNICODE +#define UNICODE +#endif + +#include <windows.h> +#include <winreg.h> +#include <msi.h> +#include <msiquery.h> +#include <wcautil.h> +#include <string.h> +#include <strsafe.h> + +/* + * Search the registry for a service whose ImagePath starts + * with our install directory. Stop and remove it if requested. + */ +static TCHAR last_service_name[128]; +int remove_service(TCHAR *installdir, int check_only) { + HKEY hKey; + int done = 0; + + if(wcslen(installdir) < 3) { + WcaLog(LOGMSG_STANDARD, "INSTALLDIR is suspiciously short, better not do anything."); + return 0; + } + + if(check_only == 0) { + WcaLog(LOGMSG_STANDARD, "Determining number of matching services..."); + int servicecount = remove_service(installdir, 1); + if(servicecount <= 0) { + WcaLog(LOGMSG_STANDARD, "No services found, not removing anything."); + return 0; + } else if(servicecount == 1) { + TCHAR buf[256]; + swprintf_s(buf, sizeof(buf), TEXT("There is a service called '%ls' set up to run from this installation. Do you wish me to stop and remove that service?"), last_service_name); + int rc = MessageBox(NULL, buf, TEXT("Removing MySQL Server"), MB_ICONQUESTION|MB_YESNOCANCEL|MB_SYSTEMMODAL); + if(rc == IDCANCEL) return -1; + if(rc != IDYES) return 0; + } else if(servicecount > 0) { + TCHAR buf[256]; + swprintf_s(buf, sizeof(buf), TEXT("There appear to be %d services set up to run from this installation. Do you wish me to stop and remove those services?"), servicecount); + int rc = MessageBox(NULL, buf, TEXT("Removing MySQL Server"), MB_ICONQUESTION|MB_YESNOCANCEL|MB_SYSTEMMODAL); + if(rc == IDCANCEL) return -1; + if(rc != IDYES) return 0; + } + } + + if(check_only == -1) check_only = 0; + + WcaLog(LOGMSG_STANDARD, "Looking for service..."); + WcaLog(LOGMSG_STANDARD, "INSTALLDIR = %ls", installdir); + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\services"), 0, KEY_READ, &hKey)==ERROR_SUCCESS) { + DWORD index = 0; + TCHAR keyname[1024]; + DWORD keylen = sizeof(keyname); + FILETIME t; + /* Go through all services in the registry */ + while(RegEnumKeyExW(hKey, index, keyname, &keylen, NULL, NULL, NULL, &t) == ERROR_SUCCESS) { + HKEY hServiceKey = 0; + TCHAR path[1024]; + DWORD pathlen = sizeof(path)-1; + if (RegOpenKeyExW(hKey, keyname, NULL, KEY_READ, &hServiceKey) == ERROR_SUCCESS) { + /* Look at the ImagePath value of each service */ + if (RegQueryValueExW(hServiceKey, TEXT("ImagePath"), NULL, NULL, (LPBYTE)path, &pathlen) == ERROR_SUCCESS) { + path[pathlen] = 0; + TCHAR *p = path; + if(p[0] == '"') p += 1; + /* See if it is similar to our install directory */ + if(wcsncmp(p, installdir, wcslen(installdir)) == 0) { + WcaLog(LOGMSG_STANDARD, "Found service '%ls' with ImagePath '%ls'.", keyname, path); + swprintf_s(last_service_name, sizeof(last_service_name), TEXT("%ls"), keyname); + /* If we are supposed to stop and remove the service... */ + if(!check_only) { + WcaLog(LOGMSG_STANDARD, "Trying to stop the service."); + SC_HANDLE hSCM = NULL; + hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); + if(hSCM != NULL) { + SC_HANDLE hService = NULL; + hService = OpenService(hSCM, keyname, SERVICE_STOP|SERVICE_QUERY_STATUS|DELETE); + if(hService != NULL) { + WcaLog(LOGMSG_STANDARD, "Waiting for the service to stop..."); + SERVICE_STATUS status; + /* Attempt to stop the service */ + if(ControlService(hService, SERVICE_CONTROL_STOP, &status)) { + /* Now wait until it's stopped */ + while("it's one big, mean and cruel world out there") { + if(!QueryServiceStatus(hService, &status)) break; + if(status.dwCurrentState == SERVICE_STOPPED) break; + Sleep(1000); + } + WcaLog(LOGMSG_STANDARD, "Stopped the service."); + } + /* Mark the service for deletion */ + DeleteService(hService); + CloseServiceHandle(hService); + } + CloseServiceHandle(hSCM); + } + } + done++; + } + } + RegCloseKey(hServiceKey); + } + index++; + keylen = sizeof(keyname)-1; + } + RegCloseKey(hKey); + } else { + WcaLog(LOGMSG_STANDARD, "Can't seem to go through the list of installed services in the registry."); + } + return done; +} + +UINT wrap(MSIHANDLE hInstall, char *name, int check_only) { + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + + hr = WcaInitialize(hInstall, name); + ExitOnFailure(hr, "Failed to initialize"); + + WcaLog(LOGMSG_STANDARD, "Initialized."); + + TCHAR INSTALLDIR[1024]; + DWORD INSTALLDIR_size = sizeof(INSTALLDIR); + if(MsiGetPropertyW(hInstall, TEXT("CustomActionData"), INSTALLDIR, &INSTALLDIR_size) == ERROR_SUCCESS) { + int rc = remove_service(INSTALLDIR, check_only); + if(rc < 0) { + er = ERROR_CANCELLED; + } + } else { + er = ERROR_CANT_ACCESS_FILE; + } + +LExit: + return WcaFinalize(er); +} + +UINT __stdcall RemoveServiceNoninteractive(MSIHANDLE hInstall) +{ + return wrap(hInstall, "RemoveServiceNoninteractive", -1); +} + +UINT __stdcall RemoveService(MSIHANDLE hInstall) +{ + return wrap(hInstall, "RemoveService", 0); +} + +UINT __stdcall TestService(MSIHANDLE hInstall) +{ + return wrap(hInstall, "TestService", 1); +} + +/* DllMain - Initialize and cleanup WiX custom action utils */ +extern "C" BOOL WINAPI DllMain( + __in HINSTANCE hInst, + __in ULONG ulReason, + __in LPVOID + ) +{ + switch(ulReason) + { + case DLL_PROCESS_ATTACH: + WcaGlobalInitialize(hInst); + break; + + case DLL_PROCESS_DETACH: + WcaGlobalFinalize(); + break; + } + + return TRUE; +} |