diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index d9a0dfba46a..da75c73d585 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -60,8 +60,8 @@ ENDIF() ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE) ADD_DEFINITIONS(-D_WIN32_WINNT=0x0A00) -# We do not want the windows.h macros min/max -ADD_DEFINITIONS(-DNOMINMAX) +# We do not want the windows.h , or winsvc.h macros min/max +ADD_DEFINITIONS(-DNOMINMAX -DNOSERVICE) # Speed up build process excluding unused header files ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN) diff --git a/include/my_global.h b/include/my_global.h index 224909116dd..ed213e69f85 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -29,6 +29,14 @@ #pragma GCC poison __WIN__ #endif +#if defined(_MSC_VER) +/* + Following functions have bugs, when used with UTF-8 active codepage. + #include will use the non-buggy wrappers +*/ +#pragma deprecated("CreateServiceA", "OpenServiceA", "ChangeServiceConfigA") +#endif + /* InnoDB depends on some MySQL internals which other plugins should not need. This is because of InnoDB's foreign key support, "safe" binlog diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc index f712e29b843..026ac3e668e 100644 --- a/sql/mysql_install_db.cc +++ b/sql/mysql_install_db.cc @@ -30,6 +30,7 @@ #include struct IUnknown; #include +#include #include @@ -916,7 +917,7 @@ end: auto sc_manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (sc_manager) { - auto sc_handle= OpenServiceA(sc_manager,opt_service, DELETE); + auto sc_handle= OpenService(sc_manager,opt_service, DELETE); if (sc_handle) { DeleteService(sc_handle); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 808e590435a..46c28c862f6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -127,6 +127,7 @@ #ifdef _WIN32 #include #include +#include /* SERVICE_STOPPED, SERVICE_RUNNING etc */ #endif #include diff --git a/sql/winmain.cc b/sql/winmain.cc index f999767cb27..bdad409065d 100644 --- a/sql/winmain.cc +++ b/sql/winmain.cc @@ -55,6 +55,7 @@ #include #include #include +#include static SERVICE_STATUS svc_status{SERVICE_WIN32_OWN_PROCESS}; static SERVICE_STATUS_HANDLE svc_status_handle; diff --git a/sql/winservice.h b/sql/winservice.h index f9ab3eda332..a14ee73d146 100644 --- a/sql/winservice.h +++ b/sql/winservice.h @@ -17,11 +17,22 @@ /* Extract properties of a windows service binary path */ +#pragma once + #ifdef __cplusplus extern "C" { #endif -#include +#include +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4995) +#endif +#include +#ifdef _MSC_VER +#pragma warning(pop) +#endif + typedef struct mysqld_service_properties_st { char mysqld_exe[MAX_PATH]; @@ -32,9 +43,171 @@ typedef struct mysqld_service_properties_st int version_patch; } mysqld_service_properties; -extern int get_mysql_service_properties(const wchar_t *bin_path, +extern int get_mysql_service_properties(const wchar_t *bin_path, mysqld_service_properties *props); + +#if !defined(UNICODE) +/* + The following wrappers workaround Windows bugs + with CreateService/OpenService with ANSI codepage UTF8. + + Apparently, these function in ANSI mode, for this codepage only + do *not* behave as expected (as-if string parameters were + converted to UTF16 and "wide" function were called) +*/ +#include +static inline wchar_t* awstrdup(const char *str) +{ + if (!str) + return NULL; + size_t len= strlen(str) + 1; + wchar_t *wstr= (wchar_t *) malloc(sizeof(wchar_t)*len); + if (MultiByteToWideChar(GetACP(), 0, str, (int)len, wstr, (int)len) == 0) + { + free(wstr); + return NULL; + } + return wstr; +} + +#define AWSTRDUP(dest, src) \ + dest= awstrdup(src); \ + if (src && !dest) \ + { \ + ok= FALSE; \ + last_error = ERROR_OUTOFMEMORY; \ + goto end; \ + } + +static inline SC_HANDLE my_OpenService(SC_HANDLE hSCManager, LPCSTR lpServiceName, DWORD dwDesiredAccess) +{ + wchar_t *w_ServiceName= NULL; + BOOL ok=TRUE; + DWORD last_error=0; + SC_HANDLE sch=NULL; + + AWSTRDUP(w_ServiceName, lpServiceName); + sch= OpenServiceW(hSCManager, w_ServiceName, dwDesiredAccess); + if (!sch) + { + ok= FALSE; + last_error= GetLastError(); + } + +end: + free(w_ServiceName); + if (!ok) + SetLastError(last_error); + return sch; +} + +static inline SC_HANDLE my_CreateService(SC_HANDLE hSCManager, + LPCSTR lpServiceName, LPCSTR lpDisplayName, + DWORD dwDesiredAccess, DWORD dwServiceType, + DWORD dwStartType, DWORD dwErrorControl, + LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, LPCSTR lpDependencies, + LPCSTR lpServiceStartName, LPCSTR lpPassword) +{ + wchar_t *w_ServiceName= NULL; + wchar_t *w_DisplayName= NULL; + wchar_t *w_BinaryPathName= NULL; + wchar_t *w_LoadOrderGroup= NULL; + wchar_t *w_Dependencies= NULL; + wchar_t *w_ServiceStartName= NULL; + wchar_t *w_Password= NULL; + SC_HANDLE sch = NULL; + DWORD last_error=0; + BOOL ok= TRUE; + + AWSTRDUP(w_ServiceName,lpServiceName); + AWSTRDUP(w_DisplayName,lpDisplayName); + AWSTRDUP(w_BinaryPathName, lpBinaryPathName); + AWSTRDUP(w_LoadOrderGroup, lpLoadOrderGroup); + AWSTRDUP(w_Dependencies, lpDependencies); + AWSTRDUP(w_ServiceStartName, lpServiceStartName); + AWSTRDUP(w_Password, lpPassword); + + sch= CreateServiceW( + hSCManager, w_ServiceName, w_DisplayName, dwDesiredAccess, dwServiceType, + dwStartType, dwErrorControl, w_BinaryPathName, w_LoadOrderGroup, + lpdwTagId, w_Dependencies, w_ServiceStartName, w_Password); + if(!sch) + { + ok= FALSE; + last_error= GetLastError(); + } + +end: + free(w_ServiceName); + free(w_DisplayName); + free(w_BinaryPathName); + free(w_LoadOrderGroup); + free(w_Dependencies); + free(w_ServiceStartName); + free(w_Password); + + if (!ok) + SetLastError(last_error); + return sch; +} + +static inline BOOL my_ChangeServiceConfig(SC_HANDLE hService, DWORD dwServiceType, + DWORD dwStartType, DWORD dwErrorControl, + LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, LPCSTR lpDependencies, + LPCSTR lpServiceStartName, LPCSTR lpPassword, + LPCSTR lpDisplayName) +{ + wchar_t *w_DisplayName= NULL; + wchar_t *w_BinaryPathName= NULL; + wchar_t *w_LoadOrderGroup= NULL; + wchar_t *w_Dependencies= NULL; + wchar_t *w_ServiceStartName= NULL; + wchar_t *w_Password= NULL; + SC_HANDLE sch = NULL; + DWORD last_error=0; + BOOL ok= TRUE; + + AWSTRDUP(w_DisplayName, lpDisplayName); + AWSTRDUP(w_BinaryPathName, lpBinaryPathName); + AWSTRDUP(w_LoadOrderGroup, lpLoadOrderGroup); + AWSTRDUP(w_Dependencies, lpDependencies); + AWSTRDUP(w_ServiceStartName, lpServiceStartName); + AWSTRDUP(w_Password, lpPassword); + + ok= ChangeServiceConfigW( + hService, dwServiceType, dwStartType, dwErrorControl, w_BinaryPathName, + w_LoadOrderGroup, lpdwTagId, w_Dependencies, w_ServiceStartName, + w_Password, w_DisplayName); + if (!ok) + { + last_error= GetLastError(); + } + +end: + free(w_DisplayName); + free(w_BinaryPathName); + free(w_LoadOrderGroup); + free(w_Dependencies); + free(w_ServiceStartName); + free(w_Password); + + if (last_error) + SetLastError(last_error); + return ok; +} +#undef AWSTRDUP + +#undef OpenService +#define OpenService my_OpenService +#undef ChangeServiceConfig +#define ChangeServiceConfig my_ChangeServiceConfig +#undef CreateService +#define CreateService my_CreateService +#endif + #ifdef __cplusplus } #endif diff --git a/win/upgrade_wizard/CMakeLists.txt b/win/upgrade_wizard/CMakeLists.txt index 20a06a41215..fd3560e1ee6 100644 --- a/win/upgrade_wizard/CMakeLists.txt +++ b/win/upgrade_wizard/CMakeLists.txt @@ -5,6 +5,7 @@ ENDIF() # We need MFC # /permissive- flag does not play well with MFC, disable it. STRING(REPLACE "/permissive-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +REMOVE_DEFINITIONS(-DNOSERVICE) # fixes "already defined" warning in an AFX header FIND_PACKAGE(MFC) IF(NOT MFC_FOUND) diff --git a/win/upgrade_wizard/upgradeDlg.cpp b/win/upgrade_wizard/upgradeDlg.cpp index 80f7c18f757..7aae4890b51 100644 --- a/win/upgrade_wizard/upgradeDlg.cpp +++ b/win/upgrade_wizard/upgradeDlg.cpp @@ -141,24 +141,24 @@ void CUpgradeDlg::PopulateServicesList() ErrorExit("OpenSCManager failed"); } - static BYTE buf[64*1024]; + static BYTE buf[2*64*1024]; static BYTE configBuffer[8*1024]; DWORD bufsize= sizeof(buf); DWORD bufneed; DWORD num_services; - BOOL ok= EnumServicesStatusEx(scm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, + BOOL ok= EnumServicesStatusExW(scm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, buf, bufsize, &bufneed, &num_services, NULL, NULL); if(!ok) ErrorExit("EnumServicesStatusEx failed"); - LPENUM_SERVICE_STATUS_PROCESS info = - (LPENUM_SERVICE_STATUS_PROCESS)buf; + LPENUM_SERVICE_STATUS_PROCESSW info = + (LPENUM_SERVICE_STATUS_PROCESSW)buf; int index=-1; for (ULONG i=0; i < num_services; i++) { - SC_HANDLE service= OpenService(scm, info[i].lpServiceName, + SC_HANDLE service= OpenServiceW(scm, info[i].lpServiceName, SERVICE_QUERY_CONFIG); if (!service) continue; @@ -187,7 +187,11 @@ void CUpgradeDlg::PopulateServicesList() ServiceProperties props; props.myini= service_props.inifile; props.datadir= service_props.datadir; - props.servicename = info[i].lpServiceName; + char service_name_buf[1024]; + WideCharToMultiByte(GetACP(), 0, info[i].lpServiceName, -1, + service_name_buf, sizeof(service_name_buf), + 0, 0); + props.servicename= service_name_buf; if (service_props.version_major) { char ver[64]; @@ -198,7 +202,7 @@ void CUpgradeDlg::PopulateServicesList() else props.version= ""; - index = m_Services.AddString(info[i].lpServiceName); + index = m_Services.AddString(service_name_buf); services.resize(index+1); services[index] = props; }