if (lpDatabaseName == NULL)
lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
+ if (wcsicmp(lpDatabaseName,SERVICES_FAILED_DATABASEW)==0)
+ {
+ DPRINT1("Database %S, does not exist\n",lpDatabaseName);
+ return ERROR_DATABASE_DOES_NOT_EXIST;
+ }
+ else if (wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
+ {
+ DPRINT1("Invalid Database name %S.\n",lpDatabaseName);
+ return ERROR_INVALID_NAME;
+ }
+
Ptr = (MANAGER_HANDLE*) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(MANAGER_HANDLE) + wcslen(lpDatabaseName) * sizeof(WCHAR));
}
+/* Internal recursive function */
+/* Need to search for every dependency on every service */
+static DWORD
+Int_EnumDependentServicesW(HKEY hServicesKey,
+ PSERVICE lpService,
+ DWORD dwServiceState,
+ PSERVICE *lpServices,
+ LPDWORD pcbBytesNeeded,
+ LPDWORD lpServicesReturned)
+{
+ DWORD dwError = ERROR_SUCCESS;
+ WCHAR szNameBuf[MAX_PATH];
+ WCHAR szValueBuf[MAX_PATH];
+ WCHAR *lpszNameBuf = szNameBuf;
+ WCHAR *lpszValueBuf = szValueBuf;
+ DWORD dwSize;
+ DWORD dwNumSubKeys;
+ DWORD dwIteration;
+ PSERVICE lpCurrentService;
+ HKEY hServiceEnumKey;
+ DWORD dwCurrentServiceState = SERVICE_ACTIVE;
+ DWORD dwDependServiceStrPtr = 0;
+ DWORD dwRequiredSize = 0;
+
+ /* Get the number of service keys */
+ dwError = RegQueryInfoKeyW(hServicesKey,
+ NULL,
+ NULL,
+ NULL,
+ &dwNumSubKeys,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT1("ERROR! Unable to get number of services keys.\n");
+ return dwError;
+ }
+
+ /* Iterate the service keys to see if another service depends on the this service */
+ for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
+ {
+ dwSize = MAX_PATH;
+ dwError = RegEnumKeyExW(hServicesKey,
+ dwIteration,
+ lpszNameBuf,
+ &dwSize,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (dwError != ERROR_SUCCESS)
+ return dwError;
+
+ /* Open the Service key */
+ dwError = RegOpenKeyExW(hServicesKey,
+ lpszNameBuf,
+ 0,
+ KEY_READ,
+ &hServiceEnumKey);
+ if (dwError != ERROR_SUCCESS)
+ return dwError;
+
+ dwSize = MAX_PATH;
+
+ /* Check for the DependOnService Value */
+ dwError = RegQueryValueExW(hServiceEnumKey,
+ L"DependOnService",
+ NULL,
+ NULL,
+ (LPBYTE)lpszValueBuf,
+ &dwSize);
+
+ /* FIXME: Handle load order. */
+
+ /* If the service found has a DependOnService value */
+ if (dwError == ERROR_SUCCESS)
+ {
+ dwDependServiceStrPtr = 0;
+
+ /* Can be more than one Dependencies in the DependOnService string */
+ while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
+ {
+ if (wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
+ {
+ /* Get the current enumed service pointer */
+ lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
+
+ /* Check for valid Service */
+ if (!lpCurrentService)
+ {
+ /* This should never happen! */
+ DPRINT1("This should not happen at this point, report to Developer\n");
+ return ERROR_NOT_FOUND;
+ }
+
+ /* Determine state the service is in */
+ if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+ dwCurrentServiceState = SERVICE_INACTIVE;
+
+ /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
+ if ((dwCurrentServiceState == dwServiceState) ||
+ (dwServiceState == SERVICE_STATE_ALL))
+ {
+ /* Calculate the required size */
+ dwRequiredSize += sizeof(SERVICE_STATUS);
+ dwRequiredSize += ((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
+ dwRequiredSize += ((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
+
+ /* Add the size for service name and display name pointers */
+ dwRequiredSize += (2 * sizeof(PVOID));
+
+ /* increase the BytesNeeded size */
+ *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
+
+ /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
+ comes first */
+
+ /* Recursive call to check for its dependencies */
+ Int_EnumDependentServicesW(hServicesKey,
+ lpCurrentService,
+ dwServiceState,
+ lpServices,
+ pcbBytesNeeded,
+ lpServicesReturned);
+
+ /* If the lpServices is valid set the service pointer */
+ if (lpServices)
+ lpServices[*lpServicesReturned] = lpCurrentService;
+
+ *lpServicesReturned = *lpServicesReturned + 1;
+ }
+ }
+
+ dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
+ }
+ }
+ else if (*pcbBytesNeeded)
+ {
+ dwError = ERROR_SUCCESS;
+ }
+
+ RegCloseKey(hServiceEnumKey);
+ }
+
+ return dwError;
+}
+
+
/* Function 0 */
DWORD RCloseServiceHandle(
handle_t BindingHandle,
PSERVICE_HANDLE hSvc;
PSERVICE lpService = NULL;
HKEY hServiceKey = NULL;
+ LPWSTR lpDisplayNameW = NULL;
DPRINT("RChangeServiceConfigW() called\n");
DPRINT("dwServiceType = %lu\n", dwServiceType);
REG_SZ,
(LPBYTE)lpDisplayName,
(wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
- /* FIXME: update lpService->lpDisplayName */
+
+ /* Update the display name */
+ lpDisplayNameW = (LPWSTR)HeapAlloc(GetProcessHeap(),
+ 0,
+ (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
+ if (lpDisplayNameW == NULL)
+ {
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ if (lpService->lpDisplayName != lpService->lpServiceName)
+ HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
+
+ lpService->lpDisplayName = lpDisplayNameW;
}
if (dwServiceType != SERVICE_NO_CHANGE)
LPBOUNDED_DWORD_256K lpServicesReturned)
{
DWORD dwError = ERROR_SUCCESS;
+ DWORD dwServicesReturned = 0;
+ DWORD dwServiceCount;
+ HKEY hServicesKey = NULL;
+ LPSC_RPC_HANDLE hSCObject;
+ PSERVICE_HANDLE hSvc;
+ PSERVICE lpService = NULL;
+ PSERVICE *lpServicesArray = NULL;
+ LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
+ LPWSTR lpStr;
- UNIMPLEMENTED;
*pcbBytesNeeded = 0;
*lpServicesReturned = 0;
- DPRINT1("REnumDependentServicesW() done (Error %lu)\n", dwError);
+ DPRINT("REnumDependentServicesW() called\n");
+
+ hSCObject = &hService;
+ hSvc = (PSERVICE_HANDLE) *hSCObject;
+ lpService = hSvc->ServiceEntry;
+
+ /* Check access rights */
+ if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+ SC_MANAGER_ENUMERATE_SERVICE))
+ {
+ DPRINT1("Insufficient access rights! 0x%lx\n",
+ hSvc->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ /* Open the Services Reg key */
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"System\\CurrentControlSet\\Services",
+ 0,
+ KEY_READ,
+ &hServicesKey);
+ if (dwError != ERROR_SUCCESS)
+ return dwError;
+
+ /* First determine the bytes needed and get the number of dependent services */
+ dwError = Int_EnumDependentServicesW(hServicesKey,
+ lpService,
+ dwServiceState,
+ NULL,
+ pcbBytesNeeded,
+ &dwServicesReturned);
+ if (dwError != ERROR_SUCCESS)
+ goto Done;
+
+ /* If buffer size is less than the bytes needed or pointer is null */
+ if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
+ {
+ dwError = ERROR_MORE_DATA;
+ goto Done;
+ }
+
+ /* Allocate memory for array of service pointers */
+ lpServicesArray = HeapAlloc(GetProcessHeap(),
+ 0,
+ (dwServicesReturned + 1) * sizeof(PSERVICE));
+ if (!lpServicesArray)
+ {
+ DPRINT1("Could not allocate a buffer!!\n");
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto Done;
+ }
+
+ dwServicesReturned = 0;
+ *pcbBytesNeeded = 0;
+
+ dwError = Int_EnumDependentServicesW(hServicesKey,
+ lpService,
+ dwServiceState,
+ lpServicesArray,
+ pcbBytesNeeded,
+ &dwServicesReturned);
+ if (dwError != ERROR_SUCCESS)
+ {
+ goto Done;
+ }
+
+ lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
+ lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
+
+ /* Copy EnumDepenedentService to Buffer */
+ for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
+ {
+ lpService = lpServicesArray[dwServiceCount];
+
+ /* Copy status info */
+ memcpy(&lpServicesPtr->ServiceStatus,
+ &lpService->Status,
+ sizeof(SERVICE_STATUS));
+
+ /* Copy display name */
+ wcscpy(lpStr, lpService->lpDisplayName);
+ lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
+ lpStr += (wcslen(lpService->lpDisplayName) + 1);
+
+ /* Copy service name */
+ wcscpy(lpStr, lpService->lpServiceName);
+ lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
+ lpStr += (wcslen(lpService->lpServiceName) + 1);
+
+ lpServicesPtr ++;
+ }
+
+ *lpServicesReturned = dwServicesReturned;
+
+Done:
+ if (lpServicesArray != NULL)
+ HeapFree(GetProcessHeap(), 0, lpServicesArray);
+
+ RegCloseKey(hServicesKey);
+
+ DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
return dwError;
}
if (!lpServiceHandle)
return ERROR_INVALID_PARAMETER;
+ if (!lpServiceName)
+ return ERROR_INVALID_ADDRESS;
+
hManager = (PMANAGER_HANDLE)hSCManager;
if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
{
LPWSTR lpImagePath = NULL;
LPWSTR lpServiceStartName = NULL;
DWORD dwRequiredSize;
- LPQUERY_SERVICE_CONFIGW lpConfig;
+ LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
+ WCHAR lpEmptyString[] = {0,0};
LPWSTR lpStr;
DPRINT("RQueryServiceConfigW() called\n");
if (lpImagePath != NULL)
dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
+ else
+ dwRequiredSize += 2 * sizeof(WCHAR);
if (lpService->lpGroup != NULL)
dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
+ else
+ dwRequiredSize += 2 * sizeof(WCHAR);
/* FIXME: Add Dependencies length*/
if (lpServiceStartName != NULL)
dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
+ else
+ dwRequiredSize += 2 * sizeof(WCHAR);
if (lpService->lpDisplayName != NULL)
dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
+ else
+ dwRequiredSize += 2 * sizeof(WCHAR);
if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
{
if (lpImagePath != NULL)
{
wcscpy(lpStr, lpImagePath);
- lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
- lpStr += (wcslen(lpImagePath) + 1);
}
else
{
- lpConfig->lpBinaryPathName = NULL;
+ wcscpy(lpStr, lpEmptyString);
}
+ lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpStr += (wcslen(lpStr) + 1);
+
if (lpService->lpGroup != NULL)
{
wcscpy(lpStr, lpService->lpGroup->lpGroupName);
- lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
- lpStr += (wcslen(lpService->lpGroup->lpGroupName) + 1);
}
else
{
- lpConfig->lpLoadOrderGroup = NULL;
+ wcscpy(lpStr, lpEmptyString);
}
+ lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpStr += (wcslen(lpStr) + 1);
+
/* FIXME: Append Dependencies */
- lpConfig->lpDependencies = NULL;
+ wcscpy(lpStr, lpEmptyString);
+
+ lpStr += (wcslen(lpStr) + 1);
+ lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
if (lpServiceStartName != NULL)
{
wcscpy(lpStr, lpServiceStartName);
- lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
- lpStr += (wcslen(lpServiceStartName) + 1);
}
else
{
- lpConfig->lpServiceStartName = NULL;
+ wcscpy(lpStr, lpEmptyString);
}
+ lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpStr += (wcslen(lpStr) + 1);
+
if (lpService->lpDisplayName != NULL)
{
wcscpy(lpStr, lpService->lpDisplayName);
- lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
}
else
{
- lpConfig->lpDisplayName = NULL;
+ wcscpy(lpStr, lpEmptyString);
}
+
+ lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
}
if (pcbBytesNeeded != NULL)
DWORD dwPwSize,
LPSTR lpDisplayName)
{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
+ DWORD dwError = ERROR_SUCCESS;
+ PSERVICE_HANDLE hSvc;
+ PSERVICE lpService = NULL;
+ HKEY hServiceKey = NULL;
+ LPWSTR lpDisplayNameW = NULL;
+ // LPWSTR lpBinaryPathNameW = NULL;
+ LPWSTR lpLoadOrderGroupW = NULL;
+ LPWSTR lpDependenciesW = NULL;
+ // LPWSTR lpPasswordW = NULL;
+ DPRINT("RChangeServiceConfigA() called\n");
+ DPRINT("dwServiceType = %lu\n", dwServiceType);
+ DPRINT("dwStartType = %lu\n", dwStartType);
+ DPRINT("dwErrorControl = %lu\n", dwErrorControl);
+ DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
+ DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
+ DPRINT("lpDisplayName = %s\n", lpDisplayName);
-/* Function 24 */
-DWORD RCreateServiceA(
- handle_t BindingHandle,
- SC_RPC_HANDLE hSCManager,
- LPSTR lpServiceName,
- LPSTR lpDisplayName,
- DWORD dwDesiredAccess,
- DWORD dwServiceType,
- DWORD dwStartType,
- DWORD dwErrorControl,
- LPSTR lpBinaryPathName,
- LPSTR lpLoadOrderGroup,
- LPDWORD lpdwTagId,
- LPBYTE lpDependencies,
- DWORD dwDependSize,
- LPSTR lpServiceStartName,
- LPBYTE lpPassword,
- DWORD dwPwSize,
- LPSC_RPC_HANDLE lpServiceHandle)
-{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
+ if (ScmShutdown)
+ return ERROR_SHUTDOWN_IN_PROGRESS;
+ hSvc = (PSERVICE_HANDLE)hService;
+ if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
+ {
+ DPRINT1("Invalid handle tag!\n");
+ return ERROR_INVALID_HANDLE;
+ }
-/* Function 25 */
-DWORD REnumDependentServicesA(
- handle_t BindingHandle,
- SC_RPC_HANDLE hService,
- DWORD dwServiceState,
- LPBYTE lpServices,
- DWORD cbBufSize,
- LPBOUNDED_DWORD_256K pcbBytesNeeded,
- LPBOUNDED_DWORD_256K lpServicesReturned)
-{
- UNIMPLEMENTED;
- *pcbBytesNeeded = 0;
- *lpServicesReturned = 0;
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
+ if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+ SERVICE_CHANGE_CONFIG))
+ {
+ DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
+ }
+ lpService = hSvc->ServiceEntry;
+ if (lpService == NULL)
+ {
+ DPRINT1("lpService == NULL!\n");
+ return ERROR_INVALID_HANDLE;
+ }
-/* Function 26 */
-DWORD REnumServicesStatusA(
- handle_t BindingHandle,
- SC_RPC_HANDLE hSCManager,
- DWORD dwServiceType,
- DWORD dwServiceState,
- LPBYTE lpBuffer,
- DWORD dwBufSize,
- LPBOUNDED_DWORD_256K pcbBytesNeeded,
- LPBOUNDED_DWORD_256K lpServicesReturned,
- LPBOUNDED_DWORD_256K lpResumeHandle)
-{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
+ /* FIXME: Lock database exclusively */
+ if (lpService->bDeleted)
+ {
+ /* FIXME: Unlock database */
+ DPRINT1("The service has already been marked for delete!\n");
+ return ERROR_SERVICE_MARKED_FOR_DELETE;
+ }
-/* Function 27 */
-DWORD ROpenSCManagerA(
- handle_t BindingHandle,
- LPSTR lpMachineName,
- LPSTR lpDatabaseName,
- DWORD dwDesiredAccess,
- LPSC_RPC_HANDLE lpScHandle)
-{
- UNICODE_STRING MachineName;
- UNICODE_STRING DatabaseName;
- DWORD dwError;
+ /* Open the service key */
+ dwError = ScmOpenServiceKey(lpService->szServiceName,
+ KEY_SET_VALUE,
+ &hServiceKey);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
- DPRINT("ROpenSCManagerA() called\n");
+ /* Write service data to the registry */
- if (lpMachineName)
- RtlCreateUnicodeStringFromAsciiz(&MachineName,
- lpMachineName);
+ if (lpDisplayName != NULL && *lpDisplayName != 0)
+ {
+ /* Set the display name */
+ lpDisplayNameW = HeapAlloc(GetProcessHeap(),
+ 0,
+ (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
+ if (lpDisplayNameW == NULL)
+ {
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ MultiByteToWideChar(CP_ACP,
+ 0,
+ lpDisplayName,
+ -1,
+ lpDisplayNameW,
+ (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
+
+ RegSetValueExW(hServiceKey,
+ L"DisplayName",
+ 0,
+ REG_SZ,
+ (LPBYTE)lpDisplayNameW,
+ (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
+
+ /* Update lpService->lpDisplayName */
+ if (lpService->lpDisplayName)
+ HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
+
+ lpService->lpDisplayName = lpDisplayNameW;
+ }
+
+ if (dwServiceType != SERVICE_NO_CHANGE)
+ {
+ /* Set the service type */
+ dwError = RegSetValueExW(hServiceKey,
+ L"Type",
+ 0,
+ REG_DWORD,
+ (LPBYTE)&dwServiceType,
+ sizeof(DWORD));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ lpService->Status.dwServiceType = dwServiceType;
+ }
+
+ if (dwStartType != SERVICE_NO_CHANGE)
+ {
+ /* Set the start value */
+ dwError = RegSetValueExW(hServiceKey,
+ L"Start",
+ 0,
+ REG_DWORD,
+ (LPBYTE)&dwStartType,
+ sizeof(DWORD));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ lpService->dwStartType = dwStartType;
+ }
+
+ if (dwErrorControl != SERVICE_NO_CHANGE)
+ {
+ /* Set the error control value */
+ dwError = RegSetValueExW(hServiceKey,
+ L"ErrorControl",
+ 0,
+ REG_DWORD,
+ (LPBYTE)&dwErrorControl,
+ sizeof(DWORD));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ lpService->dwErrorControl = dwErrorControl;
+ }
+
+#if 0
+ /* FIXME: set the new ImagePath value */
+
+ /* Set the image path */
+ if (dwServiceType & SERVICE_WIN32)
+ {
+ if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
+ {
+ lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, (wcslen(lpBinaryPathNameW)+1) * sizeof(WCHAR));
+ dwError = RegSetValueExW(hServiceKey,
+ L"ImagePath",
+ 0,
+ REG_EXPAND_SZ,
+ (LPBYTE)lpBinaryPathNameW,
+ (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+ }
+ }
+ else if (dwServiceType & SERVICE_DRIVER)
+ {
+ if (lpImagePath != NULL && *lpImagePath != 0)
+ {
+ dwError = RegSetValueExW(hServiceKey,
+ L"ImagePath",
+ 0,
+ REG_EXPAND_SZ,
+ (LPBYTE)lpImagePath,
+ (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+ }
+ }
+#endif
+
+ /* Set the group name */
+ if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
+ {
+ lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
+ 0,
+ (strlen(lpLoadOrderGroup)+1) * sizeof(WCHAR));
+ if (lpLoadOrderGroupW == NULL)
+ {
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ MultiByteToWideChar(CP_ACP,
+ 0,
+ lpLoadOrderGroup,
+ -1,
+ lpLoadOrderGroupW,
+ (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
+
+ dwError = RegSetValueExW(hServiceKey,
+ L"Group",
+ 0,
+ REG_SZ,
+ (LPBYTE)lpLoadOrderGroupW,
+ (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ /* FIXME: Update lpService->lpServiceGroup */
+
+ HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
+ }
+
+ if (lpdwTagId != NULL)
+ {
+ dwError = ScmAssignNewTag(lpService);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ dwError = RegSetValueExW(hServiceKey,
+ L"Tag",
+ 0,
+ REG_DWORD,
+ (LPBYTE)&lpService->dwTag,
+ sizeof(DWORD));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ *lpdwTagId = lpService->dwTag;
+ }
+
+ /* Write dependencies */
+ if (lpDependencies != NULL && *lpDependencies != 0)
+ {
+ lpDependenciesW = HeapAlloc(GetProcessHeap(),
+ 0,
+ (strlen(lpDependencies)+1) * sizeof(WCHAR));
+ if (lpDependenciesW == NULL)
+ {
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ MultiByteToWideChar(CP_ACP,
+ 0,
+ lpDependencies,
+ dwDependSize,
+ lpDependenciesW,
+ (wcslen(lpDependenciesW)+1) * sizeof(WCHAR));
+
+ dwError = ScmWriteDependencies(hServiceKey,
+ (LPWSTR)lpDependenciesW,
+ dwDependSize);
+
+ HeapFree(GetProcessHeap(), 0, lpDependenciesW);
+ }
+
+ if (lpPassword != NULL)
+ {
+ /* FIXME: Write password */
+ }
+
+ /* FIXME: Unlock database */
+
+done:
+ if (hServiceKey != NULL)
+ RegCloseKey(hServiceKey);
+
+ DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
+
+ return dwError;
+}
+
+
+/* Function 24 */
+DWORD RCreateServiceA(
+ handle_t BindingHandle,
+ SC_RPC_HANDLE hSCManager,
+ LPSTR lpServiceName,
+ LPSTR lpDisplayName,
+ DWORD dwDesiredAccess,
+ DWORD dwServiceType,
+ DWORD dwStartType,
+ DWORD dwErrorControl,
+ LPSTR lpBinaryPathName,
+ LPSTR lpLoadOrderGroup,
+ LPDWORD lpdwTagId,
+ LPBYTE lpDependencies,
+ DWORD dwDependSize,
+ LPSTR lpServiceStartName,
+ LPBYTE lpPassword,
+ DWORD dwPwSize,
+ LPSC_RPC_HANDLE lpServiceHandle)
+{
+ UNIMPLEMENTED;
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 25 */
+DWORD REnumDependentServicesA(
+ handle_t BindingHandle,
+ SC_RPC_HANDLE hService,
+ DWORD dwServiceState,
+ LPBYTE lpServices,
+ DWORD cbBufSize,
+ LPBOUNDED_DWORD_256K pcbBytesNeeded,
+ LPBOUNDED_DWORD_256K lpServicesReturned)
+{
+ DWORD dwError = ERROR_SUCCESS;
+ DWORD dwServicesReturned = 0;
+ DWORD dwServiceCount;
+ HKEY hServicesKey = NULL;
+ LPSC_RPC_HANDLE hSCObject;
+ PSERVICE_HANDLE hSvc;
+ PSERVICE lpService = NULL;
+ PSERVICE *lpServicesArray = NULL;
+ LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
+ LPSTR lpStr;
+
+ *pcbBytesNeeded = 0;
+ *lpServicesReturned = 0;
+
+ DPRINT("REnumDependentServicesA() called\n");
+
+ hSCObject = &hService;
+ hSvc = (PSERVICE_HANDLE) *hSCObject;
+ lpService = hSvc->ServiceEntry;
+
+ /* Check access rights */
+ if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+ SC_MANAGER_ENUMERATE_SERVICE))
+ {
+ DPRINT1("Insufficient access rights! 0x%lx\n",
+ hSvc->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ /* Open the Services Reg key */
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"System\\CurrentControlSet\\Services",
+ 0,
+ KEY_READ,
+ &hServicesKey);
+
+ if (dwError != ERROR_SUCCESS) return dwError;
+
+ /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
+ both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
+ are the same for both. Verified in WINXP. */
+
+ /* First determine the bytes needed and get the number of dependent services*/
+ dwError = Int_EnumDependentServicesW(hServicesKey,
+ lpService,
+ dwServiceState,
+ NULL,
+ pcbBytesNeeded,
+ &dwServicesReturned);
+ if (dwError != ERROR_SUCCESS)
+ goto Done;
+
+ /* If buffer size is less than the bytes needed or pointer is null*/
+ if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
+ {
+ dwError = ERROR_MORE_DATA;
+ goto Done;
+ }
+
+ /* Allocate memory for array of service pointers */
+ lpServicesArray = HeapAlloc(GetProcessHeap(),
+ 0,
+ (dwServicesReturned + 1) * sizeof(PSERVICE));
+ if (!lpServicesArray)
+ {
+ DPRINT1("Could not allocate a buffer!!\n");
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto Done;
+ }
+
+ dwServicesReturned = 0;
+ *pcbBytesNeeded = 0;
+
+ dwError = Int_EnumDependentServicesW(hServicesKey,
+ lpService,
+ dwServiceState,
+ lpServicesArray,
+ pcbBytesNeeded,
+ &dwServicesReturned);
+ if (dwError != ERROR_SUCCESS)
+ {
+ goto Done;
+ }
+
+ lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
+ lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
+
+ /* Copy EnumDepenedentService to Buffer */
+ for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
+ {
+ lpService = lpServicesArray[dwServiceCount];
+
+ /* Copy the status info */
+ memcpy(&lpServicesPtr->ServiceStatus,
+ &lpService->Status,
+ sizeof(SERVICE_STATUS));
+
+ /* Copy display name */
+ WideCharToMultiByte(CP_ACP,
+ 0,
+ lpService->lpDisplayName,
+ -1,
+ lpStr,
+ wcslen(lpService->lpDisplayName),
+ 0,
+ 0);
+ lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
+ lpStr += strlen(lpStr) + 1;
+
+ /* Copy service name */
+ WideCharToMultiByte(CP_ACP,
+ 0,
+ lpService->lpServiceName,
+ -1,
+ lpStr,
+ wcslen(lpService->lpServiceName),
+ 0,
+ 0);
+ lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
+ lpStr += strlen(lpStr) + 1;
+
+ lpServicesPtr ++;
+ }
+
+ *lpServicesReturned = dwServicesReturned;
+
+Done:
+ if (lpServicesArray)
+ HeapFree(GetProcessHeap(), 0, lpServicesArray);
+
+ RegCloseKey(hServicesKey);
+
+ DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
+
+ return dwError;
+}
+
+
+/* Function 26 */
+DWORD REnumServicesStatusA(
+ handle_t BindingHandle,
+ SC_RPC_HANDLE hSCManager,
+ DWORD dwServiceType,
+ DWORD dwServiceState,
+ LPBYTE lpBuffer,
+ DWORD dwBufSize,
+ LPBOUNDED_DWORD_256K pcbBytesNeeded,
+ LPBOUNDED_DWORD_256K lpServicesReturned,
+ LPBOUNDED_DWORD_256K lpResumeHandle)
+{
+ UNIMPLEMENTED;
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 27 */
+DWORD ROpenSCManagerA(
+ handle_t BindingHandle,
+ LPSTR lpMachineName,
+ LPSTR lpDatabaseName,
+ DWORD dwDesiredAccess,
+ LPSC_RPC_HANDLE lpScHandle)
+{
+ UNICODE_STRING MachineName;
+ UNICODE_STRING DatabaseName;
+ DWORD dwError;
+
+ DPRINT("ROpenSCManagerA() called\n");
+
+ if (lpMachineName)
+ RtlCreateUnicodeStringFromAsciiz(&MachineName,
+ lpMachineName);
if (lpDatabaseName)
RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
DPRINT("ROpenServiceA() called\n");
- RtlCreateUnicodeStringFromAsciiz(&ServiceName,
- lpServiceName);
+ if (lpServiceName)
+ RtlCreateUnicodeStringFromAsciiz(&ServiceName,
+ lpServiceName);
dwError = ROpenServiceW(BindingHandle,
hSCManager,
dwDesiredAccess,
lpServiceHandle);
- RtlFreeUnicodeString(&ServiceName);
+ if (lpServiceName)
+ RtlFreeUnicodeString(&ServiceName);
return dwError;
}
DWORD cbBufSize,
LPBOUNDED_DWORD_8K pcbBytesNeeded)
{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
+ LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
+ DWORD dwError = ERROR_SUCCESS;
+ PSERVICE_HANDLE hSvc;
+ PSERVICE lpService = NULL;
+ HKEY hServiceKey = NULL;
+ LPWSTR lpImagePath = NULL;
+ LPWSTR lpServiceStartName = NULL;
+ DWORD dwRequiredSize;
+ LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
+ CHAR lpEmptyString[]={0,0};
+ LPSTR lpStr;
+
+ DPRINT("RQueryServiceConfigA() called\n");
+
+ if (ScmShutdown)
+ return ERROR_SHUTDOWN_IN_PROGRESS;
+
+ hSvc = (PSERVICE_HANDLE)hService;
+ if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
+ {
+ DPRINT1("Invalid handle tag!\n");
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+ SERVICE_QUERY_CONFIG))
+ {
+ DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ lpService = hSvc->ServiceEntry;
+ if (lpService == NULL)
+ {
+ DPRINT1("lpService == NULL!\n");
+ return ERROR_INVALID_HANDLE;
+ }
+
+ /* FIXME: Lock the service database shared */
+
+ dwError = ScmOpenServiceKey(lpService->lpServiceName,
+ KEY_READ,
+ &hServiceKey);
+ if (dwError != ERROR_SUCCESS)
+ goto Done;
+
+ dwError = ScmReadString(hServiceKey,
+ L"ImagePath",
+ &lpImagePath);
+ if (dwError != ERROR_SUCCESS)
+ goto Done;
+
+ ScmReadString(hServiceKey,
+ L"ObjectName",
+ &lpServiceStartName);
+
+ dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
+
+ if (lpImagePath != NULL)
+ dwRequiredSize += wcslen(lpImagePath) + 1;
+ else
+ dwRequiredSize += 2;
+
+ if (lpService->lpGroup != NULL)
+ dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
+ else
+ dwRequiredSize += 2;
+
+ /* FIXME: Add Dependencies length*/
+ dwRequiredSize += 2;
+
+ if (lpServiceStartName != NULL)
+ dwRequiredSize += wcslen(lpServiceStartName) + 1;
+ else
+ dwRequiredSize += 2;
+
+ if (lpService->lpDisplayName != NULL)
+ dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
+ else
+ dwRequiredSize += 2;
+
+ if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
+ {
+ dwError = ERROR_INSUFFICIENT_BUFFER;
+ }
+ else
+ {
+ lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
+ lpConfig->dwServiceType = lpService->Status.dwServiceType;
+ lpConfig->dwStartType = lpService->dwStartType;
+ lpConfig->dwErrorControl = lpService->dwErrorControl;
+ lpConfig->dwTagId = lpService->dwTag;
+
+ lpStr = (LPSTR)(lpServiceConfig + 1);
+
+ /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
+ Verified in WINXP*/
+
+ if (lpImagePath)
+ {
+ WideCharToMultiByte(CP_ACP,
+ 0,
+ lpImagePath,
+ -1,
+ lpStr,
+ wcslen(lpImagePath),
+ 0,
+ 0);
+ }
+ else
+ {
+ strcpy(lpStr, lpEmptyString);
+ }
+
+ lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpStr += (strlen((LPSTR)lpStr) + 1);
+
+ if (lpService->lpGroup)
+ {
+ WideCharToMultiByte(CP_ACP,
+ 0,
+ lpService->lpGroup->lpGroupName,
+ -1,
+ lpStr,
+ wcslen(lpService->lpGroup->lpGroupName),
+ 0,
+ 0);
+ }
+ else
+ {
+ strcpy(lpStr, lpEmptyString);
+ }
+
+ lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpStr += (strlen(lpStr) + 1);
+
+ /* FIXME: Append Dependencies */
+ strcpy(lpStr, lpEmptyString);
+
+ lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpStr += (strlen(lpStr) + 1);
+
+ if (lpServiceStartName)
+ {
+ WideCharToMultiByte(CP_ACP,
+ 0,
+ lpServiceStartName,
+ -1,
+ lpStr,
+ wcslen(lpServiceStartName),
+ 0,
+ 0);
+ }
+ else
+ {
+ strcpy(lpStr, lpEmptyString);
+ }
+
+ lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpStr += (strlen(lpStr) + 1);
+
+ if (lpService->lpDisplayName)
+ {
+ WideCharToMultiByte(CP_ACP,
+ 0,
+ lpService->lpDisplayName,
+ -1,
+ lpStr,
+ wcslen(lpService->lpDisplayName),
+ 0,
+ 0);
+ }
+ else
+ {
+ strcpy(lpStr, lpEmptyString);
+ }
+
+ lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ }
+
+ if (pcbBytesNeeded != NULL)
+ *pcbBytesNeeded = dwRequiredSize;
+
+Done:;
+ if (lpImagePath != NULL)
+ HeapFree(GetProcessHeap(), 0, lpImagePath);
+
+ if (lpServiceStartName != NULL)
+ HeapFree(GetProcessHeap(), 0, lpServiceStartName);
+
+ if (hServiceKey != NULL)
+ RegCloseKey(hServiceKey);
+
+ /* FIXME: Unlock the service database */
+
+ DPRINT("RQueryServiceConfigA() done\n");
+
+ return dwError;
}
DWORD cbBufSize,
LPBOUNDED_DWORD_8K pcbBytesNeeded)
{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
+ DWORD dwError = ERROR_SUCCESS;
+ PSERVICE_HANDLE hSvc;
+ PSERVICE lpService = NULL;
+ HKEY hServiceKey = NULL;
+ DWORD dwRequiredSize;
+ LPWSTR lpDescriptionW = NULL;
+ LPSTR lpDescription = NULL;
+
+ DPRINT("RQueryServiceConfig2W() called\n");
+
+ if (!lpBuffer)
+ return ERROR_INVALID_ADDRESS;
+
+ if (ScmShutdown)
+ return ERROR_SHUTDOWN_IN_PROGRESS;
+
+ hSvc = (PSERVICE_HANDLE)hService;
+ if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
+ {
+ DPRINT1("Invalid handle tag!\n");
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+ SERVICE_QUERY_CONFIG))
+ {
+ DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ lpService = hSvc->ServiceEntry;
+ if (lpService == NULL)
+ {
+ DPRINT1("lpService == NULL!\n");
+ return ERROR_INVALID_HANDLE;
+ }
+
+ /* FIXME: Lock the service database shared */
+
+ dwError = ScmOpenServiceKey(lpService->lpServiceName,
+ KEY_READ,
+ &hServiceKey);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ if (dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
+ {
+ LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
+ LPSTR lpStr;
+
+ dwError = ScmReadString(hServiceKey,
+ L"Description",
+ &lpDescriptionW);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ dwRequiredSize = sizeof(SERVICE_DESCRIPTIONA) + ((wcslen(lpDescriptionW) + 1));
+
+ if (cbBufSize < dwRequiredSize)
+ {
+ *pcbBytesNeeded = dwRequiredSize;
+ dwError = ERROR_INSUFFICIENT_BUFFER;
+ goto done;
+ }
+
+ lpStr = (LPSTR)(lpServiceDescription + 1);
+
+ WideCharToMultiByte(CP_ACP,
+ 0,
+ lpDescriptionW,
+ -1,
+ lpStr,
+ wcslen(lpDescriptionW),
+ NULL,
+ NULL);
+ lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
+ }
+ else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
+ {
+ UNIMPLEMENTED;
+ dwError = ERROR_CALL_NOT_IMPLEMENTED;
+ goto done;
+ }
+
+done:
+ if (lpDescription != NULL)
+ HeapFree(GetProcessHeap(), 0, lpDescription);
+
+ if (hServiceKey != NULL)
+ RegCloseKey(hServiceKey);
+
+ /* FIXME: Unlock database */
+
+ DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
+
+ return dwError;
}
DPRINT("RQueryServiceConfig2W() called\n");
+ if (!lpBuffer)
+ return ERROR_INVALID_ADDRESS;
+
if (ScmShutdown)
return ERROR_SHUTDOWN_IN_PROGRESS;
dwError = ERROR_INSUFFICIENT_BUFFER;
goto done;
}
- else
- {
- lpStr = (LPWSTR)(lpServiceDescription + 1);
- wcscpy(lpStr, lpDescription);
- lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
- }
+
+ lpStr = (LPWSTR)(lpServiceDescription + 1);
+ wcscpy(lpStr, lpDescription);
+ lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
}
else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
{