mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
MDEV-27092 Windows - services that have non-ASCII characters do not work with activeCodePage=UTF8
CreateServiceA, OpenServiceA, and couple of other functions do not work correctly with non-ASCII character, in the special case where application has defined activeCodePage=UTF8. Workaround by redefining affected ANSI functions to own wrapper, which works by converting narrow(ANSI) to wide, then calling wide function. Deprecate original ANSI service functions, via declspec, so that we can catch their use.
This commit is contained in:
parent
99e5ae3b1a
commit
ea0a5cb0a4
8 changed files with 201 additions and 12 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 <winservice.h> 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
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <sddl.h>
|
||||
struct IUnknown;
|
||||
#include <shlwapi.h>
|
||||
#include <winservice.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -127,6 +127,7 @@
|
|||
#ifdef _WIN32
|
||||
#include <handle_connections_win.h>
|
||||
#include <sddl.h>
|
||||
#include <winservice.h> /* SERVICE_STOPPED, SERVICE_RUNNING etc */
|
||||
#endif
|
||||
|
||||
#include <my_service_manager.h>
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <winservice.h>
|
||||
|
||||
static SERVICE_STATUS svc_status{SERVICE_WIN32_OWN_PROCESS};
|
||||
static SERVICE_STATUS_HANDLE svc_status_handle;
|
||||
|
|
177
sql/winservice.h
177
sql/winservice.h
|
@ -17,11 +17,22 @@
|
|||
/*
|
||||
Extract properties of a windows service binary path
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <windows.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4995)
|
||||
#endif
|
||||
#include <winsvc.h>
|
||||
#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 <malloc.h>
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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= "<unknown>";
|
||||
|
||||
index = m_Services.AddString(info[i].lpServiceName);
|
||||
index = m_Services.AddString(service_name_buf);
|
||||
services.resize(index+1);
|
||||
services[index] = props;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue