summaryrefslogtreecommitdiff
path: root/packaging/WiX/ca/CustomAction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'packaging/WiX/ca/CustomAction.cpp')
-rw-r--r--packaging/WiX/ca/CustomAction.cpp188
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;
+}