diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c index 39a1afc8556..51a41e7f79a 100644 --- a/dlls/advapi32/service.c +++ b/dlls/advapi32/service.c @@ -1568,6 +1568,7 @@ BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName, { DWORD err; WCHAR buffer[2]; + DWORD size; TRACE("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer); @@ -1588,10 +1589,14 @@ BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName, *lpcchBuffer = 2; } + /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer + * includes the nul-terminator on input. */ + size = *lpcchBuffer - 1; + __TRY { err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName, - *lpcchBuffer, lpcchBuffer); + &size); } __EXCEPT(rpc_filter) { @@ -1599,6 +1604,10 @@ BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName, } __ENDTRY + /* The value of *lpcchBuffer excludes nul-terminator on output. */ + if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER) + *lpcchBuffer = size; + if (err) SetLastError(err); return err == ERROR_SUCCESS; @@ -1682,6 +1691,7 @@ BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, LPWSTR lpDisplayName, LPDWORD lpcchBuffer) { DWORD err; + DWORD size; WCHAR buffer[2]; TRACE("%p %s %p %p\n", hSCManager, @@ -1703,10 +1713,14 @@ BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, *lpcchBuffer = 2; } + /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer + * includes the nul-terminator on input. */ + size = *lpcchBuffer - 1; + __TRY { err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName, - *lpcchBuffer, lpcchBuffer); + &size); } __EXCEPT(rpc_filter) { @@ -1714,6 +1728,10 @@ BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, } __ENDTRY + /* The value of *lpcchBuffer excludes nul-terminator on output. */ + if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER) + *lpcchBuffer = size; + if (err) SetLastError(err); return err == ERROR_SUCCESS; diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl index 1e9aae25e58..0414dc407f2 100644 --- a/include/wine/svcctl.idl +++ b/include/wine/svcctl.idl @@ -257,17 +257,15 @@ typedef [switch_type(DWORD)] union DWORD svcctl_GetServiceDisplayNameW( [in] SC_RPC_HANDLE hSCManager, [in] LPCWSTR lpServiceName, - [out,size_is(cchBufSize)] WCHAR lpBuffer[], - [in] DWORD cchBufSize, - [in,out] DWORD *cchLength); + [out,string,size_is(*cchBufSize+1)] WCHAR lpBuffer[], + [in,out] DWORD *cchBufSize); /* Compatible with Windows function 0x15 */ DWORD svcctl_GetServiceKeyNameW( [in] SC_RPC_HANDLE hSCManager, [in] LPCWSTR lpServiceDisplayName, - [out,size_is(cchBufSize)] WCHAR lpBuffer[], - [in] DWORD cchBufSize, - [in,out] DWORD *cchLength); + [out,string,size_is(*cchBufSize+1)] WCHAR lpBuffer[], + [in,out] DWORD *cchBufSize); /* Not compatible with Windows function 0x16 */ DWORD svcctl_SCSetServiceBitsA(/* FIXME */); diff --git a/programs/services/rpc.c b/programs/services/rpc.c index 22391c24ec2..d463b622c7e 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -184,14 +184,13 @@ DWORD svcctl_GetServiceDisplayNameW( SC_RPC_HANDLE hSCManager, LPCWSTR lpServiceName, WCHAR *lpBuffer, - DWORD cchBufSize, - DWORD *cchLength) + DWORD *cchBufSize) { struct sc_manager_handle *manager; struct service_entry *entry; DWORD err; - WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceName), cchBufSize); + WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceName), *cchBufSize); if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS) return err; @@ -202,16 +201,18 @@ DWORD svcctl_GetServiceDisplayNameW( if (entry != NULL) { LPCWSTR name; + int len; service_lock_shared(entry); name = get_display_name(entry); - *cchLength = strlenW(name); - if (*cchLength < cchBufSize) + len = strlenW(name); + if (len <= *cchBufSize) { err = ERROR_SUCCESS; - lstrcpyW(lpBuffer, name); + memcpy(lpBuffer, name, (len + 1)*sizeof(*name)); } else err = ERROR_INSUFFICIENT_BUFFER; + *cchBufSize = len; service_unlock(entry); } else @@ -219,7 +220,7 @@ DWORD svcctl_GetServiceDisplayNameW( scmdatabase_unlock(manager->db); - if (err != ERROR_SUCCESS && cchBufSize > 0) + if (err != ERROR_SUCCESS) lpBuffer[0] = 0; return err; @@ -229,14 +230,13 @@ DWORD svcctl_GetServiceKeyNameW( SC_RPC_HANDLE hSCManager, LPCWSTR lpServiceDisplayName, WCHAR *lpBuffer, - DWORD cchBufSize, - DWORD *cchLength) + DWORD *cchBufSize) { struct service_entry *entry; struct sc_manager_handle *manager; DWORD err; - WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName), cchBufSize); + WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName), *cchBufSize); if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS) return err; @@ -246,15 +246,17 @@ DWORD svcctl_GetServiceKeyNameW( entry = scmdatabase_find_service_by_displayname(manager->db, lpServiceDisplayName); if (entry != NULL) { + int len; service_lock_shared(entry); - *cchLength = strlenW(entry->name); - if (*cchLength < cchBufSize) + len = strlenW(entry->name); + if (len <= *cchBufSize) { err = ERROR_SUCCESS; - lstrcpyW(lpBuffer, entry->name); + memcpy(lpBuffer, entry->name, (len + 1)*sizeof(*entry->name)); } else err = ERROR_INSUFFICIENT_BUFFER; + *cchBufSize = len; service_unlock(entry); } else @@ -262,7 +264,7 @@ DWORD svcctl_GetServiceKeyNameW( scmdatabase_unlock(manager->db); - if (err != ERROR_SUCCESS && cchBufSize > 0) + if (err != ERROR_SUCCESS) lpBuffer[0] = 0; return err;