ADVAPI32: cleanup service handles
Mike McCormack
mike at codeweavers.com
Thu Jan 13 03:28:20 CST 2005
This patch removes the abuse of unions, reduces the size of each handle
(previously >512 bytes per handle) and makes sure the correct handle
type is passed to eacg function.
Mike
ChangeLog:
* cleanup service handles
-------------- next part --------------
Index: dlls/advapi32/service.c
===================================================================
RCS file: /home/wine/wine/dlls/advapi32/service.c,v
retrieving revision 1.79
diff -u -r1.79 service.c
--- dlls/advapi32/service.c 3 Jan 2005 17:12:51 -0000 1.79
+++ dlls/advapi32/service.c 13 Jan 2005 09:23:28 -0000
@@ -2,6 +2,7 @@
* Win32 advapi functions
*
* Copyright 1995 Sven Verdoolaege
+ * Copyright 2005 Mike McCormack
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -73,104 +74,90 @@
typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
struct sc_handle;
+typedef VOID (*sc_handle_destructor)(struct sc_handle *);
-struct sc_manager /* SCM handle */
+struct sc_handle
{
- HKEY hkey_scm_db; /* handle to services database in the registry */
- LONG ref_count; /* handle must remain alive until any related service */
- /* handle exists because DeleteService requires it */
+ SC_HANDLE_TYPE htype;
+ DWORD ref_count;
+ sc_handle_destructor destroy;
};
-struct sc_service /* service handle */
+struct sc_manager /* service control manager handle */
{
- HKEY hkey; /* handle to service entry in the registry (under hkey_scm_db) */
- struct sc_handle *sc_manager; /* pointer to SCM handle */
- WCHAR name[ MAX_SERVICE_NAME ];
+ struct sc_handle hdr;
+ HKEY hkey; /* handle to services database in the registry */
};
-struct sc_handle
+struct sc_service /* service handle */
{
- SC_HANDLE_TYPE htype;
- union
- {
- struct sc_manager manager;
- struct sc_service service;
- } u;
+ struct sc_handle hdr;
+ HKEY hkey; /* handle to service entry in the registry (under hkey) */
+ struct sc_manager *scm; /* pointer to SCM handle */
+ WCHAR name[1];
};
-static struct sc_handle* alloc_sc_handle( SC_HANDLE_TYPE htype )
+static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
+ sc_handle_destructor destroy)
{
- struct sc_handle *retval;
+ struct sc_handle *hdr;
- retval = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sc_handle) );
- if( retval != NULL )
+ hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
+ if (hdr)
{
- retval->htype = htype;
+ hdr->htype = htype;
+ hdr->ref_count = 1;
+ hdr->destroy = destroy;
}
- TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
- return retval;
+ TRACE("sc_handle type=%d -> %p\n", htype, hdr);
+ return hdr;
}
-static void free_sc_handle( struct sc_handle* handle )
+static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
{
- if( NULL == handle )
- return;
-
- switch( handle->htype )
- {
- case SC_HTYPE_MANAGER:
- {
- if( InterlockedDecrement( &handle->u.manager.ref_count ) )
- /* there are references to this handle */
- return;
+ struct sc_handle *hdr = (struct sc_handle *) handle;
- if( handle->u.manager.hkey_scm_db )
- RegCloseKey( handle->u.manager.hkey_scm_db );
- break;
- }
-
- case SC_HTYPE_SERVICE:
- {
- struct sc_handle *h = handle->u.service.sc_manager;
+ if (!hdr)
+ return NULL;
+ if (hdr->htype != htype)
+ return NULL;
+ return hdr;
+}
- if( h )
- {
- /* release SCM handle */
- if( 0 == InterlockedDecrement( &h->u.manager.ref_count ) )
- {
- /* it's time to destroy SCM handle */
- if( h->u.manager.hkey_scm_db )
- RegCloseKey( h->u.manager.hkey_scm_db );
-
- TRACE("SC_HANDLE (SCM) %p type=%d\n",h,h->htype);
-
- HeapFree( GetProcessHeap(), 0, h );
- }
- }
- if( handle->u.service.hkey )
- RegCloseKey( handle->u.service.hkey );
- break;
- }
- }
+static void sc_handle_free(struct sc_handle* hdr)
+{
+ if (!hdr)
+ return;
+ if (--hdr->ref_count)
+ return;
+ hdr->destroy(hdr);
+ HeapFree(GetProcessHeap(), 0, hdr);
+}
- TRACE("SC_HANDLE %p type=%d\n",handle,handle->htype);
+static void sc_handle_destroy_manager(struct sc_handle *handle)
+{
+ struct sc_manager *mgr = (struct sc_manager*) handle;
- HeapFree( GetProcessHeap(), 0, handle );
+ TRACE("destroying SC Manager %p\n", mgr);
+ if (mgr->hkey)
+ RegCloseKey(mgr->hkey);
}
-static void init_service_handle( struct sc_handle* handle,
- struct sc_handle* sc_manager,
- HKEY hKey, LPCWSTR lpServiceName )
+static void sc_handle_destroy_service(struct sc_handle *handle)
{
- /* init sc_service structure */
- handle->u.service.hkey = hKey;
- lstrcpynW( handle->u.service.name, lpServiceName, MAX_SERVICE_NAME );
-
- /* add reference to SCM handle */
- InterlockedIncrement( &sc_manager->u.manager.ref_count );
- handle->u.service.sc_manager = sc_manager;
+ struct sc_service *svc = (struct sc_service*) handle;
+
+ TRACE("destroying service %p\n", svc);
+ if (svc->hkey)
+ RegCloseKey(svc->hkey);
+ svc->hkey = NULL;
+ sc_handle_free(&svc->scm->hdr);
+ svc->scm = NULL;
}
+/******************************************************************************
+ * String management functions
+ */
static inline LPWSTR SERV_dup( LPCSTR str )
{
UINT len;
@@ -740,7 +727,7 @@
SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
DWORD dwDesiredAccess )
{
- struct sc_handle *retval;
+ struct sc_manager *manager;
HKEY hReg;
LONG r;
@@ -765,27 +752,27 @@
}
}
- retval = alloc_sc_handle( SC_HTYPE_MANAGER );
- if( NULL == retval ) return NULL;
-
- retval->u.manager.ref_count = 1;
+ manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
+ sc_handle_destroy_manager );
+ if (!manager)
+ return NULL;
r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
if (r!=ERROR_SUCCESS)
goto error;
r = RegOpenKeyExW(hReg, szServiceManagerKey,
- 0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
+ 0, KEY_ALL_ACCESS, &manager->hkey);
RegCloseKey( hReg );
if (r!=ERROR_SUCCESS)
goto error;
- TRACE("returning %p\n", retval);
+ TRACE("returning %p\n", manager);
- return (SC_HANDLE) retval;
+ return (SC_HANDLE) &manager->hdr;
error:
- free_sc_handle( retval );
+ sc_handle_free( &manager->hdr );
return NULL;
}
@@ -810,7 +797,7 @@
BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
LPSERVICE_STATUS lpServiceStatus )
{
- struct sc_handle *hsvc = hService;
+ struct sc_service *hsvc;
WCHAR object_name[ MAX_PATH ];
HANDLE mutex = NULL, shmem = NULL;
HANDLE disp_event = NULL, ack_event = NULL;
@@ -818,8 +805,18 @@
DWORD r;
BOOL ret = FALSE, mutex_owned = FALSE;
+ hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
+ if (!hsvc)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return FALSE;
+ }
+
+ TRACE("%p(%s) %ld %p\n", hService, debugstr_w(hsvc->name),
+ dwControl, lpServiceStatus);
+
/* open and hold mutex */
- snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, hsvc->u.service.name );
+ snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, hsvc->name );
mutex = OpenMutexW( MUTEX_ALL_ACCESS, FALSE, object_name );
if( NULL == mutex )
{
@@ -839,18 +836,18 @@
mutex_owned = TRUE;
/* open event objects */
- snprintfW( object_name, MAX_PATH, szServiceDispEventNameFmtW, hsvc->u.service.name );
+ snprintfW( object_name, MAX_PATH, szServiceDispEventNameFmtW, hsvc->name );
disp_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
if( NULL == disp_event )
goto done;
- snprintfW( object_name, MAX_PATH, szServiceAckEventNameFmtW, hsvc->u.service.name );
+ snprintfW( object_name, MAX_PATH, szServiceAckEventNameFmtW, hsvc->name );
ack_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
if( NULL == ack_event )
goto done;
/* get service environment block */
- seb = open_seb_shmem( hsvc->u.service.name, &shmem );
+ seb = open_seb_shmem( hsvc->name, &shmem );
if( NULL == seb )
goto done;
@@ -906,9 +903,9 @@
BOOL WINAPI
CloseServiceHandle( SC_HANDLE hSCObject )
{
- TRACE("(%p)\n", hSCObject);
+ TRACE("%p\n", hSCObject);
- free_sc_handle( (struct sc_handle*) hSCObject );
+ sc_handle_free( (struct sc_handle*) hSCObject );
return TRUE;
}
@@ -934,7 +931,7 @@
LPWSTR lpServiceNameW;
SC_HANDLE ret;
- TRACE("%p %s %ld\n",hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
+ TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
lpServiceNameW = SERV_dup(lpServiceName);
ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
@@ -951,12 +948,13 @@
SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
DWORD dwDesiredAccess)
{
- struct sc_handle *hscm = hSCManager;
- struct sc_handle *retval;
+ struct sc_manager *hscm;
+ struct sc_service *hsvc;
HKEY hKey;
long r;
+ DWORD len;
- TRACE("%p %s %ld\n",hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
+ TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
if (!lpServiceName)
{
@@ -964,24 +962,36 @@
return NULL;
}
- retval = alloc_sc_handle( SC_HTYPE_SERVICE );
- if( NULL == retval )
- return NULL;
+ hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
+ if (!hscm)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return FALSE;
+ }
- r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db,
- lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
+ r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
if (r!=ERROR_SUCCESS)
{
- free_sc_handle( retval );
SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
return NULL;
}
- init_service_handle( retval, hscm, hKey, lpServiceName );
+ len = strlenW(lpServiceName)+1;
+ hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
+ sizeof (struct sc_service) + len*sizeof(WCHAR),
+ sc_handle_destroy_service );
+ if (!hsvc)
+ return NULL;
+ strcpyW( hsvc->name, lpServiceName );
+ hsvc->hkey = hKey;
+
+ /* add reference to SCM handle */
+ hscm->hdr.ref_count++;
+ hsvc->scm = hscm;
- TRACE("returning %p\n",retval);
+ TRACE("returning %p\n",hsvc);
- return (SC_HANDLE) retval;
+ return (SC_HANDLE) &hsvc->hdr;
}
/******************************************************************************
@@ -996,11 +1006,11 @@
LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
LPCWSTR lpPassword )
{
- struct sc_handle *hscm = hSCManager;
- struct sc_handle *retval;
+ struct sc_manager *hscm;
+ struct sc_service *hsvc = NULL;
HKEY hKey;
LONG r;
- DWORD dp;
+ DWORD dp, len;
static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
static const WCHAR szType[] = {'T','y','p','e',0};
static const WCHAR szStart[] = {'S','t','a','r','t',0};
@@ -1012,17 +1022,18 @@
FIXME("%p %s %s\n", hSCManager,
debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
- retval = alloc_sc_handle( SC_HTYPE_SERVICE );
- if( NULL == retval )
+ hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
+ if (!hscm)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
return NULL;
+ }
- r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL,
+ r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
if (r!=ERROR_SUCCESS)
goto error;
- init_service_handle( retval, hscm, hKey, lpServiceName );
-
if (dp != REG_CREATED_NEW_KEY)
{
SetLastError(ERROR_SERVICE_EXISTS);
@@ -1091,10 +1102,22 @@
FIXME("Don't know how to add a ServiceStartName for a service.\n");
}
- return (SC_HANDLE) retval;
+ len = strlenW(lpServiceName)+1;
+ hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
+ sizeof (struct sc_service) + len*sizeof(WCHAR),
+ sc_handle_destroy_service );
+ if (!hsvc)
+ return NULL;
+ strcpyW( hsvc->name, lpServiceName );
+ hsvc->hkey = hKey;
+ hsvc->scm = hscm;
+ hscm->hdr.ref_count++;
+
+ return (SC_HANDLE) &hsvc->hdr;
error:
- free_sc_handle( retval );
+ if (hsvc)
+ sc_handle_free( &hsvc->hdr );
return NULL;
}
@@ -1157,13 +1180,21 @@
*/
BOOL WINAPI DeleteService( SC_HANDLE hService )
{
- struct sc_handle *hsvc = hService;
- HKEY hKey = hsvc->u.service.hkey;
+ struct sc_service *hsvc;
+ HKEY hKey;
WCHAR valname[MAX_PATH+1];
INT index = 0;
LONG rc;
DWORD size;
+ hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
+ if (!hsvc)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return FALSE;
+ }
+ hKey = hsvc->hkey;
+
size = MAX_PATH+1;
/* Clean out the values */
rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
@@ -1176,11 +1207,10 @@
}
RegCloseKey(hKey);
- hsvc->u.service.hkey = NULL;
+ hsvc->hkey = NULL;
/* delete the key */
- RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
- hsvc->u.service.name);
+ RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
return TRUE;
}
@@ -1249,7 +1279,7 @@
{
static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
- struct sc_handle *hsvc = hService;
+ struct sc_service *hsvc;
WCHAR path[MAX_PATH],str[MAX_PATH];
DWORD type,size;
DWORD i;
@@ -1264,18 +1294,25 @@
STARTUPINFOW startupinfo;
BOOL ret = FALSE;
- TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
+ TRACE("%p %ld %p\n",hService,dwNumServiceArgs,
lpServiceArgVectors);
+ hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
+ if (!hsvc)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return FALSE;
+ }
+
size = sizeof(str);
- r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
+ r = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
if (r!=ERROR_SUCCESS)
return FALSE;
ExpandEnvironmentStringsW(str,path,sizeof(path));
TRACE("Starting service %s\n", debugstr_w(path) );
- hLock = LockServiceDatabase( hsvc->u.service.sc_manager );
+ hLock = LockServiceDatabase( (SC_HANDLE) &hsvc->scm->hdr );
if( NULL == hLock )
return FALSE;
@@ -1291,14 +1328,14 @@
ERR("Couldn't map shared memory\n");
goto done;
}
- strcpyW( shmem_lock, hsvc->u.service.name );
+ strcpyW( shmem_lock, hsvc->name );
/* create service environment block */
size = sizeof(struct SEB);
for( i = 0; i < dwNumServiceArgs; i++ )
size += sizeof(WCHAR) * (1 + strlenW( lpServiceArgVectors[ i ] ));
- snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->u.service.name );
+ snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->name );
hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE,
NULL, PAGE_READWRITE, 0, size, str );
if( NULL == hServiceShmem )
@@ -1394,7 +1431,7 @@
BOOL WINAPI
QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
{
- struct sc_handle *hsvc = hService;
+ struct sc_service *hsvc;
LONG r;
DWORD type, val, size;
WCHAR object_name[ MAX_PATH ];
@@ -1402,8 +1439,15 @@
struct SEB *seb = NULL;
BOOL ret = FALSE, mutex_owned = FALSE;
+ hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
+ if (!hsvc)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return FALSE;
+ }
+
/* try to open service mutex */
- snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, hsvc->u.service.name );
+ snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, hsvc->name );
mutex = OpenMutexW( MUTEX_ALL_ACCESS, FALSE, object_name );
if( NULL == mutex )
goto stopped;
@@ -1421,7 +1465,7 @@
mutex_owned = TRUE;
/* get service environment block */
- seb = open_seb_shmem( hsvc->u.service.name, &shmem );
+ seb = open_seb_shmem( hsvc->name, &shmem );
if( NULL == seb )
goto done;
@@ -1440,7 +1484,7 @@
/* service stopped */
/* read the service type from the registry */
size = sizeof(val);
- r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
+ r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
if(type!=REG_DWORD)
{
ERR("invalid Type\n");
@@ -1497,7 +1541,8 @@
static const CHAR szImagePath[] = "ImagePath";
static const CHAR szGroup[] = "Group";
static const CHAR szDependencies[] = "Dependencies";
- HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
+ struct sc_service *hsvc;
+ HKEY hKey;
CHAR str_buffer[ MAX_PATH ];
LONG r;
DWORD type, val, sz, total, n;
@@ -1506,6 +1551,14 @@
TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
cbBufSize, pcbBytesNeeded);
+ hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
+ if (!hsvc)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return FALSE;
+ }
+ hKey = hsvc->hkey;
+
/* calculate the size required first */
total = sizeof (QUERY_SERVICE_CONFIGA);
@@ -1636,15 +1689,24 @@
static const WCHAR szGroup[] = {'G','r','o','u','p',0};
static const WCHAR szDependencies[] = {
'D','e','p','e','n','d','e','n','c','i','e','s',0};
- HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
WCHAR str_buffer[ MAX_PATH ];
LONG r;
DWORD type, val, sz, total, n;
LPBYTE p;
+ HKEY hKey;
+ struct sc_service *hsvc;
TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
cbBufSize, pcbBytesNeeded);
+ hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
+ if (!hsvc)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return FALSE;
+ }
+ hKey = hsvc->hkey;
+
/* calculate the size required first */
total = sizeof (QUERY_SERVICE_CONFIGW);
@@ -1921,7 +1983,16 @@
BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
LPVOID lpInfo)
{
- HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
+ HKEY hKey;
+ struct sc_service *hsvc;
+
+ hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
+ if (!hsvc)
+ {
+ SetLastError( ERROR_INVALID_HANDLE );
+ return FALSE;
+ }
+ hKey = hsvc->hkey;
if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
{
More information about the wine-patches
mailing list