MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CustomAction.cpp
1 /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #ifndef UNICODE
17 #define UNICODE
18 #endif
19 
20 #include <windows.h>
21 #include <winreg.h>
22 #include <msi.h>
23 #include <msiquery.h>
24 #include <wcautil.h>
25 #include <string.h>
26 #include <strsafe.h>
27 
28 /*
29  * Search the registry for a service whose ImagePath starts
30  * with our install directory. Stop and remove it if requested.
31  */
32 static TCHAR last_service_name[128];
33 int remove_service(TCHAR *installdir, int check_only) {
34  HKEY hKey;
35  int done = 0;
36 
37  if(wcslen(installdir) < 3) {
38  WcaLog(LOGMSG_STANDARD, "INSTALLDIR is suspiciously short, better not do anything.");
39  return 0;
40  }
41 
42  if(check_only == 0) {
43  WcaLog(LOGMSG_STANDARD, "Determining number of matching services...");
44  int servicecount = remove_service(installdir, 1);
45  if(servicecount <= 0) {
46  WcaLog(LOGMSG_STANDARD, "No services found, not removing anything.");
47  return 0;
48  } else if(servicecount == 1) {
49  TCHAR buf[256];
50  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);
51  int rc = MessageBox(NULL, buf, TEXT("Removing MySQL Server"), MB_ICONQUESTION|MB_YESNOCANCEL|MB_SYSTEMMODAL);
52  if(rc == IDCANCEL) return -1;
53  if(rc != IDYES) return 0;
54  } else if(servicecount > 0) {
55  TCHAR buf[256];
56  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);
57  int rc = MessageBox(NULL, buf, TEXT("Removing MySQL Server"), MB_ICONQUESTION|MB_YESNOCANCEL|MB_SYSTEMMODAL);
58  if(rc == IDCANCEL) return -1;
59  if(rc != IDYES) return 0;
60  }
61  }
62 
63  if(check_only == -1) check_only = 0;
64 
65  WcaLog(LOGMSG_STANDARD, "Looking for service...");
66  WcaLog(LOGMSG_STANDARD, "INSTALLDIR = %ls", installdir);
67  if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\services"), 0, KEY_READ, &hKey)==ERROR_SUCCESS) {
68  DWORD index = 0;
69  TCHAR keyname[1024];
70  DWORD keylen = sizeof(keyname);
71  FILETIME t;
72  /* Go through all services in the registry */
73  while(RegEnumKeyExW(hKey, index, keyname, &keylen, NULL, NULL, NULL, &t) == ERROR_SUCCESS) {
74  HKEY hServiceKey = 0;
75  TCHAR path[1024];
76  DWORD pathlen = sizeof(path)-1;
77  if (RegOpenKeyExW(hKey, keyname, NULL, KEY_READ, &hServiceKey) == ERROR_SUCCESS) {
78  /* Look at the ImagePath value of each service */
79  if (RegQueryValueExW(hServiceKey, TEXT("ImagePath"), NULL, NULL, (LPBYTE)path, &pathlen) == ERROR_SUCCESS) {
80  path[pathlen] = 0;
81  TCHAR *p = path;
82  if(p[0] == '"') p += 1;
83  /* See if it is similar to our install directory */
84  if(wcsncmp(p, installdir, wcslen(installdir)) == 0) {
85  WcaLog(LOGMSG_STANDARD, "Found service '%ls' with ImagePath '%ls'.", keyname, path);
86  swprintf_s(last_service_name, sizeof(last_service_name), TEXT("%ls"), keyname);
87  /* If we are supposed to stop and remove the service... */
88  if(!check_only) {
89  WcaLog(LOGMSG_STANDARD, "Trying to stop the service.");
90  SC_HANDLE hSCM = NULL;
91  hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
92  if(hSCM != NULL) {
93  SC_HANDLE hService = NULL;
94  hService = OpenService(hSCM, keyname, SERVICE_STOP|SERVICE_QUERY_STATUS|DELETE);
95  if(hService != NULL) {
96  WcaLog(LOGMSG_STANDARD, "Waiting for the service to stop...");
97  SERVICE_STATUS status;
98  /* Attempt to stop the service */
99  if(ControlService(hService, SERVICE_CONTROL_STOP, &status)) {
100  /* Now wait until it's stopped */
101  while("it's one big, mean and cruel world out there") {
102  if(!QueryServiceStatus(hService, &status)) break;
103  if(status.dwCurrentState == SERVICE_STOPPED) break;
104  Sleep(1000);
105  }
106  WcaLog(LOGMSG_STANDARD, "Stopped the service.");
107  }
108  /* Mark the service for deletion */
109  DeleteService(hService);
110  CloseServiceHandle(hService);
111  }
112  CloseServiceHandle(hSCM);
113  }
114  }
115  done++;
116  }
117  }
118  RegCloseKey(hServiceKey);
119  }
120  index++;
121  keylen = sizeof(keyname)-1;
122  }
123  RegCloseKey(hKey);
124  } else {
125  WcaLog(LOGMSG_STANDARD, "Can't seem to go through the list of installed services in the registry.");
126  }
127  return done;
128 }
129 
130 UINT wrap(MSIHANDLE hInstall, char *name, int check_only) {
131  HRESULT hr = S_OK;
132  UINT er = ERROR_SUCCESS;
133 
134  hr = WcaInitialize(hInstall, name);
135  ExitOnFailure(hr, "Failed to initialize");
136 
137  WcaLog(LOGMSG_STANDARD, "Initialized.");
138 
139  TCHAR INSTALLDIR[1024];
140  DWORD INSTALLDIR_size = sizeof(INSTALLDIR);
141  if(MsiGetPropertyW(hInstall, TEXT("CustomActionData"), INSTALLDIR, &INSTALLDIR_size) == ERROR_SUCCESS) {
142  int rc = remove_service(INSTALLDIR, check_only);
143  if(rc < 0) {
144  er = ERROR_CANCELLED;
145  }
146  } else {
147  er = ERROR_CANT_ACCESS_FILE;
148  }
149 
150 LExit:
151  return WcaFinalize(er);
152 }
153 
154 UINT __stdcall RemoveServiceNoninteractive(MSIHANDLE hInstall)
155 {
156  return wrap(hInstall, "RemoveServiceNoninteractive", -1);
157 }
158 
159 UINT __stdcall RemoveService(MSIHANDLE hInstall)
160 {
161  return wrap(hInstall, "RemoveService", 0);
162 }
163 
164 UINT __stdcall TestService(MSIHANDLE hInstall)
165 {
166  return wrap(hInstall, "TestService", 1);
167 }
168 
169 /* DllMain - Initialize and cleanup WiX custom action utils */
170 extern "C" BOOL WINAPI DllMain(
171  __in HINSTANCE hInst,
172  __in ULONG ulReason,
173  __in LPVOID
174  )
175 {
176  switch(ulReason)
177  {
178  case DLL_PROCESS_ATTACH:
179  WcaGlobalInitialize(hInst);
180  break;
181 
182  case DLL_PROCESS_DETACH:
183  WcaGlobalFinalize();
184  break;
185  }
186 
187  return TRUE;
188 }